--- /dev/null
+QT LICENSE AGREEMENT
+Agreement version 4.4
+
+This Qt License Agreement ("Agreement") is a legal agreement for the licensing
+of Licensed Software (as defined below) between The Qt Company (as defined
+below) and the Licensee who has accepted the terms of this Agreement by signing
+this Agreement or by downloading or using the Licensed Software or in any other
+appropriate means.
+
+Capitalized terms used herein are defined in Section 1.
+
+WHEREAS:
+ (A) Licensee wishes to use the Licensed Software for the purpose of
+ developing and distributing Applications and/or Devices (each as defined
+ below);
+ (B) The Qt Company is willing to grant the Licensee a right to use Licensed
+ Software for such a purpose pursuant to term and conditions of this
+ Agreement; and
+ (C) Parties wish to enable that their respective Affiliates also can sell
+ and purchase licenses to serve Licensee Affiliates' needs to use Licensed
+ Software pursuant to terms of the Agreement. Any such license purchases by
+ Licensee Affiliates from The Qt Company or its Affiliates will create
+ contractual relationship directly between the relevant The Qt Company and
+ the respective ordering Licensee Affiliate "Acceding Agreement").
+ Accordingly, Licensee shall not be a party to any such Acceding Agreement,
+ and no rights or obligations are created to the Licensee thereunder but all
+ rights and obligations under such Acceding Agreement are vested and borne
+ solely by the ordering Licensee Affiliate and the relevant The Qt Company
+ as a contracting parties under such Acceding Agreement.
+
+NOW, THEREFORE, THE PARTIES HEREBY AGREE AS FOLLOWS:
+
+1. DEFINITIONS
+
+"Affiliate" of a Party shall mean an entity
+ (i) which is directly or indirectly controlling such Party;
+ (ii) which is under the same direct or indirect ownership or control as
+ such Party; or
+ (iii) which is directly or indirectly owned or controlled by such Party.
+For these purposes, an entity shall be treated as being controlled by another
+if that other entity has fifty percent (50 %) or more of the votes in such
+entity, is able to direct its affairs and/or to control the composition of its
+board of directors or equivalent body.
+
+"Add-on Products" shall mean The Qt Company's specific add-on software products
+which are not licensed as part of The Qt Company's standard product offering,
+but shall be included into the scope of Licensed Software only if so
+specifically agreed between the Parties.
+
+"Agreement Term" shall mean the validity period of this Agreement, as set forth
+in Section 12.
+
+"Applications" shall mean software products created using the Licensed
+Software, which include the Redistributables, or part thereof.
+
+"Contractor(s)" shall mean third party consultants, distributors and
+contractors performing services to the Licensee under applicable contractual
+arrangement.
+
+"Customer(s)" shall mean Licensee's customers to whom Licensee, directly or
+indirectly, distributes copies of the Redistributables as integrated or
+incorporated into Applications or Devices.
+
+"Data Protection Legislation" shall mean the General Data Protection Regulation
+(EU 2016/679) (GDPR) and any national implementing laws, regulations and
+secondary legislation, as may be amended or updated from time to time, as well
+as any other data protection laws or regulations applicable in relevant
+territory.
+
+"Deployment Platforms" shall mean target operating systems and/or hardware
+specified in the License Certificate, on which the Redistributables can be
+distributed pursuant to the terms and conditions of this Agreement.
+
+"Designated User(s)" shall mean the employee(s) of Licensee or Licensee's
+Affiliates acting within the scope of their employment or Licensee's
+Contractors acting within the scope of their services on behalf of Licensee.
+
+"Development License" shall mean the license needed by the Licensee for each
+Designated User to use the Licensed Software under the license grant described
+in Section 3.1 of this Agreement. Development Licenses are available per
+respective Licensed Software products, each product having its designated scope
+and purpose of use.
+
+"Development License Term" shall mean the agreed validity period of the
+Development License or QA Tools license during which time the relevant Licensed
+Software product can be used pursuant to this Agreement. Agreed Development
+License Term, as ordered and paid for by the Licensee, shall be memorialized in
+the applicable License Certificate.
+
+"Development Platforms" shall mean those host operating systems specified in
+the License Certificate, in which the Licensed Software can be used under the
+Development License.
+
+"Devices" shall mean
+ (1) hardware devices or products that
+ i. are manufactured and/or distributed by the Licensee, its Affiliates,
+ Contractors or Customers, and
+ ii. incorporate, integrate or link to Applications such that
+ substantial functionality of such unit, when used by an End User,
+ is provided by Application(s) or otherwise depends on the Licensed
+ Software, regardless of whether the Application is developed by
+ Licensee or its Contractors; or
+ (2) Applications designed for the hardware devices specified in item (1).
+
+ Devices covered by this Agreement shall be specified in Appendix 2 or in a
+ quote.
+
+"Distribution License(s)" shall mean a royalty-bearing license required for any
+kind of sale, trade, exchange, loan, lease, rental or other distribution by or
+on behalf of Licensee to a third party of Redistributables in connection with
+Devices pursuant to license grant described in Section 3.3 of this Agreement.
+Distribution Licensed are sold separately for each type of Device respectively
+and cannot be used for any type of Devices at Licensee's discretion.
+
+"Distribution License Packs" shall mean set of prepaid Distribution Licenses
+for distribution of Redistributables, as defined in The Qt Company's standard
+price list, quote, Purchase Order confirmation or in an Appendix 2 hereto, as
+the case may be.
+
+"End User" shall mean the final end user of the Application or a Device.
+
+"Evaluation License Term" shall mean a time period specified in the License
+Certificate for the Licensee to use the relevant Licensed Software for
+evaluation purposes according to Section 3.6 herein.
+
+"Intellectual Property Rights" shall mean patents (including utility models),
+design patents, and designs (whether or not capable of registration), chip
+topography rights and other like protection, copyrights, trademarks, service
+marks, trade names, logos or other words or symbols and any other form of
+statutory protection of any kind and applications for any of the foregoing as
+well as any trade secrets.
+
+"License Certificate" shall mean a certificate generated by The Qt Company for
+each Designated User respectively upon them downloading the Licensed Software,
+which will be available under respective Designated User's Qt Account at
+account.qt.io. License Certificates will specify relevant information
+pertaining the Licensed Software purchased by Licensee and Designated User's
+license to the Licensed Software.
+
+"License Fee" shall mean the fee charged to the Licensee for rights granted
+under the terms of this Agreement.
+
+"Licensed Software" shall mean specified product of commercially licensed
+version of Qt Software and/or QA Tools defined in Appendix 1 and/or Appendix 3,
+which Licensee has purchased and which is provided to Licensee under the terms
+of this Agreement. Licensed Software shall include corresponding online or
+electronic documentation, associated media and printed materials, including the
+source code (where applicable), example programs and the documentation.
+Licensed Software does not include Third Party Software (as defined in Section
+4) or Open Source Qt. The Qt Company may, in the course of its development
+activities, at its free and absolute discretion and without any obligation to
+send or publish any notifications to the Licensee or in general, make changes,
+additions or deletions in the components and functionalities of the Licensed
+Software, provided that no such changes, additions or deletions will affect
+the already released version of the Licensed Software, but only upcoming
+version(s).
+
+"Licensee" shall mean the individual or legal entity that is party to this
+Agreement.
+
+"Licensee's Records" shall mean books and records that contain information
+bearing on Licensee's compliance with this Agreement, Licensee's use of Open
+Source Qt and/or the payments due to The Qt Company under this Agreement,
+including, but not limited to user information, assembly logs, sales records
+and distribution records.
+
+"Modified Software" shall have the meaning as set forth in Section 2.3.
+
+"Online Services" shall mean any services or access to systems made available
+by The Qt Company to the Licensee over the Internet relating to the Licensed
+Software or for the purpose of use by the Licensee of the Licensed Software or
+Support. Use of any such Online Services is discretionary for the Licensee and
+some of them may be subject to additional fees.
+
+"Open Source Qt" shall mean Qt Software available under the terms of the GNU
+Lesser General Public License, version 2.1 or later ("LGPL") or the GNU General
+Public License, version 2.0 or later ("GPL"). For clarity, Open Source Qt shall
+not be provided, governed or used under this Agreement.
+
+"Party" or "Parties" shall mean Licensee and/or The Qt Company.
+
+"Permitted Software" shall mean (i) third party open source software products
+that are generally available for public in source code form and free of any
+charge under any of the licenses approved by Open Source Initiative as listed
+on https://opensource.org/licenses, which may include parts of Open Source Qt
+or be developed using Open Source Qt; and (ii) software The Qt Company has made
+available via its Qt Marketplace online distribution channel.
+
+"Pre-Release Code" shall have the meaning as set forth in Section 4.
+
+"Prohibited Combination" shall mean any effort to use, combine, incorporate,
+link or integrate Licensed Software with any software created with or
+incorporating Open Source Qt, or use Licensed Software for creation of any such
+software.
+
+"Purchase Order" shall have the meaning as set forth in Section 10.2.
+
+"QA Tools" shall mean software libraries and tools as defined in Appendix 1
+depending on which product(s) the Licensee has purchased under the Agreement.
+
+"Qt Software" shall mean the software libraries and tools of The Qt Company,
+which The Qt Company makes available under commercial and/or open source
+licenses.
+
+"Redistributables" shall mean the portions of the Licensed Software set forth
+in Appendix 1 that may be distributed pursuant to the terms of this Agreement
+in object code form only, including any relevant documentation. Where relevant,
+any reference to Licensed Software in this Agreement shall include and refer
+also to Redistributables.
+
+"Renewal Term" shall mean an extension of previous Development License Term as
+agreed between the Parties.
+
+"Submitted Modified Software" shall have the meaning as set forth in Section
+2.3.
+
+"Support" shall mean standard developer support that is provided by The Qt
+Company to assist Designated Users in using the Licensed Software in accordance
+with this Agreement and the Support Terms.
+
+"Support Terms" shall mean The Qt Company's standard support terms specified in
+Appendix 9 hereto.
+
+"Taxes" shall have the meaning set forth in Section 10.5.
+
+"The Qt Company" shall mean:
+ (i) in the event Licensee is an individual residing in the United States or
+ a legal entity incorporated in the United States or having its
+ headquarters in the United States, The Qt Company Inc., a Delaware
+ corporation with its office at 3031 Tisch Way, 110 Plaza West,
+ San Jose, CA 95128, USA.; or
+ (ii) in the event the Licensee is an individual residing outside of the
+ United States or a legal entity incorporated outside of the United
+ States or having its registered office outside of the United States,
+ The Qt Company Ltd., a Finnish company with its registered office at
+ Bertel Jungin aukio D3A, 02600 Espoo, Finland.
+
+"Third-Party Software" shall have the meaning set forth in Section 4.
+
+"Updates" shall mean a release or version of the Licensed Software containing
+bug fixes, error corrections and other changes that are generally made
+available to users of the Licensed Software that have contracted for Support.
+Updates are generally depicted as a change to the digits following the decimal
+in the Licensed Software version number. The Qt Company shall make Updates
+available to the Licensee under the Support. Updates shall be considered as
+part of the Licensed Software hereunder.
+
+"Upgrades" shall mean a release or version of the Licensed Software containing
+enhancements and new features and are generally depicted as a change to the
+first digit of the Licensed Software version number. In the event Upgrades are
+provided to the Licensee under this Agreement, they shall be considered as part
+of the Licensed Software hereunder.
+
+2. OWNERSHIP
+
+2.1. Ownership of The Qt Company
+
+The Licensed Software is protected by copyright laws and international
+copyright treaties, as well as other intellectual property laws and treaties.
+The Licensed Software is licensed, not sold.
+
+All of The Qt Company's Intellectual Property Rights are and shall remain the
+exclusive property of The Qt Company or its licensors respectively. No rights
+to The Qt Company's Intellectual Property Rights are assigned or granted to
+Licensee under this Agreement, except when and to the extent expressly
+specified herein.
+
+2.2. Ownership of Licensee
+
+All the Licensee's Intellectual Property Rights are and shall remain the
+exclusive property of the Licensee or its licensors respectively.
+
+All Intellectual Property Rights to the Modified Software, Applications and
+Devices shall remain with the Licensee and no rights thereto shall be granted
+by the Licensee to The Qt Company under this Agreement (except as set forth in
+Section 2.3 below).
+
+2.3. Modified Software
+
+Licensee may create bug-fixes, error corrections, patches or modifications to
+the Licensed Software ("Modified Software"). Such Modified Software may break
+the source or binary compatibility with the Licensed Software (including
+without limitation through changing the application programming interfaces
+("API") or by adding, changing or deleting any variable, method, or class
+signature in the Licensed Software and/or any inter-process protocols,
+services or standards in the Licensed Software libraries). To the extent that
+Licensee's Modified Software so breaks source or binary compatibility with the
+Licensed Software, Licensee acknowledges that The Qt Company's ability to
+provide Support may be prevented or limited and Licensee's ability to make use
+of Updates may be restricted.
+
+Licensee may, at its sole and absolute discretion, choose to submit Modified
+Software to The Qt Company ("Submitted Modified Software") in connection with
+Licensee's Support request, service request or otherwise. In the event
+Licensee does so, then, Licensee hereby grants The Qt Company a sublicensable,
+assignable, irrevocable, perpetual, worldwide, non-exclusive, royalty-free and
+fully paid-up license, under all of Licensee's Intellectual Property Rights, to
+reproduce, adapt, translate, modify, and prepare derivative works of, publicly
+display, publicly perform, sublicense, make available and distribute such
+Submitted Modified Software as The Qt Company sees fit at its free and absolute
+discretion.
+
+3. LICENSES GRANTED
+
+3.1. Development with Licensed Software
+
+Subject to the terms of this Agreement, The Qt Company grants to Licensee a
+worldwide, non-exclusive, non-transferable license, valid for each Development
+License Term, to use, modify and copy the Licensed Software by Designated
+Users on the Development Platforms for the sole purposes of designing,
+developing, demonstrating and testing Application(s) and/or Devices, and to
+provide thereto related support and other related services to Customers. Each
+Application and/or Device can only include, incorporate or integrate
+contributions by such Designated Users who are duly licensed for the applicable
+Development Platform(s) and Deployment Platform(s) (i.e have a valid license
+for the appropriate Licensed Software product).
+
+Licensee may install copies of the Licensed Software on five (5) computers per
+Designated User, provided that only the Designated Users who have a valid
+Development License may use the Licensed Software.
+
+Licensee may at any time designate another Designated User to replace a
+then-current Designated User by notifying The Qt Company in writing, where such
+replacement is due to termination of employment, change of job duties, long
+time absence or other such permanent reason affecting Designated User's need
+for Licensed Software.
+
+Upon expiry of the initially agreed Development License Term, the respective
+Development License Term shall be automatically extended to one or more Renewal
+Term(s), unless and until either Party notifies the other Party in writing, or
+any other method acceptable to The Qt Company (it being specifically
+acknowledged and understood that verbal notification is explicitly deemed
+inadequate in all circumstances), that it does not wish to continue the
+Development License Term, such notification to be provided to the other Party
+no less than thirty (30) days before expiry of the respective Development
+License Term. The Qt Company shall, in good time before the due date for the
+above notification, remind the Licensee on the coming Renewal Term. Unless
+otherwise agreed between the Parties, Renewal Term shall be 12 months.
+
+Any such Renewal Term shall be subject to License Fees agreed between the
+Parties or, if no advance agreement exists, subject to The Qt Company's
+standard list pricing applicable at the commencement date of any such
+Renewal Term.
+
+The Qt Company may either request the Licensee to place a purchase order
+corresponding to a quote by The Qt Company, or use Licensee's stored Credit
+Card information in the Qt Account to automatically charge the Licensee for the
+relevant Renewal Term.
+
+3.2. Distribution of Applications
+
+Subject to the terms of this Agreement, The Qt Company grants to Licensee a
+worldwide, non-exclusive, non-transferable, revocable (for cause pursuant to
+this Agreement), right and license, valid for the Agreement Term, to
+ (i) distribute, by itself or through its Contractors, Redistributables as
+ installed, incorporated or integrated into Applications for execution
+ on the Deployment Platforms, and
+ (ii) grant perpetual and irrevocable sublicenses to Redistributables, as
+ distributed hereunder, for Customers solely to the extent necessary in
+ order for the Customers to use the Applications for their respective
+ intended purposes.
+
+Right to distribute the Redistributables as part of an Application as provided
+herein is not royalty-bearing but is conditional upon the Application having
+been created, updated and maintained under a valid and duly paid Development
+Licenses.
+
+3.3. Distribution of Devices
+
+Subject to the terms of this Agreement, The Qt Company grants to Licensee a
+worldwide, non-exclusive, non-transferable, revocable (for cause pursuant to
+this Agreement), right and license, valid for the Agreement Term, to
+ (i) distribute, by itself or through one or more tiers of Contractors,
+ Redistributables as installed, incorporated or integrated, or intended
+ to be installed, incorporated or integrated into Devices for execution
+ on the Deployment Platforms, and
+ (ii) grant perpetual and irrevocable sublicenses to Redistributables, as
+ distributed hereunder, for Customers solely to the extent necessary in
+ order for the Customers to use the Devices for their respective
+ intended purposes.
+
+Right to distribute the Devices as provided herein is conditional upon
+ (i) the Devices having been created, updated and maintained under a valid
+ and duly paid Development Licenses, and
+ (ii) the Licensee having acquired corresponding Distribution Licenses at
+ the time of distribution of any Devices to Customers.
+
+3.4. Further Requirements
+
+The licenses granted above in this Section 3 by The Qt Company to Licensee are
+conditional and subject to Licensee's compliance with the following terms:
+ (i) Licensee acknowledges that The Qt Company has separate products of
+ Licensed Software for the purpose of Applications and Devices
+ respectively, where development and distribution of Devices is only
+ allowed using the correct designated product. Licensee shall make sure
+ and bear the burden of proof that Licensee is using a correct product
+ of Licensed Software entitling Licensee to development and distribution
+ of Devices;
+ (ii) Licensee shall not remove or alter any copyright, trademark or other
+ proprietary rights notice(s) contained in any portion of the Licensed
+ Software;
+ (iii) Applications must add primary and substantial functionality to the
+ Licensed Software so as not to compete with the Licensed Software;
+ (iv) Applications may not pass on functionality which in any way makes it
+ possible for others to create software with the Licensed Software;
+ provided however that Licensee may use the Licensed Software's
+ scripting and QML ("Qt Quick") functionality solely in order to enable
+ scripting, themes and styles that augment the functionality and
+ appearance of the Application(s) without adding primary and substantial
+ functionality to the Application(s);
+ (v) Licensee shall not use Licensed Software in any manner or for any
+ purpose that infringes, misappropriates or otherwise violates any
+ Intellectual property or right of any third party, or that violates any
+ applicable law;
+ (vi) Licensee shall not use The Qt Company's or any of its suppliers'
+ names, logos, or trademarks to market Applications, except that
+ Licensee may use "Built with Qt" logo to indicate that Application(s)
+ or Device(s) was developed using the Licensed Software;
+ (vii) Licensee shall not distribute, sublicense or disclose source code of
+ Licensed Software to any third party (provided however that Licensee
+ may appoint employee(s) of Contractors and Affiliates as Designated
+ Users to use Licensed Software pursuant to this Agreement). Such right
+ may be available for the Licensee subject to a separate software
+ development kit ("SDK") license agreement to be concluded with The Qt
+ Company;
+ (viii) Licensee shall not grant the Customers a right to (a) make copies of
+ the Redistributables except when and to the extent required to use the
+ Applications and/or Devices for their intended purpose, (b) modify the
+ Redistributables or create derivative works thereof, (c) decompile,
+ disassemble or otherwise reverse engineer Redistributables, or (d)
+ redistribute any copy or portion of the Redistributables to any third
+ party, except as part of the onward sale of the Application or Device
+ on which the Redistributables are installed;
+ (ix) Licensee shall not and shall cause that its Affiliates or Contractors
+ shall not use Licensed Software in any Prohibited Combination, unless
+ Licensee has received an advance written permission from The Qt Company
+ to do so. Absent such written permission, any and all distribution by
+ the Licensee during the Agreement Term of a hardware device or product
+ a) which incorporate or integrate any part of Licensed Software or Open
+ Source Qt; or b) where substantial functionality is provided by
+ software built with Licensed Software or Open Source Qt or otherwise
+ depends on the Licensed Software or Open Source Qt, shall be considered
+ to be Device distribution under this Agreement and shall be dependent
+ on Licensee's compliance thereof (including but not limited to
+ obligation to pay applicable License Fees for such distribution).
+ Notwithstanding what is provided above in this sub-section (ix),
+ Licensee is entitled to use and combine Licensed Software with any
+ Permitted Software;
+ (x) Licensee shall cause all of its Affiliates, Contractors and Customers
+ entitled to make use of the licenses granted under this Agreement, to
+ be contractually bound to comply with the relevant terms of this
+ Agreement and not to use the Licensed Software beyond the terms hereof
+ and for any purposes other than operating within the scope of their
+ services for Licensee. Licensee shall be responsible for any and all
+ actions and omissions of its Affiliates and Contractors relating to the
+ Licensed Software and use thereof (including but not limited to payment
+ of all applicable License Fees);
+ (xi) Except when and to the extent explicitly provided in this Section 3,
+ Licensee shall not transfer, publish, disclose, display or otherwise
+ make available the Licensed Software; and
+ (xii) Licensee shall not attempt or enlist a third party to conduct or
+ attempt to conduct any of the above.
+
+Above terms shall not be applicable if and to the extent they conflict with any
+mandatory provisions of any applicable laws.
+
+Any use of Licensed Software beyond the provisions of this Agreement is
+strictly prohibited and requires an additional license from The Qt Company.
+
+3.5 QA Tools License
+
+Subject to the terms of this Agreement, The Qt Company grants to Licensee a
+worldwide, non-exclusive, non-transferable license, valid for the Development
+License Term, to use the QA Tools for Licensee's internal business purposes in
+the manner provided below and in Appendix 1 hereto.
+
+Licensee may modify the QA Tools except for altering or removing any details of
+ownership, copyright, trademark or other property right connected with the QA
+Tools.
+
+Licensee shall not distribute the QA Tools or any part thereof, modified or
+unmodified, separately or as part of any software package, Application or
+Device.
+
+Upon expiry of the initially agreed Development License Term, the respective
+Development License Term shall be automatically extended to one or more Renewal
+Term(s), unless and until either Party notifies the other Party in writing, or
+any other method acceptable to The Qt Company (it being specifically
+acknowledged and understood that verbal notification is explicitly deemed
+inadequate in all circumstances), that it does not wish to continue the
+Development License Term, such notification to be provided to the other Party
+no less than thirty (30) days before expiry of the respective Development
+License Term. The Qt Company shall, in good time before the due date for the
+above notification, remind the Licensee on the coming Renewal Term. Unless
+otherwise agreed between the Parties, Renewal Term shall be 12 months.
+
+Any such Renewal Term shall be subject to License Fees agreed between the
+Parties or, if no advance agreement exists, subject to The Qt Company's
+standard list pricing applicable at the commencement date of any such
+Renewal Term.
+
+3.6 Evaluation License
+
+Subject to the terms of this Agreement, The Qt Company grants to Licensee a
+worldwide, non-exclusive, non-transferable license, valid for the Evaluation
+License Term to use the Licensed Software solely for the Licensee's internal
+use to evaluate and determine whether the Licensed Software meets Licensee's
+business requirements, specifically excluding any commercial use of the
+Licensed Software or any derived work thereof.
+
+Upon the expiry of the Evaluation License Term, Licensee must either
+discontinue use of the relevant Licensed Software or acquire a commercial
+Development License or QA Tools License specified herein.
+
+4. THIRD-PARTY SOFTWARE
+
+The Licensed Software may provide links or access to third party libraries or
+code (collectively "Third-Party Software") to implement various functions.
+Third-Party Software does not, however, comprise part of the Licensed Software,
+but is provided to Licensee complimentary and use thereof is discretionary for
+the Licensee. Third-Party Software will be listed in the ".../src/3rdparty"
+source tree delivered with the Licensed Software or documented in the Licensed
+Software, as such may be amended from time to time. Licensee acknowledges that
+use or distribution of Third-Party Software is in all respects subject to
+applicable license terms of applicable third-party right holders.
+
+5. PRE-RELEASE CODE
+
+The Licensed Software may contain pre-release code and functionality, or sample
+code marked or otherwise stated with appropriate designation such as
+"Technology Preview", "Alpha", "Beta", "Sample", "Example" etc.
+("Pre-Release Code").
+
+Such Pre-Release Code may be present complimentary for the Licensee, in order
+to provide experimental support or information for new platforms or
+preliminary versions of one or more new functionalities or for other similar
+reasons. The Pre-Release Code may not be at the level of performance and
+compatibility of a final, generally available, product offering. The
+Pre-Release Code may not operate correctly, may contain errors and may be
+substantially modified by The Qt Company prior to the first commercial
+product release, if any. The Qt Company is under no obligation to make
+Pre-Release Code commercially available, or provide any Support or Updates
+relating thereto. The Qt Company assumes no liability whatsoever regarding
+any Pre-Release Code, but any use thereof is exclusively at Licensee's own risk
+and expense.
+
+For clarity, unless Licensed Software specifies different license terms for the
+respective Pre-Release Code, the Licensee is entitled to use such pre-release
+code pursuant to Section 3, just like other Licensed Software.
+
+6. LIMITED WARRANTY AND WARRANTY DISCLAIMER
+
+The Qt Company hereby represents and warrants that (i) it has the power and
+authority to grant the rights and licenses granted to Licensee under this
+Agreement, and (ii) Licensed Software will operate materially in accordance
+with its specifications.
+
+Except as set forth above, the Licensed Software is licensed to Licensee "as
+is" and Licensee's exclusive remedy and The Qt Company's entire liability for
+errors in the Licensed Software shall be limited, at The Qt Company's option,
+to correction of the error, replacement of the Licensed Software or return of
+the applicable fees paid for the defective Licensed Software for the time
+period during which the License is not able to utilize the Licensed Software
+under the terms of this Agreement.
+
+TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, THE QT COMPANY ON BEHALF OF
+ITSELF AND ITS LICENSORS, SUPPLIERS AND AFFILIATES, DISCLAIMS ALL OTHER
+WARRANTIES, EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, ANY IMPLIED
+WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
+NON-INFRINGEMENT WITH REGARD TO THE LICENSED SOFTWARE. THE QT COMPANY DOES NOT
+WARRANT THAT THE LICENSED SOFTWARE WILL SATISFY LICENSEE'S REQUIREMENTS OR THAT
+IT WILL OPERATE WITHOUT DEFECT OR ERROR OR THAT THE OPERATION THEREOF WILL BE
+UNINTERRUPTED.
+
+7. LIMITATION OF LIABILITY
+
+EXCEPT FOR (I) CASES OF GROSS NEGLIGENCE OR INTENTIONAL MISCONDUCT, AND (II)
+BREACH OF CONFIDENTIALITY, AND TO THE EXTENT PERMITTED BY APPLICABLE LAW, IN NO
+EVENT SHALL EITHER PARTY BE LIABLE TO THE OTHER PARTY FOR ANY LOSS OF PROFIT,
+LOSS OF DATA, LOSS OF BUSINESS OR GOODWILL OR ANY OTHER INDIRECT, SPECIAL,
+CONSEQUENTIAL, INCIDENTAL OR PUNITIVE COST, DAMAGES OR EXPENSE OF ANY KIND,
+HOWSOEVER ARISING UNDER OR IN CONNECTION WITH THIS AGREEMENT.
+
+EXCEPT FOR (I) CASES OF GROSS NEGLIGENCE OR INTENTIONAL MISCONDUCT, AND (II)
+BREACH OF CONFIDENTIALITY, AND TO THE EXTENT PERMITTED BY APPLICABLE LAW, IN NO
+EVENT SHALL EITHER PARTY'S TOTAL AGGREGATE LIABILITY UNDER THIS AGREEMENT
+EXCEED THE AGGREGATE LICENSE FEES PAID OR PAYABLE TO THE QT COMPANY BY LICENSEE
+DURING THE DEVELOPMENT LICENSE TERM DURING WHICH THE EVENT RESULTING IN SUCH
+LIABILITY OCCURRED.
+
+THE PROVISIONS OF THIS SECTION 7 ALLOCATE THE RISKS UNDER THIS AGREEMENT
+BETWEEN THE QT COMPANY AND LICENSEE AND THE PARTIES HAVE RELIED UPON THE
+LIMITATIONS SET FORTH HEREIN IN DETERMINING WHETHER TO ENTER INTO THIS
+AGREEMENT.
+
+NOTWITHSTANDING ANYTHING TO THE CONTRARY IN THIS AGREEMENT, LICENSEE SHALL
+ALWAYS BE LIABLE TO PAY THE APPLICABLE LICENSE FEES CORRESPONDING TO ITS
+ACTUAL USE OF LICENSED SOFTWARE.
+
+8. SUPPORT, UPDATES AND ONLINE SERVICES
+
+Upon due payment of the agreed License Fees the Licensee will be eligible to
+receive Support and Updates and to use the Online Services during the agreed
+Development License Term or other agreed fixed time period. Support is
+provided according to agreed support level and subject to applicable
+requirements and restrictions, as specified in the Support Terms.
+
+Unless otherwise decided by The Qt Company at its free and absolute discretion,
+Upgrades will not be included in the Support but may be available subject to
+additional fees.
+
+From time to time The Qt Company may change the Support Terms, provided that
+during the respective ongoing Support period the level of Support may not be
+reduced without the consent of the Licensee.
+
+Unless otherwise agreed, The Qt Company shall not be responsible for providing
+any service or support to Customers.
+
+9. CONFIDENTIALITY
+
+Each Party acknowledges that during the Agreement Term each Party may receive
+information about the other Party's business, business methods, business plans,
+customers, business relations, technology, and other information, including the
+terms of this Agreement, that is confidential and of great value to the other
+Party, and the value of which would be significantly reduced if disclosed to
+third parties ("Confidential Information"). Accordingly, when a Party (the
+"Receiving Party") receives Confidential Information from the other Party (the
+"Disclosing Party"), the Receiving Party shall only disclose such information
+to employees and Contractors on a need to know basis, and shall cause its
+employees and employees of its Affiliates to: (i) maintain any and all
+Confidential Information in confidence; (ii) not disclose the Confidential
+Information to a third party without the Disclosing Party's prior written
+approval; and (iii) not, directly or indirectly, use the Confidential
+Information for any purpose other than for exercising its rights and
+fulfilling its responsibilities pursuant to this Agreement. Each Party shall
+take reasonable measures to protect the Confidential Information of the other
+Party, which measures shall not be less than the measures taken by such Party
+to protect its own confidential and proprietary information.
+
+Obligation of confidentiality shall not apply to information that (i) is or
+becomes generally known to the public through no act or omission of the
+Receiving Party; (ii) was in the Receiving Party's lawful possession prior to
+the disclosure hereunder and was not subject to limitations on disclosure or
+use; (iii) is developed independently by employees or Contractors of the
+Receiving Party or other persons working for the Receiving Party who have not
+had access to the Confidential Information of the Disclosing Party, as proven
+by the written records of the Receiving Party; (iv) is lawfully disclosed to
+the Receiving Party without restrictions, by a third party not under an
+obligation of confidentiality; or (v) the Receiving Party is legally compelled
+to disclose, in which case the Receiving Party shall notify the Disclosing
+Party of such compelled disclosure and assert the privileged and confidential
+nature of the information and cooperate fully with the Disclosing Party to
+limit the scope of disclosure and the dissemination of disclosed Confidential
+Information to the minimum extent necessary.
+
+The obligations under this Section 9 shall continue to remain in force for a
+period of five (5) years after the last disclosure, and, with respect to trade
+secrets, for so long as such trade secrets are protected under applicable trade
+secret laws.
+
+10. FEES, DELIVERY AND PAYMENT
+
+10.1. License Fees
+
+License Fees are described in The Qt Company's standard price list, quote or
+Purchase Order confirmation or in an Appendix 2 hereto, as the case may be.
+
+Unless otherwise expressly provided in this Agreement, the License Fees shall
+not be refunded or claimed as a credit in any event or for any reason
+whatsoever.
+
+10.2. Ordering Licenses
+
+Licensee may purchase Development Licenses, Distribution Licenses and QA Tools
+Licenses pursuant to agreed pricing terms or, if no specific pricing terms have
+been agreed upon, at The Qt Company's standard pricing terms applicable at the
+time of purchase.
+
+Unless expressly otherwise agreed, any price or other term quoted to the
+Licensee or specified herein shall only be valid for the thirty (30) days from
+the effective date of this Agreement, Appendix 2 or the date of the quote, as
+applicable.
+
+Licensee shall submit all purchase orders for Development Licenses and
+Distribution Licenses to The Qt Company by email or any other method acceptable
+to The Qt Company (each such order is referred to herein as a "Purchase Order")
+for confirmation, whereupon the Purchase Order shall become binding between the
+Parties.
+
+Licensee acknowledges and agrees that all Purchase Orders for Licensed Software
+the Licensee makes during the Agreement Term shall be governed exclusively
+under the terms of this Agreement.
+
+10.3. Distribution License Packs
+
+Unless otherwise agreed, Distribution Licenses shall be purchased by way of
+Distribution License Packs.
+
+Upon due payment of the ordered Distribution License Pack(s), the Licensee will
+have an account of Distribution Licenses available for distributing the
+Redistributables in accordance with this Agreement.
+
+Each time Licensee distributes a copy of Redistributables, then one
+Distribution License is used, and Licensee's account of available Distribution
+Licenses is decreased accordingly.
+
+Licensee may distribute copies of the Redistributables so long as Licensee has
+Distribution Licenses remaining on its account.
+
+10.4. Payment Terms
+
+License Fees and any other charges under this Agreement shall be paid by
+Licensee no later than thirty (30) days from the date of the applicable invoice
+from The Qt Company.
+
+The Qt Company will submit an invoice to Licensee after the date of this
+Agreement and/or after The Qt Company receives a Purchase Order from Licensee.
+
+A late payment charge of the lower of (a) one percent per month; or (b) the
+interest rate stipulated by applicable law, shall be charged on any unpaid
+balances that remain past due and which have not been disputed by the Licensee
+in good faith.
+
+10.5. Taxes
+
+All License Fees and other charges payable hereunder are gross amounts but
+exclusive of any value added tax, use tax, sales tax, withholding tax and other
+taxes, duties or tariffs ("Taxes") levied directly for the sale, delivery or
+use of Licensed Software hereunder pursuant to any applicable law. Such
+applicable Taxes shall be paid by Licensee to The Qt Company, or, where
+applicable, in lieu of payment of such Taxes to The Qt Company, Licensee shall
+provide an exemption certificate to The Qt Company and any applicable
+authority.
+
+11. RECORD-KEEPING AND REPORTING OBLIGATIONS; AUDIT RIGHTS
+
+11.1. Licensee's Record-keeping
+
+Licensee shall at all times during the Agreement Term and for a period of two
+(2) years thereafter maintain Licensee's Records in an accurate and up-to-date
+form. Licensee's Records shall be adequate to reasonably enable The Qt Company
+to determine Licensee's compliance with the provisions of this Agreement. The
+records shall conform to general good accounting practices.
+
+Licensee shall, within thirty (30) days from receiving The Qt Company's request
+to that effect, deliver to The Qt Company a report based on Licensee's Records,
+such report to contain information, in sufficient detail, on (i) number and
+identity of users working with Licensed Software or Open Source Qt, (ii) copies
+of Redistributables distributed by Licensee during the most recent calendar
+quarter and/or any other term specified by The Qt Company, , and (iii) any
+other information pertaining to Licensee's compliance with the terms of this
+Agreement (like e.g. information on products and/or projects relating to use of
+Distribution Licenses), as The Qt Company may reasonably require from time to
+time.
+
+11.2. The Qt Company's Audit Rights
+
+The Qt Company or an independent auditor acting on behalf of The Qt Company's,
+may, upon at least thirty (30) days' prior written notice and at its expense,
+audit Licensee with respect to the Licensee's use of the Licensed Software, but
+not more frequently than once during each 6-month period. Such audit may be
+conducted by mail, electronic means or through an in-person visit to Licensee's
+place of business. Any possible in-person audit shall be conducted during
+regular business hours at Licensee's facilities and shall not unreasonably
+interfere with Licensee's business activities and shall be limited in scope to
+verify Licensee's compliance with the terms of this Agreement. The Qt Company
+or the independent auditor acting on behalf of The Qt Company shall be entitled
+to inspect Licensee's Records and conduct necessary interviews of Licensee's
+relevant employees and Contractors. All such Licensee's Records and use thereof
+shall be subject to an obligation of confidentiality under this Agreement.
+
+If an audit reveals that Licensee is using the Licensed Software beyond scope
+of the licenses Licensee has paid for, Licensee shall pay to The Qt Company any
+amounts owed for such unauthorized use within 30 days from receipt of the
+corresponding invoice from The Qt Company.
+
+In addition, in the event the audit reveals a material violation of the terms
+of this Agreement (without limitation, either (i) underpayment of more than 10
+% of License Fees or 10,000 euros (whichever is more) or (ii) distribution of
+products, which include or result from Prohibited Combination, shall be deemed
+a material violation for purposes of this section), then the Licensee shall
+pay The Qt Company's reasonable cost of conducting such audit.
+
+12. TERM AND TERMINATION
+
+12.1. Agreement Term
+
+This Agreement shall enter into force upon due acceptance by both Parties and
+remain in force until terminated pursuant to the terms of this Section 12
+("Agreement Term").
+
+12.2. Termination for breach and suspension of rights
+Either Party shall have the right to terminate this Agreement upon thirty (30)
+days prior written notice if the other Party commits a material breach of any
+obligation of this Agreement and fails to remedy such breach within such notice
+period.
+
+Instead of termination, The Qt Company shall have the right to suspend or
+withhold grants of all rights to the Licensed Software hereunder, including but
+not limited to the Development Licenses, Distribution License, and Support,
+should Licensee fail to make payment in timely fashion or otherwise violates or
+is reasonably suspected to violate its obligations or terms of this Agreement,
+and where such violation or breach is not cured within ten (10) business days
+following The Qt Company's written notice thereof.
+
+12.3. Termination for insolvency
+
+Either Party shall have the right to terminate this Agreement immediately upon
+written notice in the event that the other Party becomes insolvent, files for
+any form of bankruptcy, makes any assignment for the benefit of creditors, has
+a receiver, administrative receiver or officer appointed over the whole or a
+substantial part of its assets, ceases to conduct business, or an act
+equivalent to any of the above occurs under the laws of the jurisdiction of the
+other Party.
+
+12.4. Parties' Rights and Duties upon Termination
+
+Upon expiry or termination of the Agreement, Licensee shall cease and shall
+cause all Designated Users (including those of its Affiliates' and
+Contractors') to cease using the Licensed Software under this Agreement. For
+clarity, a Development License of a Designated User or a QA Tools License, and
+all rights relating thereto, shall always terminate at the expiry of the
+respective Development License Term, even if the Agreement continues to remain
+in force.
+
+Upon such termination the Licensee shall destroy or return to The Qt Company
+all copies of the Licensed Software and all related materials and will certify
+the same by Licensee's duly authorized officer to The Qt Company upon its
+request, provided however that Licensee may retain and exploit such copies of
+the Licensed Software as it may reasonably require in providing continued
+support to Customers.
+
+Except when this Agreement is terminated by The Qt Company due to Licensee's
+material breach as set forth in Section 12.2, the Licensee may continue
+distribution of Applications and Devices under the terms of this Agreement
+despite the termination of this Agreement. In such event the terms hereof will
+continue to be applicable and govern any such distribution of Applications and
+Devices beyond the expiry or termination of this Agreement. In case of
+termination by The Qt Company due to Licensee's material breach, Licensee must
+cease any distribution of Applications and Devices at the date of termination
+of this Agreement.
+
+Expiry or termination of this Agreement for any reason whatsoever shall not
+relieve Licensee of its obligation to pay any License Fees accrued or payable
+to The Qt Company prior to the effective date of termination, and Licensee pay
+to The Qt Company all such fees within 30 days from the effective date of
+termination of this Agreement.
+
+Termination of this Agreement shall not affect any rights of Customers to
+continue use of Applications and Devices (and therein incorporated
+Redistributables).
+
+12.5. Extension of Rights under Special Circumstances
+
+In the event of The Qt Company choosing not to renew the Development License(s)
+or QA Tools Licenses, as set forth in Section 3.1 and 3.5 respectively, and
+where such decision of non-renewal is not due to any ongoing breach or alleged
+breach (as reasonably determined by The Qt Company) by Licensee of the terms of
+this Agreement or any applicable license terms of Open Source Qt, then all
+valid and affected Development Licenses and QA Tools licenses possessed by the
+Licensee at such date shall be extended to be valid in perpetuity under the
+terms of this Agreement and Licensee is entitled to purchase additional
+licenses as set forth in Section 10.2.
+
+In the event The Qt Company is declared bankrupt under a final, non-cancellable
+decision by relevant court of law, and this Agreement is not, at the date of
+expiry of the Development License(s) or QA Tools Licenses, assigned to party,
+who has assumed The Qt Company's position as a legitimate licensor of Licensed
+Software under this Agreement, then all valid Development Licenses and QA Tools
+Licenses possessed by the Licensee at such date of expiry, and which the
+Licensee has not notified for expiry, shall be extended to be valid in
+perpetuity under the terms of this Agreement.
+
+For clarity, in case of an extension under this Section 12.5, any such
+extension shall not apply to The Qt Company's Support obligations, but Support
+shall be provided only up until the end of the respective fixed Development
+License Term regardless of the extension of relevant Development License or QA
+Tools License, unless otherwise agreed between the Parties.
+
+13. GOVERNING LAW AND LEGAL VENUE
+
+In the event this Agreement is in the name of The Qt Company Inc., a Delaware
+Corporation, then:
+ (i) this Agreement shall be construed and interpreted in accordance with
+ the laws of the State of California, USA, excluding its choice of law
+ provisions;
+ (ii) the United Nations Convention on Contracts for the International Sale
+ of Goods will not apply to this Agreement; and
+ (iii) any dispute, claim or controversy arising out of or relating to this
+ Agreement or the breach, termination, enforcement, interpretation or
+ validity thereof, including the determination of the scope or
+ applicability of this Agreement to arbitrate, shall be determined by
+ arbitration in San Francisco, USA, before one arbitrator. The
+ arbitration shall be administered by JAMS pursuant to JAMS' Streamlined
+ Arbitration Rules and Procedures. Judgment on the Award may be entered
+ in any court having jurisdiction. This Section shall not preclude
+ parties from seeking provisional remedies in aid of arbitration from a
+ court of appropriate jurisdiction.
+
+In the event this Agreement is in the name of The Qt Company Ltd., a Finnish
+Company, then:
+ (i) this Agreement shall be construed and interpreted in accordance with
+ the laws of Finland, excluding its choice of law provisions;
+ (ii) the United Nations Convention on Contracts for the International Sale
+ of Goods will not apply to this Agreement; and
+ (iii) any disputes, controversy or claim arising out of or relating to this
+ Agreement, or the breach, termination or validity thereof shall be
+ finally settled by arbitration in accordance with the Arbitration Rules
+ of International Chamber of Commerce. The arbitration tribunal shall
+ consist of one (1), or if either Party so requires, of three (3),
+ arbitrators. The award shall be final and binding and enforceable in
+ any court of competent jurisdiction. The arbitration shall be held in
+ Helsinki, Finland and the process shall be conducted in the English
+ language. This Section shall not preclude parties from seeking
+ provisional remedies in aid of arbitration from a court of appropriate
+ jurisdiction.
+
+14. GENERAL PROVISIONS
+
+14.1. No Assignment
+
+Except in the case of a merger or sale of substantially all of its corporate
+assets, Licensee shall not be entitled to assign or transfer all or any of its
+rights, benefits and obligations under this Agreement without the prior written
+consent of The Qt Company, which shall not be unreasonably withheld or delayed.
+The Qt Company shall be entitled to freely assign or transfer any of its
+rights, benefits or obligations under this Agreement.
+
+14.2. No Third-Party Representations
+
+Licensee shall make no representations or warranties concerning the Licensed
+Software on behalf of The Qt Company. Any representation or warranty Licensee
+makes or purports to make on The Qt Company's behalf shall be void as to
+The Qt Company.
+
+14.3. Surviving Sections
+
+Any terms and conditions that by their nature or otherwise reasonably should
+survive termination of this Agreement shall so be deemed to survive. Such
+sections include especially the following: 1, 2, 6, 7, 9, 11, 12.4, 13 and 14.
+
+14.4. Entire Agreement
+
+This Agreement, the Appendices hereto, the License Certificate and any
+applicable quote and Purchase Order accepted by The Qt Company constitute the
+complete agreement between the Parties and supersedes all prior or
+contemporaneous discussions, representations, and proposals, written or oral,
+with respect to the subject matters discussed herein.
+
+In the event of any conflict or inconsistency between this Agreement and any
+Purchase Order, the terms of this Agreement will prevail over the terms of the
+Purchase Order with respect to such conflict or inconsistency.
+
+Parties specifically acknowledge and agree that this Agreement prevails over
+any click-to-accept or similar agreements the Designated Users may need to
+accept online upon download of the Licensed Software, as may be required by
+The Qt Company's applicable processes relating to Licensed Software.
+
+14.5. Modifications
+
+No modification of this Agreement shall be effective unless contained in a
+writing executed by an authorized representative of each Party. No term or
+condition contained in Licensee's Purchase Order ("Deviating Terms") shall
+apply unless The Qt Company has expressly agreed such Deviating Terms in
+writing. Unless and to the extent expressly agreed by The Qt Company, any such
+Deviating Terms shall be deemed void and with no legal effect. For clarity,
+delivery of the Licensed Software following the receipt of the Purchase Order
+including Deviating Terms shall not constitute acceptance of such Deviating
+Terms.
+
+14.6. Force Majeure
+
+Except for the payment obligations hereunder, neither Party shall be liable to
+the other for any delay or non-performance of its obligations hereunder in the
+event and to the extent that such delay or non-performance is due to an event
+of act of God, terrorist attack or other similar unforeseeable catastrophic
+event that prevents either Party for fulfilling its obligations under this
+Agreement and which such Party cannot avoid or circumvent ("Force Majeure
+Event"). If the Force Majeure Event results in a delay or non-performance of a
+Party for a period of three (3) months or longer, then either Party shall have
+the right to terminate this Agreement with immediate effect without any
+liability (except for the obligations of payment arising prior to the event of
+Force Majeure) towards the other Party.
+
+14.7. Notices
+
+Any notice given by one Party to the other shall be deemed properly given and
+deemed received if specifically acknowledged by the receiving Party in writing
+or when successfully delivered to the recipient by hand, fax, or special
+courier during normal business hours on a business day to the addresses
+specified for each Party on the signature page. Each communication and document
+made or delivered by one Party to the other Party pursuant to this Agreement
+shall be in the English language.
+
+14.8. Export Control
+
+Licensee acknowledges that the Redistributables, as incorporated in
+Applications or Devices, may be subject to export control restrictions under
+the applicable laws of respective countries. Licensee shall fully comply with
+all applicable export license restrictions and requirements as well as with all
+laws and regulations relating to the Redistributables and exercise of licenses
+hereunder and shall procure all necessary governmental authorizations,
+including without limitation, all necessary licenses, approvals, permissions or
+consents, where necessary for the re-exportation of the Redistributables,
+Applications and/or Devices.
+
+14.9. No Implied License
+
+There are no implied licenses or other implied rights granted under this
+Agreement, and all rights, save for those expressly granted hereunder, shall
+remain with The Qt Company and its licensors. In addition, no licenses or
+immunities are granted to the combination of the Licensed Software with any
+other software or hardware not delivered by The Qt Company under this
+Agreement.
+
+14.10. Attorney Fees
+
+The prevailing Party in any action to enforce this Agreement shall be entitled
+to recover its attorney's fees and costs in connection with such action, as to
+be ordered by the relevant dispute resolution body.
+
+14.11. Privacy
+
+Licensee acknowledges and agrees that for the purpose of this Agreement,
+The Qt Company may collect, use, transfer and disclose personal data pertaining
+to Designated Users as well as any other employees and directors of the
+Licensee and its Contractors relevant for carrying out the intent of this
+Agreement. Such personal data will be primarily collected from the relevant
+individuals but may be collected also from Licensee (e.g. in the course of
+Licensee's reporting obligations). The Parties acknowledge that as
+The Qt Company determines the purpose and means for such collection and
+processing of the applicable personal data, The Qt Company shall be regarded as
+the Data Controller under the applicable Data Protection Legislation.
+The Qt Company shall process any such personal data in accordance with its
+privacy and security policies and practices, which will comply with all
+applicable requirements of the Data Protection Legislation.
+
+14.12. Severability
+
+If any provision of this Agreement shall be adjudged by any court of competent
+jurisdiction to be unenforceable or invalid, that provision shall be limited or
+eliminated to the minimum extent necessary so that this Agreement shall
+otherwise remain in full force and effect and enforceable.
+
+14.13. Marketing Rights
+
+Parties have agreed upon Marketing Rights pursuant to Appendix 7, if any.
+
+
+
+
+APPENDICES
+The Agreement includes following Appendices 1-10, as applicable.
+- Appendix 1: Licensed Software details
+- Appendix 2: Pricing
+- Appendix 3: Add-on Software details (optional)
+- Appendix 4: Non-commercial and educational Licenses (optional)
+- Appendix 5: Small business and startup Licenses (optional)
+- Appendix 6: License Reporting (optional)
+- Appendix 7: Marketing Rights (optional)
+- Appendix 8: Intentionally left blank (optional)
+- Appendix 9: Support Terms
+- Appendix 10: Conversion from legacy Licenses to Subscription (optional)
+
+
+APPENDIX 1: LICENSED SOFTWARE
+
+The modules and/or tools that are included in the latest publicly available
+version of the respective product at the effective date of this Agreement- Qt
+for Application Development Professional (ADP), Qt for Application Development
+Enterprise (ADE), Qt for Device Creation Professional (DCP), Qt for Device
+Creation Enterprise (DCE), - are marked with "X" in the below table. The
+modules and tools are specific to each product version respectively and may
+vary from version to version. Modules and tools included in the latest publicly
+available version of the respective product at any given time are listed in
+Appendix 1 of the latest version of this Agreement available at
+www.qt.io/terms-conditions/. If a new version of Licensed Software does not
+include a module or tool present in an older version which Licensee is entitled
+to use under a valid license from The Qt Company, then Licensee will continue
+to have such right during the Term of this Agreement. In the event a new
+version of the Licensed Software adds modules or tools to any previous
+version(s), Licensee's rights will extend to cover also such additional modules
+and tools.
+
+Parts of the product that are permitted for distribution in object-code form
+only ("Redistributables") are marked with "R" in the below table.
+
++----------------------------------------------------------+
+| Modules / Tools | ADP | ADE | DCP | DCE |
++----------------------------------------------------------+
+| Active Qt | X,R | X,R | X,R | X,R |
++----------------------------------------------------------+
+| Qt 3D | X,R | X,R | X,R | X,R |
++----------------------------------------------------------+
+| Qt 5 Core Compatibility APIs | X,R | X,R | X,R | X,R |
++----------------------------------------------------------+
+| Qt Android Extras | X,R | X,R | X,R | X,R |
++----------------------------------------------------------+
+| Qt Bluetooth | X,R | X,R | X,R | X,R |
++----------------------------------------------------------+
+| Qt Canvas 3D | X,R | X,R | X,R | X,R |
++----------------------------------------------------------+
+| Qt Charts | X,R | X,R | X,R | X,R |
++----------------------------------------------------------+
+| Qt Concurrent | X,R | X,R | X,R | X,R |
++----------------------------------------------------------+
+| Qt Core | X,R | X,R | X,R | X,R |
++----------------------------------------------------------+
+| Qt Data Visualization | X,R | X,R | X,R | X,R |
++----------------------------------------------------------+
+| Qt D-Bus | X,R | X,R | X,R | X,R |
++----------------------------------------------------------+
+| Qt for Python | X,R | X,R | X,R | X,R |
++----------------------------------------------------------+
+| Qt for WebAssembly | X,R | X,R | X,R | X,R |
++----------------------------------------------------------+
+| Qt Gamepad | X,R | X,R | X,R | X,R |
++----------------------------------------------------------+
+| Qt Graphical Effects | X,R | X,R | X,R | X,R |
++----------------------------------------------------------+
+| Qt GUI | X,R | X,R | X,R | X,R |
++----------------------------------------------------------+
+| Qt Help | X,R | X,R | X,R | X,R |
++----------------------------------------------------------+
+| Qt Image Formats | X,R | X,R | X,R | X,R |
++----------------------------------------------------------+
+| Qt Location | X,R | X,R | X,R | X,R |
++----------------------------------------------------------+
+| Qt Lottie Animation | X,R | X,R | X,R | X,R |
++----------------------------------------------------------+
+| Qt Mac Extras | X,R | X,R | X,R | X,R |
++----------------------------------------------------------+
+| Qt Multimedia | X,R | X,R | X,R | X,R |
++----------------------------------------------------------+
+| Qt Multimedia Widgets | X,R | X,R | X,R | X,R |
++----------------------------------------------------------+
+| Qt Network | X,R | X,R | X,R | X,R |
++----------------------------------------------------------+
+| Qt Network Authorization | X,R | X,R | X,R | X,R |
++----------------------------------------------------------+
+| Qt NFC | X,R | X,R | X,R | X,R |
++----------------------------------------------------------+
+| Qt OpenGL | X,R | X,R | X,R | X,R |
++----------------------------------------------------------+
+| Qt PDF | X,R | X,R | X,R | X,R |
++----------------------------------------------------------+
+| Qt Platform Headers | X,R | X,R | X,R | X,R |
++----------------------------------------------------------+
+| Qt Positioning | X,R | X,R | X,R | X,R |
++----------------------------------------------------------+
+| Qt Print Support | X,R | X,R | X,R | X,R |
++----------------------------------------------------------+
+| Qt Purchasing | X,R | X,R | X,R | X,R |
++----------------------------------------------------------+
+| Qt QML | X,R | X,R | X,R | X,R |
++----------------------------------------------------------+
+| Qt Quick | X,R | X,R | X,R | X,R |
++----------------------------------------------------------+
+| Qt Quick 3D | X,R | X,R | X,R | X,R |
++----------------------------------------------------------+
+| Qt Quick Controls 1 | X,R | X,R | X,R | X,R |
++----------------------------------------------------------+
+| Qt Quick Controls | X,R | X,R | X,R | X,R |
++----------------------------------------------------------+
+| Qt Quick Dialogs | X,R | X,R | X,R | X,R |
++----------------------------------------------------------+
+| Qt Quick Extras | X,R | X,R | X,R | X,R |
++----------------------------------------------------------+
+| Qt Quick Layouts | X,R | X,R | X,R | X,R |
++----------------------------------------------------------+
+| Qt Quick Test | X,R | X,R | X,R | X,R |
++----------------------------------------------------------+
+| Qt Quick Timeline | X,R | X,R | X,R | X,R |
++----------------------------------------------------------+
+| Qt Quick WebGL | X,R | X,R | X,R | X,R |
++----------------------------------------------------------+
+| Qt Quick Widgets | X,R | X,R | X,R | X,R |
++----------------------------------------------------------+
+| Qt Remote Objects | X,R | X,R | X,R | X,R |
++----------------------------------------------------------+
+| Qt Script | X,R | X,R | X,R | X,R |
++----------------------------------------------------------+
+| Qt Script Tools | X,R | X,R | X,R | X,R |
++----------------------------------------------------------+
+| Qt SCXML | X,R | X,R | X,R | X,R |
++----------------------------------------------------------+
+| Qt Sensors | X,R | X,R | X,R | X,R |
++----------------------------------------------------------+
+| Qt Serial Bus | X,R | X,R | X,R | X,R |
++----------------------------------------------------------+
+| Qt Serial Port | X,R | X,R | X,R | X,R |
++----------------------------------------------------------+
+| Qt Shader Tools | X,R | X,R | X,R | X,R |
++----------------------------------------------------------+
+| Qt Speech | X,R | X,R | X,R | X,R |
++----------------------------------------------------------+
+| Qt State Machine | X,R | X,R | X,R | X,R |
++----------------------------------------------------------+
+| Qt SQL | X,R | X,R | X,R | X,R |
++----------------------------------------------------------+
+| Qt SVG | X,R | X,R | X,R | X,R |
++----------------------------------------------------------+
+| Qt Test | X,R | X,R | X,R | X,R |
++----------------------------------------------------------+
+| Qt UI Tools | X,R | X,R | X,R | X,R |
++----------------------------------------------------------+
+| Qt Virtual Keyboard | X,R | X,R | X,R | X,R |
++----------------------------------------------------------+
+| Qt Wayland Compositor | X,R | X,R | X,R | X,R |
++----------------------------------------------------------+
+| Qt WebChannel | X,R | X,R | X,R | X,R |
++----------------------------------------------------------+
+| Qt WebEngine | X,R | X,R | X,R | X,R |
++----------------------------------------------------------+
+| Qt WebSockets | X,R | X,R | X,R | X,R |
++----------------------------------------------------------+
+| Qt WebView | X,R | X,R | X,R | X,R |
++----------------------------------------------------------+
+| Qt Widgets | X,R | X,R | X,R | X,R |
++----------------------------------------------------------+
+| Qt Windows Extras | X,R | X,R | X,R | X,R |
++----------------------------------------------------------+
+| Qt X11 Extras | X,R | X,R | X,R | X,R |
++----------------------------------------------------------+
+| Qt XML | X,R | X,R | X,R | X,R |
++----------------------------------------------------------+
+| Qt XML Patterns | X,R | X,R | X,R | X,R |
++----------------------------------------------------------+
+| Qt Designer (Qt Widget Designer) | X,R | X,R | X,R | X,R |
++----------------------------------------------------------+
+| Qt Linguist | X,R | X,R | X,R | X,R |
++----------------------------------------------------------+
+| Qt Assistant | X,R | X,R | X,R | X,R |
++----------------------------------------------------------+
+| lupdate | X,R | X,R | X,R | X,R |
++----------------------------------------------------------+
+| lrelease | X,R | X,R | X,R | X,R |
++----------------------------------------------------------+
+| lconvert | X,R | X,R | X,R | X,R |
++----------------------------------------------------------+
+| Qt MQTT | | X,R | X,R | X,R |
++----------------------------------------------------------+
+| Qt KNX | | X,R | X,R | X,R |
++----------------------------------------------------------+
+| Qt OPC UA | | X,R | X,R | X,R |
++----------------------------------------------------------+
+| Qt CoAP | | X,R | X,R | X,R |
++----------------------------------------------------------+
+| Boot 2 Qt stacks | | | X,R | X,R |
++----------------------------------------------------------+
+| Qt OTA | | | X,R | X,R |
++----------------------------------------------------------+
+| Device Utilities | | | X,R | X,R |
++----------------------------------------------------------+
+| Qt Debugging Bridge (QBD) Daemon | | | X,R | X,R |
++----------------------------------------------------------+
+| Qt Quick Ultralite Controls | | | X,R | X,R |
++----------------------------------------------------------+
+| Qt Quick Ultralite | | | X,R | X,R |
++----------------------------------------------------------+
+| Qt Safe Renderer (QSR) | | | | X,R |
++----------------------------------------------------------+
+| Qt Application Manager | | | | X,R |
++----------------------------------------------------------+
+| Qt Interface Framework | | | | X,R |
++----------------------------------------------------------+
+| Neptune Reference UI | | | | X,R |
++----------------------------------------------------------+
+| Qt for Android Automotive (QAA) | | | | X,R |
++----------------------------------------------------------+
+| Qt Creator | X | X | X | X |
++----------------------------------------------------------+
+| Qt Design Studio Professional | X | X | X | X |
++----------------------------------------------------------+
+| androiddeployqt | X | X | X | X |
++----------------------------------------------------------+
+| androidtestrunner | X | X | X | X |
++----------------------------------------------------------+
+| canbusutil | X | X | X | X |
++----------------------------------------------------------+
+| dumpcpp | X | X | X | X |
++----------------------------------------------------------+
+| dumpdoc | X | X | X | X |
++----------------------------------------------------------+
+| fixqt4headers.pl | X | X | X | X |
++----------------------------------------------------------+
+| idc | X | X | X | X |
++----------------------------------------------------------+
+| moc | X | X | X | X |
++----------------------------------------------------------+
+| pixeltool | X | X | X | X |
++----------------------------------------------------------+
+| qdbus | X | X | X | X |
++----------------------------------------------------------+
+| qdbuscpp2xml | X | X | X | X |
++----------------------------------------------------------+
+| qdbusviwer | X | X | X | X |
++----------------------------------------------------------+
+| qdbusxml2cpp | X | X | X | X |
++----------------------------------------------------------+
+| qdistancefieldgenerator | X | X | X | X |
++----------------------------------------------------------+
+| qdoc | X | X | X | X |
++----------------------------------------------------------+
+| qhelpgenerator | X | X | X | X |
++----------------------------------------------------------+
+| qlalr | X | X | X | X |
++----------------------------------------------------------+
+| qmake | X | X | X | X |
++----------------------------------------------------------+
+| qml | X | X | X | X |
++----------------------------------------------------------+
+| qmlcachegen | X | X | X | X |
++----------------------------------------------------------+
+| qmldom | X | X | X | X |
++----------------------------------------------------------+
+| qmleasing | X | X | X | X |
++----------------------------------------------------------+
+| qmlformat | X | X | X | X |
++----------------------------------------------------------+
+| qmllint | X | X | X | X |
++----------------------------------------------------------+
+| qmlpreview | X | X | X | X |
++----------------------------------------------------------+
+| qmlprofiler | X | X | X | X |
++----------------------------------------------------------+
+| qmlscene | X | X | X | X |
++----------------------------------------------------------+
+| qmltestrunner | X | X | X | X |
++----------------------------------------------------------+
+| qmltime | X | X | X | X |
++----------------------------------------------------------+
+| qmlviewer | X | X | X | X |
++----------------------------------------------------------+
+| qtdiag | X | X | X | X |
++----------------------------------------------------------+
+| qtpaths | X | X | X | X |
++----------------------------------------------------------+
+| qtplugininfo | X | X | X | X |
++----------------------------------------------------------+
+| qvkgen | X | X | X | X |
++----------------------------------------------------------+
+| rcc | X | X | X | X |
++----------------------------------------------------------+
+| tracegen | X | X | X | X |
++----------------------------------------------------------+
+| uic | X | X | X | X |
++----------------------------------------------------------+
+| windeployqt | X | X | X | X |
++----------------------------------------------------------+
+| Target toolchains | | | X | X |
++----------------------------------------------------------+
+| Qt Debugging Bridge Host Tools | | | X | X |
++----------------------------------------------------------+
+| qtconfig-gui | | | X | X |
++----------------------------------------------------------+
+| Qt Emulator | | | X | X |
++----------------------------------------------------------+
+| Qt Creator VxWorks plugin | | | X | X |
++----------------------------------------------------------+
+| Qt Creator plugin for Qt | | | | X |
+| Application Manager | | | | |
++----------------------------------------------------------+
+| qmlinterfacegenerator | | | | X |
++----------------------------------------------------------+
+| qmltocpp | | | | X |
++----------------------------------------------------------+
+| qulfontcompiler | | | | X |
++----------------------------------------------------------+
+| Qt Deployment Server | | | | X |
++----------------------------------------------------------+
+
+
+Rights for Application and Device use cases
+
+Following table summarizes the rights afforded by different products of the
+Licensed Software to create and distribute Applications and Devices as defined
+in this Agreement (X marks for rights):
+
++---------------------------------------------------------------+
+| | Applications | Devices |
++---------------------------------------------------------------+
+| ADP | X | |
++---------------------------------------------------------------+
+| ADE | X | |
++---------------------------------------------------------------+
+| DCP | X | X |
++---------------------------------------------------------------+
+| DCE | X | X |
++---------------------------------------------------------------+
+
+Licensed Software: Designer tools and modules
+
+The modules and/or tools that are included in the respective product - Qt for
+Design Studio Professional (DSP), Qt for Design Studio Enterprise (DSE) - are
+marked with "X" in the below table.
+
+Designer tools provides no Redistributables.
+
++---------------------------------------------+
+| | DSP | DSE |
++---------------------------------------------+
+| Qt Design Studio | X | X |
++---------------------------------------------+
+| Qt Design Bridges | | X |
++---------------------------------------------+
+| QML Live on host | X | X |
++---------------------------------------------+
+| QML Live on target | | X |
++---------------------------------------------+
+| Variant Management | | X |
++---------------------------------------------+
+| Shader creation tools | | X |
++---------------------------------------------+
+| Profiling tools | | X |
++---------------------------------------------+
+| Simulink support | | X |
++---------------------------------------------+
+
+
+Both DSP and DSE can be used to create an user interface for use cases covered
+by ADP, ADE, DCP and DCE.
+
+Licensed Software: QA Tools
+
+The modules and/or tools that are included in the respective QA Tools product
+- Squish (both Tester and execution Licenses), Coco or Test Center - are marked
+with "X" in the below table. Optional features that will need additional
+licenses are marked with "O". QA Tools include no Redistributables.
+
++---------------------------------------------------------------------+
+| | Squish | Coco | Test Center |
++---------------------------------------------------------------------+
+| Squish IDE | X | | |
++---------------------------------------------------------------------+
+| QA Tool-specific command line tools | X | X | X |
++---------------------------------------------------------------------+
+| Coverage Browser | | X | |
++---------------------------------------------------------------------+
+| HTML interface | | | X |
++---------------------------------------------------------------------+
+| Qt Support Module | X | | |
++---------------------------------------------------------------------+
+| Java support module | X | | |
++---------------------------------------------------------------------+
+| Windows support module | X | | |
++---------------------------------------------------------------------+
+| iOS support module | X | | |
++---------------------------------------------------------------------+
+| Android support module | X | | |
++---------------------------------------------------------------------+
+| Web support module | X | | |
++---------------------------------------------------------------------+
+| macOS support module | X | | |
++---------------------------------------------------------------------+
+| VNC support module | X | | |
++---------------------------------------------------------------------+
+| MCU support module | X | | |
++---------------------------------------------------------------------+
+| C and C++ language module | | X | |
++---------------------------------------------------------------------+
+| C# language module | | X | |
++---------------------------------------------------------------------+
+| QML language module | | X | |
++---------------------------------------------------------------------+
+| Tester Cross-Compilation Add-On | O | O | |
++---------------------------------------------------------------------+
+
+License capabilities for Squish
+
+License capabilities that are included in the Squish Tester and Execution
+Licenses are marked with "X" in the below table.
+
++-----------------------------------------------------------------------------+
+| | Squish Tester License | Squish Execution License |
++-----------------------------------------------------------------------------+
+| Ability to create, edit, | X | |
+| and debug test cas | | |
++-----------------------------------------------------------------------------+
+| Ability to execute test | X | X |
+| cases | | |
++-----------------------------------------------------------------------------+
+
+Install and use capabilities for QA Tools
+
+Install and use capabilities that are included in the respective QA Tools
+products are defined in the below table.
+
++-----------------------------------------------------------------------------+
+| | Squish | Squish | Coco | Test |
+| | Tester | Execution | License | Center |
+| | License | License | | License |
++-----------------------------------------------------------------------------+
+| Number of installation | Unlimited | Unlimited | Unlimited | One(1) |
+| instances per license | | | | |
++-----------------------------------------------------------------------------+
+| Number of concurrent | Limited by| Limited by | Limited by | Limited by |
+| users | number of | number of | number of | number of |
+| | Squish | Squish | Coco | Test Center |
+| | Tester | Execution | Tester | Licenses |
+| | Licenses | Licenses | Licenses | |
++-----------------------------------------------------------------------------+
+
+
+APPENDIX 2: PRICING
+
+Separate template
+
+APPENDIX 3: ADD-ON PRODUCTS TO LICENSED SOFTWARE
+
+Intentionally left blank.
+
+APPENDIX 4: SMALL BUSINESS AND STARTUP
+
+The provisions of this Appendix 4 are applicable for companies with an annual
+revenue, including funding, equivalent to maximum of 250,000 USD (in applicable
+currency) during the latest full calendar year, as evidenced by duly audited
+records of the Licensee and approved by The Qt Company ("Start-up Company").
+
+Start-up Companies are qualified for a discounted License Fee for maximum of
+four (4) Development Licenses ("Start-up Development License") unless otherwise
+agreed between the parties.
+
+Start-up Development License entitles the respective Designated User for
+Support only for Install Support as defined in Appendix 9, Support Terms.
+
+Upon expiry of the respective Development License Term, the Start-up
+Development Licenses shall be automatically extended, pursuant to Section 3.1
+of the Agreement, for a Renewal Term either as new Start-up Development
+Licenses (if the Licensee still qualifies as a Start-up Company), or as normal
+then standard list price Development Licenses (if the Licensee no longer
+qualifies as a Start-up Company).
+
+APPENDIX 5: NON-COMMERCIAL AND EDUCATIONAL USE
+
+The provisions of this Appendix 5 are applicable for non-commercial use of the
+Licensed Software by the Licensee.
+
+For the purpose of this Appendix 5, the following additional definitions
+(replacing the relevant definition of the Agreement, where applicable) shall be
+applicable:
+
+"Demo Units" shall mean (i) hardware development platform, which incorporates
+the Licensed Software along with Licensee's software and/or hardware, and (ii)
+prototype versions of Applications or Devices.
+
+"Designated User(s)" shall mean the employees and students of the Licensee.
+
+"Licensee Products" shall mean Applications and/or Devices.
+
+"Permitted Purpose" shall mean (i) Licensee's internal evaluation and testing
+of Licensed Software, (ii) building Demo Units as well as (iii) educational
+use.
+
+"Agreement Term" shall mean a period of twelve (12) months or any such other
+period as may be agreed between the Parties.
+
+For the purpose of this Appendix 5, the following changes shall be agreed with
+respect to relevant Sections of the Agreement:
+ I. Recital (A) shall be replaced in its entirety to read as follows:
+ "(A) Licensee wishes to use the Licensed Software for the Permitted
+ Purpose."
+ II. Section 3.1 shall be replaced in its entirety to read as follows:
+ "The Qt Company grants to Licensee a personal, non-exclusive,
+ non-transferable, revocable, royalty-free license, valid for the
+ Agreement Term, to use, modify and copy the Licensed Software solely
+ for the Permitted Purpose. Licensee may install copies of the Licensed
+ Software on five (5) computers per Designated User, provided that only
+ the Designated Users who have a valid Development License may use the
+ Licensed Software. Licensee may demonstrate the Demo Units, provided
+ that such demonstrations must be conducted by Licensee, and the Demo
+ Units must remain in Licensee's possession and under Licensee's control
+ at all times.
+ For clarity, this Agreement does not (i) entitle Licensee to use
+ Licensed Software to create Applications or Devices (other than
+ prototypes thereof) or (ii) carry any distribution rights to Licensee,
+ but such rights are subject to and conditional upon conclusion of a
+ separate license agreement with The Qt Company."
+ III. Sections 3.2, 3.3, 3.5, 3.6, 8 and 10 shall be deleted.
+ IV. Section 3.4 shall be replaced in its entirety to read as follows:
+ "Licensee shall not:
+ - remove or alter any copyright, trademark or other proprietary rights
+ notice contained in any portion of the Licensed Software;
+ - transfer, publish, sublicense, disclose, display or otherwise make
+ the Licensed Software available to any third party (except that
+ Licensee may demonstrate the Demo Units pursuant to Section 3.1);
+ - in any way combine, incorporate or integrate Licensed Software with,
+ or use Licensed Software for creation of, any software created with
+ or incorporating Open Source Qt; Licensee shall cause all Designated
+ Users who make use of the licenses granted under this Agreement, to
+ be contractually bound to comply with the relevant terms of this
+ Agreement and not to use the Licensed Software beyond the terms
+ hereof. Licensee shall be responsible for any and all actions and
+ omissions of its Designated Users relating to the Licensed Software
+ and use thereof. Any use of Licensed Software beyond the provisions
+ of this Agreement is strictly prohibited and requires an additional
+ license from The Qt Company."
+ V. Section 12 shall be replaced in its entirety to read as follows:
+ "This Agreement shall enter into force upon due acceptance by both
+ Parties and remain in force for the Agreement Term, unless and until
+ terminated pursuant to the terms of Section 12.
+ Upon termination of the Agreement, Licensee shall cease using the
+ Licensed Software. All other copies of Licensed Software in the
+ possession or control of Licensee must be erased or destroyed. An
+ officer of Licensee must, upon request, promptly deliver to The Qt
+ Company a written confirmation that this has occurred."
+
+Except for the modifications specified above, this Appendix carries no change
+to the terms of the Agreement which shall remain in full force.
+
+APPENDIX 6: LICENSE REPORTING
+
+Separate template
+
+APPENDIX 7: MARKETING RIGHTS
+
+This Appendix 7 has the purpose to grant visibility through The Qt Company
+marketing channels of the usage of Qt and related product and service in
+Licensee product. Following related marketing right are agreed between the Qt
+Company and the Licensee.
+
+1. LICENSEE NAME AND LICENSEE LOGO
+
+The Qt Company has the right to use Licensee name and Licensee logo in public
+channel, in respect of the value proposition that the Qt company provided to
+the Licensee.
+
+2. MARKETING CONTENT COOPERATION
+
+2.1. LICENSEE CASES
+
+The Licensee is open to collaborate on content creation for marketing and
+communication purpose. The Licensee will nominate one responsible that will be
+in charge to support The Qt company with this content creation, according to
+content format paragraph, answering technical questions or sharing professional
+picture or video of required content. The Qt Company will have the right to
+advertise this in Content Format and Channel as mentioned in paragraph 3 and 4.
+
+2.2. FINAL PRODUCT REFERRAL
+
+Licensee agree that The Qt Company could connect their software product and
+services with the Licensee device or application, that the Licensee has created
+using The Qt Company technology and competence. Licensee will provide high
+quality picture, and video of the created final product where the Qt technology
+is running into. The Qt Company will have the right to advertise this in
+Content Format and Channel as mentioned in paragraph 3 and 4.
+
+3. CONTENT FORMAT
+
+- Video
+- Written Licensee case
+- Press release
+- Social media posts
+- Emails
+- Event booth Graphics
+- Printed material
+
+4. CHANNELS
+
+- Social media
+- The Qt Company resource center and website
+- Email to the Qt company contact database
+- Events
+- Online webinars
+- Public speech
+- Public presentations
+
+APPENDIX 8: INTENTIONALLY LEFT BLANK
+
+APPENDIX 9: SUPPORT TERMS
+
+These Qt support terms and conditions ("Support Terms") set forth the legal
+framework, where under The Qt Company ("The Qt Company") provides support
+services (as herein defined) to the Licensee.
+
+1 DEFINITIONS
+
+"Application Code" shall mean a computer software program written strictly
+using the Qt programming language, by or for the Licensee, with a user
+interface, enabling the Licensee or their users to accomplish a specific task
+and display any results of the task on the display monitor or screen.
+
+"Dedicated Contact" shall mean the employee of The Qt Company who will be the
+first point of contact for all Designated Users' requests for Support.
+
+"Errors" shall mean an error, flaw, mistake, failure, or fault in Licensed
+Software that prevents it from behaving as described in the relevant
+documentation or as agreed between the Parties.
+
+"Extended Support" shall mean a continuation to the normal Support period,
+which allows Designated Users to receive selected Support (Standard Support or
+Premium Support) for a version of Licensed Software that is no longer generally
+supported by The Qt Company.
+
+"Install Support" shall mean Support that is limited to installation related
+Error(s) on Development Platforms specified as supported host platforms for
+each Qt release under doc.qt.io.
+
+"Maintenance Release" shall mean a release or version of Licensed Software
+containing bug fixes, error corrections and other changes targeted to
+maintaining and improving product stability and quality. Maintenance Releases
+are generally depicted as a change to the third digit of Licensed Software
+version number.
+
+"Platforms" shall mean both Development Platforms and Deployment Platforms.
+Supported host and target Platforms may vary from for each Qt release as
+defined under doc.qt.io.
+
+"Premium Support" shall mean an upgraded level of Support that The Qt Company
+provides pursuant to these Support Terms to Licensee if Licensee has purchased
+Premium Support instead of Standard Support. Premium Support shall always be
+purchased for all Designated User(s) in the respective development team of the
+Licensee.
+
+"Response Time" shall mean the period of time from when Licensee notifies
+TheQt Company about an Error or requests Support until The Qt Company provides
+Licensee with a response that addresses (but not necessarily resolves) the
+reported Error or provides the requested Support.
+
+"Standard Support" shall mean standard level of Support that The Qt Company
+provides pursuant to these Support Terms to Licensee.
+
+"Support" shall mean developer assistance that is provided by The Qt Company
+to assist eligible Designated Users in Licensed Software installation, usage
+and functionality problem resolution for Error(s) and Error workarounds
+pursuant to the terms of these Support Terms. Support for different products is
+available as specified in the below table ("X" marking the Support that is
+included in the license price, optional Add-on Support services are marked as
+"O"):
+
++-----------------------------------------------------------------------+
+| |ADP|ADE|DCP|DCE|DSP|DSE|Squish|Coco|Test Center|
++-----------------------------------------------------------------------+
+| Install Support | X | X | X | X | X | X | X | X | X |
++-----------------------------------------------------------------------+
+| Standard Support | | X | X | X | X | X | X | X | X |
++-----------------------------------------------------------------------+
+| Premium Support | | O | O | O | O | O | O | O | O |
++-----------------------------------------------------------------------+
+| Extended Support | | O | O | O | O | O | | | |
++-----------------------------------------------------------------------+
+| Tool Qualification Kit| | | | | | | O | O | |
++-----------------------------------------------------------------------+
+
+"Support Validity Term" shall mean the Development License Term or any other
+fixed time period agreed between the Parties during which time the Customer is
+eligible to receive Support from The Qt Company.
+
+"Tool Qualification Kit" shall mean a customized set of documents and
+validation test cases.
+
+2 SUPPORT SERVICES
+
+2.1 Support Services Provided by The Qt Company
+
+Subject to these Support Terms and during the Support Validity Term, The Qt
+Company will via its web-based support user-interface, provide Designated
+User(s) with Support for the Platforms which Customer has licensed under the
+Agreement.
+The Qt Company will make commercially reasonable efforts to solve any Errors
+reported by Designated User(s). Resolution of an Error may be provided through
+Designated User(s) themselves downloading of a later released version of the
+applicable Licensed Software product(s) or providing the Designated User with a
+temporary workaround addressing such Error.
+
+2.2 Licensee's Obligations
+
+To report an Error, the Designated User shall register the Error on The Qt
+Company's web-based support user interface located at:
+https://account.qt.io/login or at another location designated by The Qt Company.
+
+The Designated User must provide adequate information and documentation to The
+Qt Company to enable it to recreate the Error or problem for which the
+Designated User has sought assistance.
+To ensure efficient handling of Errors, the Designated User must provide the
+following information, where relevant:
+- A clear, detailed description of the problem, question or suggestion;
+- Identification of which Licensed Software product and version is affected;
+- Identification of the operating environment (e.g. operating system, hardware
+ Platform, build tools, etc.) on which the problem exists;
+- On Standard Support: A complete and compilable test case of not more than 500
+ lines of code that demonstrates the problem;
+- On Premium Support: A complete and compilable test case that demonstrates the
+ problem or access to Application Code source codes.
+
+Additional relevant content, such as screenshots, etc.
+Additional content should be included as attachments. The preferred image
+formats are JPEG and PNG. Compressed content should be included in zip or
+tar.gz archives. Executable content and documents in platform specific formats
+such as Microsoft Office' are not accepted.
+
+In order for The Qt Company to provide prompt handling of Errors, the
+Designated User shall promptly respond to any requests from The Qt Company for
+additional information.
+
+2.3 Support Limitations
+
+General limitations:
+
+Each version or release of the Licensed Software will be Supported under
+Standard Support or Premium Support only for limited time period as set forth
+in doc.qt.io. For example, regular releases of Qt Software are supported for
+one (1) year from the release date of the version x.y.0 and Long Term Support
+(LTS) Releases are supported for a period of three (3) years from the release
+date of the LTS version x.y.0.
+
+The Qt Company shall only provide Support for Designated User(s).
+
+Support is made available for the entire development teams only: It is not
+allowed to purchase Support only for some members of the development team, and
+all Designated Users of the respective development team must be eligible for
+the same level of Support.
+
+Support is not provided for snapshots, preview releases, beta releases or
+release candidates.
+
+The Qt Company shall have no obligation to provide Support for hardware or
+operating system specific problems or problems arising from improper use,
+accident, neglect or modification of Qt.
+
+Limitations with Install Support:
+
+Support limited to Error(s) regarding installation and setting up of the Qt
+development environment on host Platforms.
+
+Limitations with Standard Support:
+
+The Qt Company shall not provide Support for third-party software or problems
+caused by third-party software even if such third-party software is distributed
+together with Licensed Software product(s).
+
+The Qt Company shall only provide Support for Error(s) that are reported on and
+can be reproduced on Platforms that are officially supported for the release of
+the Licensed Software.
+
+Limitations with Premium support:
+
+The Qt Company shall not provide Support for third-party software or problems
+caused by third-party software. However, if such third-party software is
+distributed together with Licensed Software, The Qt Company will make
+commercially reasonable efforts to solve such problems.
+
+The Qt Company shall only provide Support for Error(s) that can be reproduced
+on Platforms that are officially supported for the release of the Licensed
+Software. If the Error is on a Platform that is not supported, The Qt Company
+will make commercially reasonable efforts to provide a solution on closest
+corresponding supported Platform.
+
+Premium Support is optional and purchased for an agreed bucket of hours
+("Bucket"). Hours can be used by any Designated User in the respective
+development team. To encourage continuous usage of the Support, ten percent
+(10%) of the purchased Bucket shall automatically expire (regardless of whether
+such support hours are actually used or not by the Licensee) each month after
+three (3) months from the purchase of the Premium Support.
+
+2.4 Extended Support
+
+Extended Support extends the Support Validity Term for a release of Licensed
+Software that is no longer generally supported.
+
+Extended Support includes and is by default provided with Standard Support
+rules and limitations, unless Extended Support is purchased with Premium
+Support in which case Premium Support rules and limitations will apply.
+
+Extended Support is optional and purchased with annual fee and separately per
+each Licensee product. Extended Support will need definition of (i) Licensee
+product, (ii) used Platform(s) and (iii) Licensed Software version(s).
+
+2.5 Tool Qualification Kit
+
+The Qt Company shall provide set of customized documents and validation tests
+that enable Licensee to qualify QA testing tool for the purpose of ISO 26262,
+EN 50128, DO-330, IEC 61508, IEC 62304 or IEC 13485 certification Licensee end
+to end solution.
+
+3 RESPONSE TIME
+
+In performing Support, The Qt Company shall commit to following, non-binding,
+Response Times:
+
+Standard Support: Errors and Support requests will have a Response Time not to
+exceed two (2) business days.
+
+Premium Support: Errors and Support requests will have a Response Time not to
+exceed one (1) business day.
+
+For complex issues, The Qt Company may provide an initial response to the
+Designated User and then follow up, without undue delay, with additional
+communication before an Error is properly addressed or Support provided.
+
+4 ADDITIONAL SERVICES IN PREMIUM SUPPORT
+
+The Designated User(s) will be assigned a Dedicated Contact to handle requests
+for Support. Dedicated Contact is subject to change in cases such as sick
+leave, vacation and other similar reasons.
+
+The Designated User(s) can on request ask The Qt Company to access their
+computer remotely in order to resolve problems directly.
+
+The Designated User(s) can request a session via Instant Messaging or phone
+call in the support request to The Qt Company.
+
+Premium Support can assist Licensee in implementing new features, bug fixes
+and accessing patches in Licensed Software or Application Code.
+
+All Support requests will be handled with high priority.
+
+5 MAINTENANCE RELEASES, UPDATES AND UPGRADES
+
+Under the Support the Customer is eligible for Maintenance Releases and Updates
+that The Qt Company generally makes available to customers who has purchased
+Support. Unless otherwise decided by The Company at its free and absolute
+discretion, Upgrades will not be provided under the Support.
+
+The primary focus of Maintenance Releases is product quality. Therefore, each
+Maintenance Release typically includes the following types of changes to the
+previous version of Licensed Software:
+- Bug fixes caused by changes to previously working code;
+- Fixes related to build issues on supported Platforms;
+- Error corrections specific to a single Platform that are not present on other
+ Platforms;
+- Critical Error corrections such as crashes, data corruption, loss of data,
+ race conditions; and
+- Updates to documentation and license information when deemed necessary by
+ The Qt Company.
+
+The primary focus of Updates is introducing new features to Licensed Software
+and covering new platforms. Therefore, each Updates typically includes the
+following types of changes to the previous version of Licensed Software:
+- New platform support;
+- New toolchain support;
+- New features and Qt modules;
+
+6 WARRANTY DISCLAIMER
+
+The Qt Company makes no warranties that the Support provided will be successful
+in resolving any difficulties or problems or in diagnosing faults reported by
+Licensee. Support is provided to Licensee on an "as is" basis. To the maximum
+extent permitted by applicable law, The Qt Company disclaims all warranties and
+conditions, either express or implied, including, but not limited to, implied
+warranties of merchantability and fitness for a particular purpose for the
+Support provided by The Qt Company to Licensee.
+
+APPENDIX 10: CONVERSION TO SUBSCRIPTION
+
+Subject to the terms of this Appendix Licensee's current development licenses
+("Current Licenses") for commercial version of Qt Software and the license
+agreements governing such Current Licenses ("Existing Agreements") are being
+replaced by this Agreement and subscription based Development Licenses
+governed hereunder, as further specified below.
+
++---------------------------------------------------------------------------+
+| Existing Agreement(s) | <Trolltech, Nokia, Digia, The Qt Company> and |
+| signing parties, version | <Licensee> <Version of the Agreement, e.g. 2,0,|
+| and date of signatures | 3.2 or 4.1> <Date of the agreement signatures> |
+| thereof | |
++---------------------------------------------------------------------------+
+
+Parties hereby agree on conversion of Current Licenses listed in attached
+Exhibit A to the subscription licenses listed in attached Exhibit B for use
+through License Term. As of the date hereof,
+
+i. Licensee's Current Licenses as listed in Exhibit A shall terminate and be
+replaced with the Subscription licenses listed in Exhibit B and;
+ii. Existing Agreements are terminated.
+
+Prices for the conversion of Current Licenses are defined in Appendix 2
+Pricing or Quote.
+
+Notwithstanding anything in this Appendix to the contrary, and in addition to
+any payments due pursuant to this Appendix, Licensee remains fully obligated to
+fulfill any and all outstanding payment obligations to The Qt Company under any
+applicable Existing Agreements. For the avoidance of doubt, if any payments
+remain outstanding on the Current Licenses under the applicable terms Licensee
+will continue to make such payments in accordance with the applicable order
+documentation, notwithstanding the fact that the Current Licenses are being
+converted to Development Licenses pursuant to this Appendix.
--- /dev/null
+set(QT_REPO_MODULE_VERSION "6.2.4")
+set(QT_REPO_MODULE_PRERELEASE_VERSION_SEGMENT "")
--- /dev/null
+load(qt_build_config)
+CONFIG += qt_example_installs
+
+DEFINES += QT_NO_JAVA_STYLE_ITERATORS
+DEFINES += QT_NO_FOREACH
+
+MODULE_VERSION = 6.2.4
+
+QTRO_SOURCE_TREE = $$PWD
--- /dev/null
+923c6dee3f0af69f848bf3bd4575e7dc8e0dc49e
--- /dev/null
+cmake_minimum_required(VERSION 3.16)
+
+include(.cmake.conf)
+project(QtRemoteObjects
+ VERSION "${QT_REPO_MODULE_VERSION}"
+ DESCRIPTION "Qt RemoteObjects Libraries"
+ HOMEPAGE_URL "https://qt.io/"
+ LANGUAGES CXX C
+)
+
+# Make sure we only use latest private CMake API, aka no compatibility wrappers.
+set(QT_NO_INTERNAL_COMPATIBILITY_FUNCTIONS TRUE)
+
+# Make sure we use the fixed BASE argument of qt_add_resource.
+set(QT_USE_FIXED_QT_ADD_RESOURCE_BASE TRUE)
+
+find_package(Qt6 ${PROJECT_VERSION} CONFIG REQUIRED COMPONENTS BuildInternals Core Network)
+find_package(Qt6 ${PROJECT_VERSION} CONFIG OPTIONAL_COMPONENTS Gui Widgets Quick QuickTest)
+
+if(NOT TARGET Qt::Network)
+ message(NOTICE "Skipping the build as the condition \"TARGET Qt::Network\" is not met.")
+ return()
+endif()
+qt_build_repo()
+
+if(NOT QT_BUILD_STANDALONE_TESTS)
+ # Copy mkspecs for users preferring qmake builds
+ set(mkspecs_install_dir "${INSTALL_MKSPECSDIR}")
+ qt_path_join(mkspecs_install_dir ${QT_INSTALL_DIR} ${mkspecs_install_dir})
+
+ qt_copy_or_install(DIRECTORY mkspecs/
+ DESTINATION "${mkspecs_install_dir}"
+ FILES_MATCHING PATTERN "*.pr[if]"
+ )
+endif()
--- /dev/null
+
+ GNU Free Documentation License
+ Version 1.3, 3 November 2008
+
+
+ Copyright (C) 2000, 2001, 2002, 2007, 2008 Free Software Foundation, Inc.
+ <https://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+0. PREAMBLE
+
+The purpose of this License is to make a manual, textbook, or other
+functional and useful document "free" in the sense of freedom: to
+assure everyone the effective freedom to copy and redistribute it,
+with or without modifying it, either commercially or noncommercially.
+Secondarily, this License preserves for the author and publisher a way
+to get credit for their work, while not being considered responsible
+for modifications made by others.
+
+This License is a kind of "copyleft", which means that derivative
+works of the document must themselves be free in the same sense. It
+complements the GNU General Public License, which is a copyleft
+license designed for free software.
+
+We have designed this License in order to use it for manuals for free
+software, because free software needs free documentation: a free
+program should come with manuals providing the same freedoms that the
+software does. But this License is not limited to software manuals;
+it can be used for any textual work, regardless of subject matter or
+whether it is published as a printed book. We recommend this License
+principally for works whose purpose is instruction or reference.
+
+
+1. APPLICABILITY AND DEFINITIONS
+
+This License applies to any manual or other work, in any medium, that
+contains a notice placed by the copyright holder saying it can be
+distributed under the terms of this License. Such a notice grants a
+world-wide, royalty-free license, unlimited in duration, to use that
+work under the conditions stated herein. The "Document", below,
+refers to any such manual or work. Any member of the public is a
+licensee, and is addressed as "you". You accept the license if you
+copy, modify or distribute the work in a way requiring permission
+under copyright law.
+
+A "Modified Version" of the Document means any work containing the
+Document or a portion of it, either copied verbatim, or with
+modifications and/or translated into another language.
+
+A "Secondary Section" is a named appendix or a front-matter section of
+the Document that deals exclusively with the relationship of the
+publishers or authors of the Document to the Document's overall
+subject (or to related matters) and contains nothing that could fall
+directly within that overall subject. (Thus, if the Document is in
+part a textbook of mathematics, a Secondary Section may not explain
+any mathematics.) The relationship could be a matter of historical
+connection with the subject or with related matters, or of legal,
+commercial, philosophical, ethical or political position regarding
+them.
+
+The "Invariant Sections" are certain Secondary Sections whose titles
+are designated, as being those of Invariant Sections, in the notice
+that says that the Document is released under this License. If a
+section does not fit the above definition of Secondary then it is not
+allowed to be designated as Invariant. The Document may contain zero
+Invariant Sections. If the Document does not identify any Invariant
+Sections then there are none.
+
+The "Cover Texts" are certain short passages of text that are listed,
+as Front-Cover Texts or Back-Cover Texts, in the notice that says that
+the Document is released under this License. A Front-Cover Text may
+be at most 5 words, and a Back-Cover Text may be at most 25 words.
+
+A "Transparent" copy of the Document means a machine-readable copy,
+represented in a format whose specification is available to the
+general public, that is suitable for revising the document
+straightforwardly with generic text editors or (for images composed of
+pixels) generic paint programs or (for drawings) some widely available
+drawing editor, and that is suitable for input to text formatters or
+for automatic translation to a variety of formats suitable for input
+to text formatters. A copy made in an otherwise Transparent file
+format whose markup, or absence of markup, has been arranged to thwart
+or discourage subsequent modification by readers is not Transparent.
+An image format is not Transparent if used for any substantial amount
+of text. A copy that is not "Transparent" is called "Opaque".
+
+Examples of suitable formats for Transparent copies include plain
+ASCII without markup, Texinfo input format, LaTeX input format, SGML
+or XML using a publicly available DTD, and standard-conforming simple
+HTML, PostScript or PDF designed for human modification. Examples of
+transparent image formats include PNG, XCF and JPG. Opaque formats
+include proprietary formats that can be read and edited only by
+proprietary word processors, SGML or XML for which the DTD and/or
+processing tools are not generally available, and the
+machine-generated HTML, PostScript or PDF produced by some word
+processors for output purposes only.
+
+The "Title Page" means, for a printed book, the title page itself,
+plus such following pages as are needed to hold, legibly, the material
+this License requires to appear in the title page. For works in
+formats which do not have any title page as such, "Title Page" means
+the text near the most prominent appearance of the work's title,
+preceding the beginning of the body of the text.
+
+The "publisher" means any person or entity that distributes copies of
+the Document to the public.
+
+A section "Entitled XYZ" means a named subunit of the Document whose
+title either is precisely XYZ or contains XYZ in parentheses following
+text that translates XYZ in another language. (Here XYZ stands for a
+specific section name mentioned below, such as "Acknowledgements",
+"Dedications", "Endorsements", or "History".) To "Preserve the Title"
+of such a section when you modify the Document means that it remains a
+section "Entitled XYZ" according to this definition.
+
+The Document may include Warranty Disclaimers next to the notice which
+states that this License applies to the Document. These Warranty
+Disclaimers are considered to be included by reference in this
+License, but only as regards disclaiming warranties: any other
+implication that these Warranty Disclaimers may have is void and has
+no effect on the meaning of this License.
+
+2. VERBATIM COPYING
+
+You may copy and distribute the Document in any medium, either
+commercially or noncommercially, provided that this License, the
+copyright notices, and the license notice saying this License applies
+to the Document are reproduced in all copies, and that you add no
+other conditions whatsoever to those of this License. You may not use
+technical measures to obstruct or control the reading or further
+copying of the copies you make or distribute. However, you may accept
+compensation in exchange for copies. If you distribute a large enough
+number of copies you must also follow the conditions in section 3.
+
+You may also lend copies, under the same conditions stated above, and
+you may publicly display copies.
+
+
+3. COPYING IN QUANTITY
+
+If you publish printed copies (or copies in media that commonly have
+printed covers) of the Document, numbering more than 100, and the
+Document's license notice requires Cover Texts, you must enclose the
+copies in covers that carry, clearly and legibly, all these Cover
+Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on
+the back cover. Both covers must also clearly and legibly identify
+you as the publisher of these copies. The front cover must present
+the full title with all words of the title equally prominent and
+visible. You may add other material on the covers in addition.
+Copying with changes limited to the covers, as long as they preserve
+the title of the Document and satisfy these conditions, can be treated
+as verbatim copying in other respects.
+
+If the required texts for either cover are too voluminous to fit
+legibly, you should put the first ones listed (as many as fit
+reasonably) on the actual cover, and continue the rest onto adjacent
+pages.
+
+If you publish or distribute Opaque copies of the Document numbering
+more than 100, you must either include a machine-readable Transparent
+copy along with each Opaque copy, or state in or with each Opaque copy
+a computer-network location from which the general network-using
+public has access to download using public-standard network protocols
+a complete Transparent copy of the Document, free of added material.
+If you use the latter option, you must take reasonably prudent steps,
+when you begin distribution of Opaque copies in quantity, to ensure
+that this Transparent copy will remain thus accessible at the stated
+location until at least one year after the last time you distribute an
+Opaque copy (directly or through your agents or retailers) of that
+edition to the public.
+
+It is requested, but not required, that you contact the authors of the
+Document well before redistributing any large number of copies, to
+give them a chance to provide you with an updated version of the
+Document.
+
+
+4. MODIFICATIONS
+
+You may copy and distribute a Modified Version of the Document under
+the conditions of sections 2 and 3 above, provided that you release
+the Modified Version under precisely this License, with the Modified
+Version filling the role of the Document, thus licensing distribution
+and modification of the Modified Version to whoever possesses a copy
+of it. In addition, you must do these things in the Modified Version:
+
+A. Use in the Title Page (and on the covers, if any) a title distinct
+ from that of the Document, and from those of previous versions
+ (which should, if there were any, be listed in the History section
+ of the Document). You may use the same title as a previous version
+ if the original publisher of that version gives permission.
+B. List on the Title Page, as authors, one or more persons or entities
+ responsible for authorship of the modifications in the Modified
+ Version, together with at least five of the principal authors of the
+ Document (all of its principal authors, if it has fewer than five),
+ unless they release you from this requirement.
+C. State on the Title page the name of the publisher of the
+ Modified Version, as the publisher.
+D. Preserve all the copyright notices of the Document.
+E. Add an appropriate copyright notice for your modifications
+ adjacent to the other copyright notices.
+F. Include, immediately after the copyright notices, a license notice
+ giving the public permission to use the Modified Version under the
+ terms of this License, in the form shown in the Addendum below.
+G. Preserve in that license notice the full lists of Invariant Sections
+ and required Cover Texts given in the Document's license notice.
+H. Include an unaltered copy of this License.
+I. Preserve the section Entitled "History", Preserve its Title, and add
+ to it an item stating at least the title, year, new authors, and
+ publisher of the Modified Version as given on the Title Page. If
+ there is no section Entitled "History" in the Document, create one
+ stating the title, year, authors, and publisher of the Document as
+ given on its Title Page, then add an item describing the Modified
+ Version as stated in the previous sentence.
+J. Preserve the network location, if any, given in the Document for
+ public access to a Transparent copy of the Document, and likewise
+ the network locations given in the Document for previous versions
+ it was based on. These may be placed in the "History" section.
+ You may omit a network location for a work that was published at
+ least four years before the Document itself, or if the original
+ publisher of the version it refers to gives permission.
+K. For any section Entitled "Acknowledgements" or "Dedications",
+ Preserve the Title of the section, and preserve in the section all
+ the substance and tone of each of the contributor acknowledgements
+ and/or dedications given therein.
+L. Preserve all the Invariant Sections of the Document,
+ unaltered in their text and in their titles. Section numbers
+ or the equivalent are not considered part of the section titles.
+M. Delete any section Entitled "Endorsements". Such a section
+ may not be included in the Modified Version.
+N. Do not retitle any existing section to be Entitled "Endorsements"
+ or to conflict in title with any Invariant Section.
+O. Preserve any Warranty Disclaimers.
+
+If the Modified Version includes new front-matter sections or
+appendices that qualify as Secondary Sections and contain no material
+copied from the Document, you may at your option designate some or all
+of these sections as invariant. To do this, add their titles to the
+list of Invariant Sections in the Modified Version's license notice.
+These titles must be distinct from any other section titles.
+
+You may add a section Entitled "Endorsements", provided it contains
+nothing but endorsements of your Modified Version by various
+parties--for example, statements of peer review or that the text has
+been approved by an organization as the authoritative definition of a
+standard.
+
+You may add a passage of up to five words as a Front-Cover Text, and a
+passage of up to 25 words as a Back-Cover Text, to the end of the list
+of Cover Texts in the Modified Version. Only one passage of
+Front-Cover Text and one of Back-Cover Text may be added by (or
+through arrangements made by) any one entity. If the Document already
+includes a cover text for the same cover, previously added by you or
+by arrangement made by the same entity you are acting on behalf of,
+you may not add another; but you may replace the old one, on explicit
+permission from the previous publisher that added the old one.
+
+The author(s) and publisher(s) of the Document do not by this License
+give permission to use their names for publicity for or to assert or
+imply endorsement of any Modified Version.
+
+
+5. COMBINING DOCUMENTS
+
+You may combine the Document with other documents released under this
+License, under the terms defined in section 4 above for modified
+versions, provided that you include in the combination all of the
+Invariant Sections of all of the original documents, unmodified, and
+list them all as Invariant Sections of your combined work in its
+license notice, and that you preserve all their Warranty Disclaimers.
+
+The combined work need only contain one copy of this License, and
+multiple identical Invariant Sections may be replaced with a single
+copy. If there are multiple Invariant Sections with the same name but
+different contents, make the title of each such section unique by
+adding at the end of it, in parentheses, the name of the original
+author or publisher of that section if known, or else a unique number.
+Make the same adjustment to the section titles in the list of
+Invariant Sections in the license notice of the combined work.
+
+In the combination, you must combine any sections Entitled "History"
+in the various original documents, forming one section Entitled
+"History"; likewise combine any sections Entitled "Acknowledgements",
+and any sections Entitled "Dedications". You must delete all sections
+Entitled "Endorsements".
+
+
+6. COLLECTIONS OF DOCUMENTS
+
+You may make a collection consisting of the Document and other
+documents released under this License, and replace the individual
+copies of this License in the various documents with a single copy
+that is included in the collection, provided that you follow the rules
+of this License for verbatim copying of each of the documents in all
+other respects.
+
+You may extract a single document from such a collection, and
+distribute it individually under this License, provided you insert a
+copy of this License into the extracted document, and follow this
+License in all other respects regarding verbatim copying of that
+document.
+
+
+7. AGGREGATION WITH INDEPENDENT WORKS
+
+A compilation of the Document or its derivatives with other separate
+and independent documents or works, in or on a volume of a storage or
+distribution medium, is called an "aggregate" if the copyright
+resulting from the compilation is not used to limit the legal rights
+of the compilation's users beyond what the individual works permit.
+When the Document is included in an aggregate, this License does not
+apply to the other works in the aggregate which are not themselves
+derivative works of the Document.
+
+If the Cover Text requirement of section 3 is applicable to these
+copies of the Document, then if the Document is less than one half of
+the entire aggregate, the Document's Cover Texts may be placed on
+covers that bracket the Document within the aggregate, or the
+electronic equivalent of covers if the Document is in electronic form.
+Otherwise they must appear on printed covers that bracket the whole
+aggregate.
+
+
+8. TRANSLATION
+
+Translation is considered a kind of modification, so you may
+distribute translations of the Document under the terms of section 4.
+Replacing Invariant Sections with translations requires special
+permission from their copyright holders, but you may include
+translations of some or all Invariant Sections in addition to the
+original versions of these Invariant Sections. You may include a
+translation of this License, and all the license notices in the
+Document, and any Warranty Disclaimers, provided that you also include
+the original English version of this License and the original versions
+of those notices and disclaimers. In case of a disagreement between
+the translation and the original version of this License or a notice
+or disclaimer, the original version will prevail.
+
+If a section in the Document is Entitled "Acknowledgements",
+"Dedications", or "History", the requirement (section 4) to Preserve
+its Title (section 1) will typically require changing the actual
+title.
+
+
+9. TERMINATION
+
+You may not copy, modify, sublicense, or distribute the Document
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense, or distribute it is void, and
+will automatically terminate your rights under this License.
+
+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, receipt of a copy of some or all of the same material does
+not give you any rights to use it.
+
+
+10. FUTURE REVISIONS OF THIS LICENSE
+
+The Free Software Foundation may publish new, revised versions of the
+GNU Free Documentation 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. See
+https://www.gnu.org/licenses/.
+
+Each version of the License is given a distinguishing version number.
+If the Document specifies that a particular numbered version of this
+License "or any later version" applies to it, you have the option of
+following the terms and conditions either of that specified version or
+of any later version that has been published (not as a draft) by the
+Free Software Foundation. If the Document does not specify a version
+number of this License, you may choose any version ever published (not
+as a draft) by the Free Software Foundation. If the Document
+specifies that a proxy can decide which future versions of this
+License can be used, that proxy's public statement of acceptance of a
+version permanently authorizes you to choose that version for the
+Document.
+
+11. RELICENSING
+
+"Massive Multiauthor Collaboration Site" (or "MMC Site") means any
+World Wide Web server that publishes copyrightable works and also
+provides prominent facilities for anybody to edit those works. A
+public wiki that anybody can edit is an example of such a server. A
+"Massive Multiauthor Collaboration" (or "MMC") contained in the site
+means any set of copyrightable works thus published on the MMC site.
+
+"CC-BY-SA" means the Creative Commons Attribution-Share Alike 3.0
+license published by Creative Commons Corporation, a not-for-profit
+corporation with a principal place of business in San Francisco,
+California, as well as future copyleft versions of that license
+published by that same organization.
+
+"Incorporate" means to publish or republish a Document, in whole or in
+part, as part of another Document.
+
+An MMC is "eligible for relicensing" if it is licensed under this
+License, and if all works that were first published under this License
+somewhere other than this MMC, and subsequently incorporated in whole or
+in part into the MMC, (1) had no cover texts or invariant sections, and
+(2) were thus incorporated prior to November 1, 2008.
+
+The operator of an MMC Site may republish an MMC contained in the site
+under CC-BY-SA on the same site at any time before August 1, 2009,
+provided the MMC is eligible for relicensing.
+
+
+ADDENDUM: How to use this License for your documents
+
+To use this License in a document you have written, include a copy of
+the License in the document and put the following copyright and
+license notices just after the title page:
+
+ Copyright (c) YEAR YOUR NAME.
+ Permission is granted to copy, distribute and/or modify this document
+ under the terms of the GNU Free Documentation License, Version 1.3
+ or any later version published by the Free Software Foundation;
+ with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.
+ A copy of the license is included in the section entitled "GNU
+ Free Documentation License".
+
+If you have Invariant Sections, Front-Cover Texts and Back-Cover Texts,
+replace the "with...Texts." line with this:
+
+ with the Invariant Sections being LIST THEIR TITLES, with the
+ Front-Cover Texts being LIST, and with the Back-Cover Texts being LIST.
+
+If you have Invariant Sections without Cover Texts, or some other
+combination of the three, merge those two alternatives to suit the
+situation.
+
+If your document contains nontrivial examples of program code, we
+recommend releasing these examples in parallel under your choice of
+free software license, such as the GNU General Public License,
+to permit their use in free software.
--- /dev/null
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.) 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
+this service 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 make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. 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.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute 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 and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+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
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the 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 a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE 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.
+
+ 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
+convey 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 2 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, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision 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, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This 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.
--- /dev/null
+ 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>.
--- /dev/null
+This is the GNU General Public License version 3, annotated with The
+Qt Company GPL Exception 1.0:
+
+-------------------------------------------------------------------------
+
+The Qt Company GPL Exception 1.0
+
+Exception 1:
+
+As a special exception you may create a larger work which contains the
+output of this application and distribute that work under terms of your
+choice, so long as the work is not otherwise derived from or based on
+this application and so long as the work does not in itself generate
+output that contains the output from this application in its original
+or modified form.
+
+Exception 2:
+
+As a special exception, you have permission to combine this application
+with Plugins licensed under the terms of your choice, to produce an
+executable, and to copy and distribute the resulting executable under
+the terms of your choice. However, the executable must be accompanied
+by a prominent notice offering all users of the executable the entire
+source code to this application, excluding the source code of the
+independent modules, but including any changes you have made to this
+application, under the terms of this license.
+
+
+-------------------------------------------------------------------------
+
+ 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>.
--- /dev/null
+ GNU LESSER 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.
+
+
+ This version of the GNU Lesser General Public License incorporates
+the terms and conditions of version 3 of the GNU General Public
+License, supplemented by the additional permissions listed below.
+
+ 0. Additional Definitions.
+
+ As used herein, "this License" refers to version 3 of the GNU Lesser
+General Public License, and the "GNU GPL" refers to version 3 of the GNU
+General Public License.
+
+ "The Library" refers to a covered work governed by this License,
+other than an Application or a Combined Work as defined below.
+
+ An "Application" is any work that makes use of an interface provided
+by the Library, but which is not otherwise based on the Library.
+Defining a subclass of a class defined by the Library is deemed a mode
+of using an interface provided by the Library.
+
+ A "Combined Work" is a work produced by combining or linking an
+Application with the Library. The particular version of the Library
+with which the Combined Work was made is also called the "Linked
+Version".
+
+ The "Minimal Corresponding Source" for a Combined Work means the
+Corresponding Source for the Combined Work, excluding any source code
+for portions of the Combined Work that, considered in isolation, are
+based on the Application, and not on the Linked Version.
+
+ The "Corresponding Application Code" for a Combined Work means the
+object code and/or source code for the Application, including any data
+and utility programs needed for reproducing the Combined Work from the
+Application, but excluding the System Libraries of the Combined Work.
+
+ 1. Exception to Section 3 of the GNU GPL.
+
+ You may convey a covered work under sections 3 and 4 of this License
+without being bound by section 3 of the GNU GPL.
+
+ 2. Conveying Modified Versions.
+
+ If you modify a copy of the Library, and, in your modifications, a
+facility refers to a function or data to be supplied by an Application
+that uses the facility (other than as an argument passed when the
+facility is invoked), then you may convey a copy of the modified
+version:
+
+ a) under this License, provided that you make a good faith effort to
+ ensure that, in the event an Application does not supply the
+ function or data, the facility still operates, and performs
+ whatever part of its purpose remains meaningful, or
+
+ b) under the GNU GPL, with none of the additional permissions of
+ this License applicable to that copy.
+
+ 3. Object Code Incorporating Material from Library Header Files.
+
+ The object code form of an Application may incorporate material from
+a header file that is part of the Library. You may convey such object
+code under terms of your choice, provided that, if the incorporated
+material is not limited to numerical parameters, data structure
+layouts and accessors, or small macros, inline functions and templates
+(ten or fewer lines in length), you do both of the following:
+
+ a) Give prominent notice with each copy of the object code that the
+ Library is used in it and that the Library and its use are
+ covered by this License.
+
+ b) Accompany the object code with a copy of the GNU GPL and this license
+ document.
+
+ 4. Combined Works.
+
+ You may convey a Combined Work under terms of your choice that,
+taken together, effectively do not restrict modification of the
+portions of the Library contained in the Combined Work and reverse
+engineering for debugging such modifications, if you also do each of
+the following:
+
+ a) Give prominent notice with each copy of the Combined Work that
+ the Library is used in it and that the Library and its use are
+ covered by this License.
+
+ b) Accompany the Combined Work with a copy of the GNU GPL and this license
+ document.
+
+ c) For a Combined Work that displays copyright notices during
+ execution, include the copyright notice for the Library among
+ these notices, as well as a reference directing the user to the
+ copies of the GNU GPL and this license document.
+
+ d) Do one of the following:
+
+ 0) Convey the Minimal Corresponding Source under the terms of this
+ License, and the Corresponding Application Code in a form
+ suitable for, and under terms that permit, the user to
+ recombine or relink the Application with a modified version of
+ the Linked Version to produce a modified Combined Work, in the
+ manner specified by section 6 of the GNU GPL for conveying
+ Corresponding Source.
+
+ 1) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (a) uses at run time
+ a copy of the Library already present on the user's computer
+ system, and (b) will operate properly with a modified version
+ of the Library that is interface-compatible with the Linked
+ Version.
+
+ e) Provide Installation Information, but only if you would otherwise
+ be required to provide such information under section 6 of the
+ GNU GPL, and only to the extent that such information is
+ necessary to install and execute a modified version of the
+ Combined Work produced by recombining or relinking the
+ Application with a modified version of the Linked Version. (If
+ you use option 4d0, the Installation Information must accompany
+ the Minimal Corresponding Source and Corresponding Application
+ Code. If you use option 4d1, you must provide the Installation
+ Information in the manner specified by section 6 of the GNU GPL
+ for conveying Corresponding Source.)
+
+ 5. Combined Libraries.
+
+ You may place library facilities that are a work based on the
+Library side by side in a single library together with other library
+facilities that are not Applications and are not covered by this
+License, and convey such a combined library under terms of your
+choice, if you do both of the following:
+
+ a) Accompany the combined library with a copy of the same work based
+ on the Library, uncombined with any other library facilities,
+ conveyed under the terms of this License.
+
+ b) Give prominent notice with the combined library that part of it
+ is a work based on the Library, and explaining where to find the
+ accompanying uncombined form of the same work.
+
+ 6. Revised Versions of the GNU Lesser General Public License.
+
+ The Free Software Foundation may publish revised and/or new versions
+of the GNU Lesser 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
+Library as you received it specifies that a certain numbered version
+of the GNU Lesser General Public License "or any later version"
+applies to it, you have the option of following the terms and
+conditions either of that published version or of any later version
+published by the Free Software Foundation. If the Library as you
+received it does not specify a version number of the GNU Lesser
+General Public License, you may choose any version of the GNU Lesser
+General Public License ever published by the Free Software Foundation.
+
+ If the Library as you received it specifies that a proxy can decide
+whether future versions of the GNU Lesser General Public License shall
+apply, that proxy's public statement of acceptance of any version is
+permanent authorization for you to choose that version for the
+Library.
--- /dev/null
+version: 2
+accept_configuration:
+ condition: property
+ property: features
+ not_contains_value: Disable
+
+instructions:
+ Build:
+ - !include "{{qt/qtbase}}/coin_module_build_template_v2.yaml"
+
+ Test:
+ - !include "{{qt/qtbase}}/coin_module_test_template_v3.yaml"
--- /dev/null
+#############################################################################
+##
+## Copyright (C) 2021 The Qt Company Ltd.
+## Contact: https://www.qt.io/licensing/
+##
+## This file is part of the release tools of the Qt Toolkit.
+##
+## $QT_BEGIN_LICENSE:GPL-EXCEPT$
+## Commercial License Usage
+## Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+## and conditions see https://www.qt.io/terms-conditions. For further
+## information use the contact form at https://www.qt.io/contact-us.
+##
+## 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 with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+## included in the packaging of this file. Please review the following
+## information to ensure the GNU General Public License requirements will
+## be met: https://www.gnu.org/licenses/gpl-3.0.html.
+##
+## $QT_END_LICENSE$
+##
+#############################################################################
+
+from conans import ConanFile
+import re
+from pathlib import Path
+
+
+def _parse_qt_version_by_key(key: str) -> str:
+ with open(Path(__file__).parent.resolve() / ".cmake.conf") as f:
+ m = re.search(fr'{key} .*"(.*)"', f.read())
+ return m.group(1) if m else ""
+
+
+def _get_qt_minor_version() -> str:
+ return ".".join(_parse_qt_version_by_key("QT_REPO_MODULE_VERSION").split(".")[:2])
+
+
+class QtRemoteObjects(ConanFile):
+ name = "qtremoteobjects"
+ license = "LGPL-3.0, GPL-2.0+, Commercial Qt License Agreement"
+ author = "Brett Stottlemyer, Ford Motor Company"
+ url = "https://code.qt.io/cgit/qt/qtremoteobjects.git"
+ description = (
+ "Qt Remote Objects (QtRO) is an Inter-Process Communication (IPC) module developed for Qt. "
+ "This module extends Qt's existing functionalities to enable information exchange between "
+ "processes or computers, easily."
+ )
+ topics = "qt", "qt6", "QtRO", "IPC"
+ settings = "os", "compiler", "arch", "build_type"
+ # for referencing the version number and prerelease tag and dependencies info
+ exports = ".cmake.conf", "dependencies.yaml"
+ exports_sources = "*", "!conan*.*"
+ python_requires = f"qt-conan-common/{_get_qt_minor_version()}@qt/everywhere"
+ python_requires_extend = "qt-conan-common.QtLeafModule"
--- /dev/null
+dependencies:
+ ../qtbase:
+ ref: d3b5353380797f3b67599ccebc5dc916057681e5
+ required: true
+ ../qtdeclarative:
+ ref: 26140891b4b77e2e8292f75e9d20f5798a2bd247
+ required: false
--- /dev/null
+Qt 5.11 introduces many new features and improvements as well as bugfixes
+over the 5.10.x series. For more details, refer to the online documentation
+included in this distribution. The documentation is also available online:
+
+http://doc.qt.io/qt-5/index.html
+
+Note: Tech Preview modules are able to change APIs to refine or enhance the
+module's functionality. Thus Qt's binary compatibility quarantees aren't
+applicable. Code switching to 5.11.0 from earlier versions of Qt Remote
+Objects will need to be recompiled.
+
+Some of the changes listed in this file include issue tracking numbers
+corresponding to tasks in the Qt Bug Tracker:
+
+https://bugreports.qt.io/
+
+Each of these identifiers can be entered in the bug tracker to obtain more
+information about a particular change.
+
+****************************************************************************
+* Qt 5.11.0 Changes *
+****************************************************************************
+
+ - QRemoteObjectNode
+ * [QTBUG-64086] Added heartbeatInterval property, which can be used to
+ periodically check the connection between replica and source. If the
+ connection is lost, the replica enters the "Suspect" state and will
+ attempt to reconnect.
+ * Extended acquireModel to allow prefetching data.
+
+ - QRemoteObjectAbstractPersistedStore
+ * Renamed from QRemoteObjectPersistedStore, and made a QObject to allow
+ use from QML.
+ * Added QRemoteObjectSettingsStore (SettingsStore in QML) as a concrete
+ implementation using QSettings.
+
+ - repc
+ * Added support for nested classes, via an extension to the .rep file
+ format. The syntax is `CLASS <name>(<type>), where type needs to be a
+ class defined in the same rep file, and name is the property name
+ used to access the sub-QObject.
--- /dev/null
+Qt 5.11.1 is a bug-fix release. It maintains both forward and backward
+compatibility (source and binary) with Qt 5.11.0.
+
+For more details, refer to the online documentation included in this
+distribution. The documentation is also available online:
+
+http://doc.qt.io/qt-5/index.html
+
+Note: Tech Preview modules are able to change APIs to refine or enhance the
+module's functionality. Thus Qt's binary compatibility quarantees aren't
+applicable. Code switching to 5.11.0 from earlier versions of Qt Remote
+Objects will need to be recompiled.
+
+Some of the changes listed in this file include issue tracking numbers
+corresponding to tasks in the Qt Bug Tracker:
+
+https://bugreports.qt.io/
+
+Each of these identifiers can be entered in the bug tracker to obtain more
+information about a particular change.
+
+****************************************************************************
+* Qt 5.11.1 Changes *
+****************************************************************************
+
+ - This release contains several fixes for MODEL/SUBCLASS handling and tests.
--- /dev/null
+Qt 5.11.2 is a bug-fix release. It maintains both forward and backward
+compatibility (source and binary) with Qt 5.11.0 through 5.11.1.
+
+For more details, refer to the online documentation included in this
+distribution. The documentation is also available online:
+
+http://doc.qt.io/qt-5/index.html
+
+The Qt version 5.11 series is binary compatible with the 5.10.x series.
+Applications compiled for 5.10 will continue to run with 5.11.
+
+Some of the changes listed in this file include issue tracking numbers
+corresponding to tasks in the Qt Bug Tracker:
+
+https://bugreports.qt.io/
+
+Each of these identifiers can be entered in the bug tracker to obtain more
+information about a particular change.
+
+****************************************************************************
+* Qt 5.11.2 Changes *
+****************************************************************************
+
+ - This release contains only minor code improvements.
--- /dev/null
+Qt 5.11.3 is a bug-fix release. It maintains both forward and backward
+compatibility (source and binary) with Qt 5.11.0 through 5.11.2.
+
+For more details, refer to the online documentation included in this
+distribution. The documentation is also available online:
+
+http://doc.qt.io/qt-5/index.html
+
+Note: Tech Preview modules are able to change APIs to refine or enhance the
+module's functionality. Thus Qt's binary compatibility quarantees aren't
+applicable. Code switching to 5.11.0 from earlier versions of Qt Remote
+Objects will need to be recompiled.
+
+Some of the changes listed in this file include issue tracking numbers
+corresponding to tasks in the Qt Bug Tracker:
+
+https://bugreports.qt.io/
+
+Each of these identifiers can be entered in the bug tracker to obtain more
+information about a particular change.
+
+****************************************************************************
+* Qt 5.11.3 Changes *
+****************************************************************************
+
+ - QRemoteObjectNode
+ * Fix a constant reconnect issue
--- /dev/null
+Qt 5.12 introduces many new features and improvements as well as bugfixes
+over the 5.11.x series. For more details, refer to the online documentation
+included in this distribution. The documentation is also available online:
+
+https://doc.qt.io/qt-5/index.html
+
+Note: Tech Preview modules are able to change APIs to refine or enhance the
+module's functionality. Thus Qt's binary compatibility quarantees aren't
+applicable. Code switching to 5.12.0 from earlier versions of Qt Remote
+Objects will need to be recompiled.
+
+Some of the changes listed in this file include issue tracking numbers
+corresponding to tasks in the Qt Bug Tracker:
+
+https://bugreports.qt.io/
+
+Each of these identifiers can be entered in the bug tracker to obtain more
+information about a particular change.
+
+****************************************************************************
+* Qt 5.12.0 Changes *
+****************************************************************************
+ - General
+ * [QTBUG-68678] Graduate Qt Remote Objects from TP to fully supported
+ module of Qt
+ * [QTBUG-65727] QtRemoteObjects: Documentation doesn't match the code
+
+ - QRemoteObjectNode
+ * Support externally created QIODevices, including SSL sockets.
+ * Added proxy() method to support use-cases like having a single node
+ provide a (for instance) tcp url for a device allowing access from
+ other devices, while using internal connections (like "local:*") on
+ the device.
+
+ - repc
+ * [QTBUG-68976] Cannot add comments in .rep file
+ * [QTBUG-68975] Support multiline PODs and ENUMs in repc
+ * [QTBUG-67770] repc should be able to use tab characters as a normal
+ whitespace
+
+****************************************************************************
+* QML *
+****************************************************************************
+
+ - Updated import statement to better match typical module pattern. From
+ QML "import QtRemoteObjects 5.12" should now be used.
--- /dev/null
+Qt 5.12.1 is a bug-fix release. It maintains both forward and backward
+compatibility (source and binary) with Qt 5.12.0.
+
+For more details, refer to the online documentation included in this
+distribution. The documentation is also available online:
+
+http://doc.qt.io/qt-5/index.html
+
+Note: Tech Preview modules are able to change APIs to refine or enhance the
+module's functionality. Thus Qt's binary compatibility quarantees aren't
+applicable. Code switching to 5.12 (when Remote Objects "graduated" from
+Tech Preview) from earlier versions of Qt Remote Objects will need to be
+recompiled.
+
+Some of the changes listed in this file include issue tracking numbers
+corresponding to tasks in the Qt Bug Tracker:
+
+https://bugreports.qt.io/
+
+Each of these identifiers can be entered in the bug tracker to obtain more
+information about a particular change.
+
+****************************************************************************
+* Qt 5.12.1 Changes *
+****************************************************************************
+ - General
+ * [QTBUG-72064] QVariant is also a standalone type and we must treat it
+ accordingly
+ * Convert QNX backend to use shared pointers
+ * Various code cleanup
--- /dev/null
+Qt 5.12.2 is a bug-fix release. It maintains both forward and backward
+compatibility (source and binary) with Qt 5.12.0 through 5.12.1.
+
+For more details, refer to the online documentation included in this
+distribution. The documentation is also available online:
+
+https://doc.qt.io/qt-5/index.html
+
+The Qt version 5.12 series is binary compatible with the 5.11.x series.
+Applications compiled for 5.11 will continue to run with 5.12.
+
+Some of the changes listed in this file include issue tracking numbers
+corresponding to tasks in the Qt Bug Tracker:
+
+https://bugreports.qt.io/
+
+Each of these identifiers can be entered in the bug tracker to obtain more
+information about a particular change.
+
+ - This release contains only minor code improvements.
--- /dev/null
+Qt 5.12.3 is a bug-fix release. It maintains both forward and backward
+compatibility (source and binary) with Qt 5.12.0 through 5.12.2.
+
+For more details, refer to the online documentation included in this
+distribution. The documentation is also available online:
+
+https://doc.qt.io/qt-5/index.html
+
+Note: Tech Preview modules are able to change APIs to refine or enhance the
+module's functionality. Thus Qt's binary compatibility quarantees aren't
+applicable. Code switching to 5.12 (when Remote Objects "graduated" from
+Tech Preview) from earlier versions of Qt Remote Objects will need to be
+recompiled.
+
+Some of the changes listed in this file include issue tracking numbers
+corresponding to tasks in the Qt Bug Tracker:
+
+https://bugreports.qt.io/
+
+Each of these identifiers can be entered in the bug tracker to obtain more
+information about a particular change.
+
+****************************************************************************
+* Qt 5.12.1 Changes *
+****************************************************************************
+ - General
+ * [QTBUG-74221] Fix restart/nullptr crash
+ * [QTBUG-73962] Fix crash with AllowExternalRegistration and QtRO schema
+ * Doc: Add link from index page to QML Types
--- /dev/null
+Qt 5.12.4 is a bug-fix release. It maintains both forward and backward
+compatibility (source and binary) with Qt 5.12.0 through 5.12.3 under most
+conditions. There may be exceptions if you are using Qt Remote Objects
+between proesses or devices running different versions Qt. The different
+versions of Qt must be running compatible versions of QtRO's protocol.
+
+Changes to the Qt Remote Objects protocol are documented online:
+
+https://doc.qt.io/qt-5/qtremoteobjects-compatibility.html
+
+The QtRO protocol has been updated in Qt 5.12.4 and Qt 5.13.0 to 1.3.
+
+Background: Qt's QueuedConnections work by copying signal parameters so
+the copy can be held and then later processed in another threads
+eventloop, allowing the original data to be changed in the originating
+thread.
+
+Qt Remote Objects leverages this capability and sends that data from a
+QObject in one process to a QObject in another. There is a specific
+protocol for this, as both sides need to interpret what is sent the
+same way. For example, there are Invoke and PropertyChanged packets
+exchanged. In addition to this, both sides need to know how to encode and
+decode all types shared. This type awareness is easy to ensure if the
+repc compiler is used to generate the headers for all sides.
+
+However, there are use cases where this isn't possible. In these cases
+QtRO will send the type (metaobject) information as well, allowing the
+receiving side to generate the required type information at runtime for
+certain types (PODs and enumerations).
+
+There were issues found in this type serialization code that required a
+change to the protocol. There are a number of commits going into both
+Qt 5.13.0 and Qt 5.12.4 with fixes. This means that you will not be able
+to use Qt Remote Objects on a device using Qt 5.12.3 or earlier and
+communicate to another device using Qt 5.12.4/5.13.0.
+
+For more details, refer to the online documentation included in this
+distribution. The documentation is also available online:
+
+https://doc.qt.io/qt-5/index.html
+
+The Qt version 5.12 series is binary compatible with the 5.11.x series.
+Applications compiled for 5.11 will continue to run with 5.12 as long as
+the protocol change noted above is taken into account.
+
+****************************************************************************
+* Important Behavior Changes *
+****************************************************************************
+
+ - Qt Remote Objects uses an internal protocol to pass data between
+ processes and/or devices. The same protocol version needs to be used on
+ all sides. The version was bumped from 1.2 to 1.3 in this release,
+ fixing potential crashes (see QTBUG-75017). If there is a mismatch, the
+ connecting node will output a warning and the host node will not send
+ any data.
+
+Some of the changes listed in this file include issue tracking numbers
+corresponding to tasks in the Qt Bug Tracker:
+
+https://bugreports.qt.io/
+
+The following fixes were part of the above protocol change and are in
+5.12.4 and 5.13.0.
+
+Each of these identifiers can be entered in the bug tracker to obtain more
+information about a particular change.
+
+ - QTBUG-75017: QtRO processes can crash if type registration is incorrect
+ - QTBUG-75056: Correctly handle QVariant properties on the replica side
+ - QTBUG-74084: QT remote objects false conversion warning in case of
+ QVariant property
--- /dev/null
+Qt 5.12.5 is a bug-fix release. It maintains both forward and backward
+compatibility (source and binary) with Qt 5.12.0 through 5.12.4.
+
+For more details, refer to the online documentation included in this
+distribution. The documentation is also available online:
+
+https://doc.qt.io/qt-5/index.html
+
+The Qt version 5.12 series is binary compatible with the 5.11.x series.
+Applications compiled for 5.11 will continue to run with 5.12.
+
+Some of the changes listed in this file include issue tracking numbers
+corresponding to tasks in the Qt Bug Tracker:
+
+https://bugreports.qt.io/
+
+Each of these identifiers can be entered in the bug tracker to obtain more
+information about a particular change.
+
+ - This release contains only minor code improvements.
--- /dev/null
+Qt 5.13 introduces many new features and improvements as well as bugfixes
+over the 5.12.x series. For more details, refer to the online documentation
+included in this distribution. The documentation is also available online:
+
+https://doc.qt.io/qt-5/index.html
+
+The Qt version 5.13 series is binary compatible with the 5.12.x series.
+Applications compiled for 5.12 will continue to run with 5.13 under most
+conditions. There may be exceptions if you are using Qt Remote Objects
+between proesses or devices running different versions Qt. The different
+versions of Qt must be running compatible versions of QtRO's protocol.
+
+Changes to the Qt Remote Objects protocol are documented online:
+
+https://doc.qt.io/qt-5/qtremoteobjects-compatibility.html
+
+The QtRO protocol has been updated in Qt 5.12.4 and Qt 5.13.0 to 1.3.
+
+Background: Qt's QueuedConnections work by copying signal parameters so
+the copy can be held and then later processed in another threads
+eventloop, allowing the original data to be changed in the originating
+thread.
+
+Qt Remote Objects leverages this capability and sends that data from a
+QObject in one process to a QObject in another. There is a specific
+protocol for this, as both sides need to interpret what is sent the
+same way. For example, there are Invoke and PropertyChanged packets
+exchanged. In addition to this, both sides need to know how to encode and
+decode all types shared. This type awareness is easy to ensure if the
+repc compiler is used to generate the headers for all sides.
+
+However, there are use cases where this isn't possible. In these cases
+QtRO will send the type (metaobject) information as well, allowing the
+receiving side to generate the required type information at runtime for
+certain types (PODs and enumerations).
+
+There were issues found in this type serialization code that required a
+change to the protocol. There are a number of commits going into both
+Qt 5.13.0 and Qt 5.12.4 with fixes. This means that you will not be able
+to use Qt Remote Objects on a device using Qt 5.12.3 or earlier and
+communicate to another device using Qt 5.12.4/5.13.0.
+
+Some of the changes listed in this file include issue tracking numbers
+corresponding to tasks in the Qt Bug Tracker:
+
+https://bugreports.qt.io/
+
+The following fixes were part of the above protocol change and are in
+5.12.4 and 5.13.0.
+
+Each of these identifiers can be entered in the bug tracker to obtain more
+information about a particular change.
+
+ - QTBUG-75017: QtRO processes can crash if type registration is incorrect
+ - QTBUG-75056: Correctly handle QVariant properties on the replica side
+ - QTBUG-74084: QT remote objects false conversion warning in case of
+ QVariant property
--- /dev/null
+Qt 5.13.1 is a bug-fix release. It maintains both forward and backward
+compatibility (source and binary) with Qt 5.13.0.
+
+For more details, refer to the online documentation included in this
+distribution. The documentation is also available online:
+
+https://doc.qt.io/qt-5/index.html
+
+The Qt version 5.13 series is binary compatible with the 5.12.x series.
+Applications compiled for 5.12 will continue to run with 5.13.
+
+Some of the changes listed in this file include issue tracking numbers
+corresponding to tasks in the Qt Bug Tracker:
+
+https://bugreports.qt.io/
+
+Each of these identifiers can be entered in the bug tracker to obtain more
+information about a particular change.
+
+ - Improved clarity and consistency of documentation.
+ - Made a number of fixes and improvements in the handling of enumerations.
--- /dev/null
+Qt 5.13.2 is a bug-fix release. It maintains both forward and backward
+compatibility (source and binary) with Qt 5.13.0 through 5.13.1.
+
+For more details, refer to the online documentation included in this
+distribution. The documentation is also available online:
+
+https://doc.qt.io/qt-5/index.html
+
+The Qt version 5.13 series is binary compatible with the 5.12.x series.
+Applications compiled for 5.12 will continue to run with 5.13 under most
+conditions. There may be exceptions if you are using Qt Remote Objects
+between proesses or devices running different versions Qt. The different
+versions of Qt must be running compatible versions of QtRO's protocol.
+
+Changes to the Qt Remote Objects protocol are documented online:
+
+https://doc.qt.io/qt-5/qtremoteobjects-compatibility.html
+
+The QtRO protocol has been updated in Qt 5.12.4 and Qt 5.13.0 to 1.3.
+
+Some of the changes listed in this file include issue tracking numbers
+corresponding to tasks in the Qt Bug Tracker:
+
+https://bugreports.qt.io/
+
+Each of these identifiers can be entered in the bug tracker to obtain more
+information about a particular change.
+
+ - This release contains only minor code improvements and some improvements
+ to the documentation.
--- /dev/null
+Qt 5.14 introduces many new features and improvements as well as bugfixes
+over the 5.13.x series. For more details, refer to the online documentation
+included in this distribution. The documentation is also available online:
+
+https://doc.qt.io/qt-5/index.html
+
+The Qt version 5.14 series is binary compatible with the 5.13.x series.
+Applications compiled for 5.13 will continue to run with 5.14.
+
+If you are using Qt Remote Objects between proesses or devices running
+different versions Qt, the different versions of Qt must be running
+compatible versions of QtRO's protocol. Changes to the Qt Remote Objects
+protocol are documented online:
+
+https://doc.qt.io/qt-5/qtremoteobjects-compatibility.html
+
+Some of the changes listed in this file include issue tracking numbers
+corresponding to tasks in the Qt Bug Tracker:
+
+https://bugreports.qt.io/
+
+Each of these identifiers can be entered in the bug tracker to obtain more
+information about a particular change.
+
+ - QTBUG-77178 Support SLOTs with return values in QML
--- /dev/null
+Qt 5.14.1 is a bug-fix release. It maintains both forward and backward
+compatibility (source and binary) with Qt 5.14.0.
+
+For more details, refer to the online documentation included in this
+distribution. The documentation is also available online:
+
+https://doc.qt.io/qt-5/index.html
+
+The Qt version 5.14 series is binary compatible with the 5.13.x series.
+Applications compiled for 5.13 will continue to run with 5.14.
+
+If you are using Qt Remote Objects between processes or devices running
+different versions Qt, the different versions of Qt must be running
+compatible versions of QtRO's protocol. Changes to the Qt Remote Objects
+protocol are documented online:
+
+https://doc.qt.io/qt-5/qtremoteobjects-compatibility.html
+
+Some of the changes listed in this file include issue tracking numbers
+corresponding to tasks in the Qt Bug Tracker:
+
+https://bugreports.qt.io/
+
+Each of these identifiers can be entered in the bug tracker to obtain more
+information about a particular change.
+
+ - This release contains only minor code improvements.
--- /dev/null
+Qt 5.14.2 is a bug-fix release. It maintains both forward and backward
+compatibility (source and binary) with Qt 5.14.0 through 5.14.1.
+
+For more details, refer to the online documentation included in this
+distribution. The documentation is also available online:
+
+https://doc.qt.io/qt-5/index.html
+
+The Qt version 5.14 series is binary compatible with the 5.13.x series.
+Applications compiled for 5.13 will continue to run with 5.14.
+
+If you are using Qt Remote Objects between processes or devices running
+different versions Qt, the different versions of Qt must be running
+compatible versions of QtRO's protocol. Changes to the Qt Remote Objects
+protocol are documented online:
+
+https://doc.qt.io/qt-5/qtremoteobjects-compatibility.html
+
+Some of the changes listed in this file include issue tracking numbers
+corresponding to tasks in the Qt Bug Tracker:
+
+https://bugreports.qt.io/
+
+Each of these identifiers can be entered in the bug tracker to obtain more
+information about a particular change.
+
+ - This release contains only minor code improvements.
--- /dev/null
+Qt 5.15 introduces many new features and improvements as well as bugfixes
+over the 5.14.x series. For more details, refer to the online documentation
+included in this distribution. The documentation is also available online:
+
+https://doc.qt.io/qt-5/index.html
+
+The Qt version 5.15 series is binary compatible with the 5.14.x series.
+Applications compiled for 5.14 will continue to run with 5.15.
+
+Some of the changes listed in this file include issue tracking numbers
+corresponding to tasks in the Qt Bug Tracker:
+
+https://bugreports.qt.io/
+
+Each of these identifiers can be entered in the bug tracker to obtain more
+information about a particular change.
+
+****************************************************************************
+* QML *
+****************************************************************************
+
+ - Exposed Host to enable remoting of source objects from QML.
--- /dev/null
+Qt 5.15.1 is a bug-fix release. It maintains both forward and backward
+compatibility (source and binary) with Qt 5.15.0.
+
+For more details, refer to the online documentation included in this
+distribution. The documentation is also available online:
+
+https://doc.qt.io/qt-5/index.html
+
+The Qt version 5.15 series is binary compatible with the 5.14.x series.
+Applications compiled for 5.14 will continue to run with 5.15.
+
+Some of the changes listed in this file include issue tracking numbers
+corresponding to tasks in the Qt Bug Tracker:
+
+https://bugreports.qt.io/
+
+Each of these identifiers can be entered in the bug tracker to obtain more
+information about a particular change.
+
+ - This release contains only minor code improvements.
--- /dev/null
+# Generated from examples.pro.
+
+qt_examples_build_begin(EXTERNAL_BUILD)
+
+add_subdirectory(remoteobjects)
+
+qt_examples_build_end()
--- /dev/null
+TEMPLATE = subdirs
+SUBDIRS = \
+ remoteobjects
--- /dev/null
+# Generated from remoteobjects.pro.
+
+add_subdirectory(server)
+add_subdirectory(cppclient)
+add_subdirectory(simpleswitch)
+add_subdirectory(websockets)
+if(TARGET Qt::Widgets)
+ add_subdirectory(modelviewclient)
+ add_subdirectory(modelviewserver)
+endif()
+if(QT_CONFIG___contains___ssl)
+ add_subdirectory(ssl)
+endif()
+if(TARGET Qt::Quick)
+ add_subdirectory(plugins)
+ add_subdirectory(clientapp)
+endif()
+if(TARGET Qt::Quick AND UNIX AND NOT ANDROID)
+ add_subdirectory(qmlmodelviewclient)
+endif()
--- /dev/null
+# Generated from remoteobjects.pro.
+
+qt_internal_add_example(remoteobjects_server)
+qt_internal_add_example(cppclient)
+add_subdirectory(simpleswitch)
+add_subdirectory(websockets)
+if(TARGET Qt::Widgets)
+ qt_internal_add_example(modelviewclient)
+ qt_internal_add_example(modelviewserver)
+endif()
+if(QT_FEATURE_ssl) # special case
+ add_subdirectory(ssl)
+endif()
+if(TARGET Qt::Quick)
+ qt_internal_add_example(plugins)
+ qt_internal_add_example(clientapp)
+endif()
+if(TARGET Qt::Quick AND UNIX AND NOT ANDROID)
+ qt_internal_add_example(qmlmodelviewclient)
+endif()
--- /dev/null
+# Generated from clientapp.pro.
+
+cmake_minimum_required(VERSION 3.16)
+project(clientapp LANGUAGES CXX)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(CMAKE_AUTOMOC ON)
+set(CMAKE_AUTORCC ON)
+set(CMAKE_AUTOUIC ON)
+
+if(NOT DEFINED INSTALL_EXAMPLESDIR)
+ set(INSTALL_EXAMPLESDIR "examples")
+endif()
+
+set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/remoteobjects/clientapp")
+
+find_package(Qt6 COMPONENTS Core)
+find_package(Qt6 COMPONENTS Gui)
+find_package(Qt6 COMPONENTS RemoteObjects)
+find_package(Qt6 COMPONENTS Quick)
+
+qt_add_executable(clientapp
+ main.cpp
+)
+set_target_properties(clientapp PROPERTIES
+ WIN32_EXECUTABLE TRUE
+ MACOSX_BUNDLE TRUE
+)
+target_link_libraries(clientapp PUBLIC
+ Qt::Core
+ Qt::Gui
+ Qt::Quick
+ Qt::RemoteObjects
+)
+
+
+# Resources:
+set(clientapp_resource_files
+ "qml/plugins.qml"
+ "qml/plugins0.qml"
+ "qml/plugins1.qml"
+ "qml/plugins2.qml"
+)
+
+qt6_add_resources(clientapp "clientapp"
+ PREFIX
+ "/qml"
+ FILES
+ ${clientapp_resource_files}
+)
+
+install(TARGETS clientapp
+ RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
+ BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
+ LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
+)
--- /dev/null
+SOURCES += main.cpp
+
+RESOURCES += \
+ clientapp.qrc
+
+QT += remoteobjects quick
+
+contains(QT_CONFIG, c++11): CONFIG += c++11
+
+target.path = $$[QT_INSTALL_EXAMPLES]/remoteobjects/clientapp
+INSTALLS += target
--- /dev/null
+<RCC>
+ <qresource prefix="/qml">
+ <file>qml/plugins0.qml</file>
+ <file>qml/plugins.qml</file>
+ <file>qml/plugins1.qml</file>
+ <file>qml/plugins2.qml</file>
+ </qresource>
+</RCC>
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtGui/QGuiApplication>
+#include <QtQml/QQmlEngine>
+#include <QtQuick/QQuickView>
+
+int main(int argc, char *argv[])
+{
+ QGuiApplication app(argc, argv);
+
+ QQuickView viewer;
+ viewer.engine()->addImportPath(QStringLiteral("qrc:/qml"));
+ viewer.setSource(QUrl(QStringLiteral("qrc:/qml/qml/plugins.qml")));
+ viewer.show();
+
+ return app.exec();
+}
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+
+Item {
+ width: 200
+ height: 400
+ property int counter: 0;
+ MouseArea {
+ anchors.fill: parent
+ onClicked:
+ {
+ counter = (counter + 1) % 3;
+ console.log(counter);
+ pageLoader.source = "plugins"+counter+".qml"
+ }
+ }
+ Loader {
+ id: pageLoader
+ source: "plugins0.qml"
+ }
+}
+//![0]
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+//![0]
+import QtQuick 2.0
+
+Rectangle {
+ width: 200
+ height: 400
+ color: "blue"
+}
+//![0]
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+//![0]
+import QtQuick 2.0
+import TimeExample 1.0 // import types from the plugin
+
+Rectangle {
+ width: 200
+ height: 400
+ color: "blue"
+ Clock { // this class is defined in QML (imports/TimeExample/Clock.qml)
+ id: clock1
+ anchors.top: parent.top
+ Time { // this class is defined in C++ (plugin.cpp)
+ id: time
+ }
+
+ hours: time.hour
+ minutes: time.minute
+
+ }
+}
+//![0]
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+//![0]
+import QtQuick 2.0
+import TimeExample 1.0 // import types from the plugin
+
+Rectangle {
+ width: 200
+ height: 400
+ Clock { // this class is defined in QML (imports/TimeExample/Clock.qml)
+ id: clock1
+ anchors.top: parent.top
+ Time { // this class is defined in C++ (plugin.cpp)
+ id: time
+ }
+
+ hours: time.hour
+ minutes: time.minute
+
+ }
+ Clock { // this class is defined in QML (imports/TimeExample/Clock.qml)
+ id: clock2
+ anchors.top: clock1.bottom
+ Time { // this class is defined in C++ (plugin.cpp)
+ id: time2
+ }
+
+ hours: time2.hour
+ minutes: time2.minute
+
+ }
+
+}
+//![0]
--- /dev/null
+# Generated from cppclient.pro.
+
+cmake_minimum_required(VERSION 3.16)
+project(CppClient LANGUAGES CXX)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(CMAKE_AUTOMOC ON)
+set(CMAKE_AUTORCC ON)
+set(CMAKE_AUTOUIC ON)
+
+if(NOT DEFINED INSTALL_EXAMPLESDIR)
+ set(INSTALL_EXAMPLESDIR "examples")
+endif()
+
+set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/remoteobjects/cppclient")
+
+find_package(Qt6 COMPONENTS Core)
+find_package(Qt6 COMPONENTS RemoteObjects)
+
+qt_add_executable(CppClient
+ main.cpp
+)
+set_target_properties(CppClient PROPERTIES
+ WIN32_EXECUTABLE TRUE
+ MACOSX_BUNDLE FALSE
+)
+target_link_libraries(CppClient PUBLIC
+ Qt::Core
+ Qt::RemoteObjects
+)
+
+qt6_add_repc_replicas(CppClient
+ timemodel.rep
+)
+
+install(TARGETS CppClient
+ RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
+ BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
+ LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
+)
--- /dev/null
+QT += core
+
+REPC_REPLICA += timemodel.rep
+QT += remoteobjects
+
+QT -= gui
+
+TARGET = CppClient
+CONFIG -= app_bundle
+
+TEMPLATE = app
+
+SOURCES += main.cpp
+
+OTHER_FILES += \
+ timemodel.rep
+
+target.path = $$[QT_INSTALL_EXAMPLES]/remoteobjects/cppclient
+INSTALLS += target
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QCoreApplication>
+#include <QTimer>
+#include "rep_timemodel_replica.h"
+
+class tester : public QObject
+{
+ Q_OBJECT
+public:
+ tester() : QObject(nullptr)
+ {
+ QRemoteObjectNode m_client(QUrl(QStringLiteral("local:registry")));
+ ptr1.reset(m_client.acquire< MinuteTimerReplica >());
+ ptr2.reset(m_client.acquire< MinuteTimerReplica >());
+ ptr3.reset(m_client.acquire< MinuteTimerReplica >());
+ QTimer::singleShot(0, this, &tester::clear);
+ QTimer::singleShot(1, this, &tester::clear);
+ QTimer::singleShot(10000, this, &tester::clear);
+ QTimer::singleShot(11000, this, &tester::clear);
+ }
+public slots:
+ void clear()
+ {
+ static int i = 0;
+ if (i == 0) {
+ i++;
+ ptr1.reset();
+ } else if (i == 1) {
+ i++;
+ ptr2.reset();
+ } else if (i == 2) {
+ i++;
+ ptr3.reset();
+ } else {
+ qApp->quit();
+ }
+ }
+
+private:
+ QScopedPointer<MinuteTimerReplica> ptr1, ptr2, ptr3;
+};
+
+int main(int argc, char *argv[])
+{
+ QCoreApplication a(argc, argv);
+ tester t;
+ return a.exec();
+}
+
+#include "main.moc"
--- /dev/null
+#include <QtCore>
+
+POD PresetInfo(int presetNumber, float frequency, QString stationName)
+class MinuteTimer
+{
+ PROP(int hour=1);
+ PROP(int minute=51);
+ SIGNAL(timeChanged());
+ SIGNAL(timeChanged2(QTime t));
+ SIGNAL(sendCustom(PresetInfo info));
+ SLOT(void SetTimeZone(int zn));
+};
--- /dev/null
+# Generated from modelviewclient.pro.
+
+cmake_minimum_required(VERSION 3.16)
+project(modelviewclient LANGUAGES CXX)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(CMAKE_AUTOMOC ON)
+set(CMAKE_AUTORCC ON)
+set(CMAKE_AUTOUIC ON)
+
+if(NOT DEFINED INSTALL_EXAMPLESDIR)
+ set(INSTALL_EXAMPLESDIR "examples")
+endif()
+
+set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/remoteobjects/modelviewclient")
+
+find_package(Qt6 COMPONENTS Core)
+find_package(Qt6 COMPONENTS Gui)
+find_package(Qt6 COMPONENTS Widgets)
+find_package(Qt6 COMPONENTS RemoteObjects)
+
+qt_add_executable(modelviewclient
+ main.cpp
+)
+set_target_properties(modelviewclient PROPERTIES
+ WIN32_EXECUTABLE TRUE
+ MACOSX_BUNDLE FALSE
+)
+target_link_libraries(modelviewclient PUBLIC
+ Qt::Core
+ Qt::Gui
+ Qt::RemoteObjects
+ Qt::Widgets
+)
+
+install(TARGETS modelviewclient
+ RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
+ BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
+ LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
+)
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \example modelviewclient
+ \title Model-View Client
+
+ This is the client-side application that accompanies the
+ \l {Model-View Server}.
+
+ This example showcases how to make a very simple client program which
+ displays the content and changes made on a server.
+
+ \snippet modelviewclient/main.cpp ObjectNode creation
+
+ We start by creating a QRemoteObjectNode and connecting it to a registry
+ found on the local machine. We also set a
+ \l{QRemoteObjectNode::heartbeatInterval}{heartbeat interval}.
+ The heartbeat is useful to detect if the connection to the \l{Source} has
+ been disrupted. In this case, since all the traffic is local, it would
+ detect when the server has been closed.
+
+ \snippet modelviewclient/main.cpp Model acquisition
+
+ We then \l {QRemoteObjectNode::acquireModel}{acquire} the model which
+ contains all of our data. In this case, we're looking to acquire a model
+ named \c{RemoteModel} from the remote object network we are connected to.
+
+ \snippet modelviewclient/main.cpp QTreeView-creation
+
+ And finally, we display the model in a very basic application.
+*/
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QTreeView>
+#include <QApplication>
+#include <QRemoteObjectNode>
+#include <QAbstractItemModelReplica>
+
+int main(int argc, char **argv)
+{
+
+ QLoggingCategory::setFilterRules("qt.remoteobjects.debug=false\n"
+ "qt.remoteobjects.warning=false\n"
+ "qt.remoteobjects.models.debug=false\n"
+ "qt.remoteobjects.models.debug=false");
+
+ QApplication app(argc, argv);
+
+//! [ObjectNode creation]
+ QRemoteObjectNode node(QUrl(QStringLiteral("local:registry")));
+ node.setHeartbeatInterval(1000);
+//! [ObjectNode creation]
+//! [Model acquisition]
+ QScopedPointer<QAbstractItemModelReplica> model(node.acquireModel(QStringLiteral("RemoteModel")));
+//! [Model acquisition]
+
+//! [QTreeView-creation]
+ QTreeView view;
+ view.setWindowTitle(QStringLiteral("RemoteView"));
+ view.resize(640,480);
+ view.setModel(model.data());
+ view.show();
+//! [QTreeView-creation]
+
+ return app.exec();
+}
--- /dev/null
+SOURCES = main.cpp
+
+CONFIG -= app_bundle
+
+# install
+target.path = $$[QT_INSTALL_EXAMPLES]/remoteobjects/modelviewclient
+INSTALLS += target
+
+QT += widgets remoteobjects
+requires(qtConfig(treeview))
--- /dev/null
+# Generated from modelviewserver.pro.
+
+cmake_minimum_required(VERSION 3.16)
+project(modelviewserver LANGUAGES CXX)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(CMAKE_AUTOMOC ON)
+set(CMAKE_AUTORCC ON)
+set(CMAKE_AUTOUIC ON)
+
+if(NOT DEFINED INSTALL_EXAMPLESDIR)
+ set(INSTALL_EXAMPLESDIR "examples")
+endif()
+
+set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/remoteobjects/modelviewserver")
+
+find_package(Qt6 COMPONENTS Core)
+find_package(Qt6 COMPONENTS Gui)
+find_package(Qt6 COMPONENTS Widgets)
+find_package(Qt6 COMPONENTS RemoteObjects)
+
+qt_add_executable(modelviewserver
+ main.cpp
+)
+set_target_properties(modelviewserver PROPERTIES
+ WIN32_EXECUTABLE TRUE
+ MACOSX_BUNDLE TRUE
+)
+target_link_libraries(modelviewserver PUBLIC
+ Qt::Core
+ Qt::Gui
+ Qt::RemoteObjects
+ Qt::Widgets
+)
+
+install(TARGETS modelviewserver
+ RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
+ BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
+ LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
+)
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \example modelviewserver
+ \title Model-View Server
+
+ This is the server-side application that accompanies the
+ \l {Model-View Client}.
+
+ This example showcases how to make a simple server program that displays
+ and makes changes to a QTreeView which is made available on a Remote
+ Objects network.
+
+ \snippet modelviewserver/main.cpp RegistryHost setup
+
+ We start by creating a QRemoteObjectRegistryHost with which other
+ Remote Objects will connect, be registered and then be advertised by.
+ The model we create can then be easily acquired from the client side by just
+ connecting to the registry.
+
+ \snippet modelviewserver/main.cpp Model-creation and role-selection
+
+ Now we have to create the model we need. The exact implementation is
+ available in the source code, to which you can navigate by pressing the
+ link further down on this page. We also define which \e roles we want to
+ expose to the \l{Replica} on the client side.
+
+ \snippet modelviewserver/main.cpp Model-remoting
+
+ Here, we create the QRemoteObjectHost that connects to, and shares all its
+ Remote Objects with, the Registry we created earlier. We then start remoting
+ the model we just created with the name \c{RemoteModel}. We also pass the
+ \e roles argument here.
+
+ \snippet modelviewserver/main.cpp TreeView-creation
+
+ We then display the model with a QTreeView widget.
+
+ \snippet modelviewserver/main.cpp Automated actions
+
+ For the sake of keeping the example light-weight it performs some
+ automated actions to affect the model shortly after the server application
+ launches. These changes can then be seen on both the server and client side.
+ You can also change the text in the fields on the server side and see it
+ update on the client side.
+*/
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include <QTreeView>
+#include <QApplication>
+#include <QRemoteObjectNode>
+#include <QTimer>
+#include <QStandardItemModel>
+#include <QStandardItem>
+
+#include <memory>
+
+struct TimerHandler : public QObject
+{
+ Q_OBJECT
+public:
+ QStandardItemModel *model;
+public Q_SLOTS:
+ void changeData() {
+ Q_ASSERT(model);
+ Q_ASSERT(model->rowCount() > 50);
+ Q_ASSERT(model->columnCount() > 1);
+ for (int i = 10; i < 50; ++i)
+ model->setData(model->index(i, 1), QColor(Qt::blue), Qt::BackgroundRole);
+ }
+ void insertData() {
+ Q_ASSERT(model);
+ Q_ASSERT(model->rowCount() > 50);
+ Q_ASSERT(model->columnCount() > 1);
+ model->insertRows(2, 9);
+ for (int i = 2; i < 11; ++i) {
+ model->setData(model->index(i, 1), QColor(Qt::green), Qt::BackgroundRole);
+ model->setData(model->index(i, 1), QLatin1String("InsertedRow"), Qt::DisplayRole);
+ }
+ }
+ void removeData() {
+ model->removeRows(2, 4);
+ }
+
+ void changeFlags() {
+ QStandardItem *item = model->item(0, 0);
+ item->setEnabled(false);
+ item = item->child(0, 0);
+ item->setFlags(item->flags() & Qt::ItemIsSelectable);
+ }
+
+ void moveData() {
+ model->moveRows(QModelIndex(), 2, 4, QModelIndex(), 10);
+ }
+};
+
+QList<QStandardItem*> addChild(int numChildren, int nestingLevel)
+{
+ QList<QStandardItem*> result;
+ if (nestingLevel == 0)
+ return result;
+ for (int i = 0; i < numChildren; ++i) {
+ QStandardItem *child = new QStandardItem(QStringLiteral("Child num %1, nesting Level %2").arg(i+1).arg(nestingLevel));
+ if (i == 0)
+ child->appendRow(addChild(numChildren, nestingLevel -1));
+ result.push_back(child);
+ }
+ return result;
+}
+
+std::unique_ptr<QStandardItemModel> createModel()
+{
+ std::unique_ptr<QStandardItemModel> sourceModel = std::make_unique<QStandardItemModel>();
+ const int modelSize = 100000;
+ QStringList list;
+ QStringList hHeaderList;
+ hHeaderList << QStringLiteral("First Column with spacing") << QStringLiteral("Second Column with spacing");
+ sourceModel->setHorizontalHeaderLabels(hHeaderList);
+ list.reserve(modelSize);
+ for (int i = 0; i < modelSize; ++i) {
+ QStandardItem *firstItem = new QStandardItem(QStringLiteral("FancyTextNumber %1").arg(i));
+ if (i == 0)
+ firstItem->appendRow(addChild(2, 2));
+ QStandardItem *secondItem = new QStandardItem(QStringLiteral("FancyRow2TextNumber %1").arg(i));
+ if (i % 2 == 0)
+ firstItem->setBackground(Qt::red);
+ QList<QStandardItem*> row;
+ row << firstItem << secondItem;
+ sourceModel->invisibleRootItem()->appendRow(row);
+ list << QStringLiteral("FancyTextNumber %1").arg(i);
+ }
+
+ // Needed by QMLModelViewClient
+ QHash<int,QByteArray> roleNames = {
+ {Qt::DisplayRole, "_text"},
+ {Qt::BackgroundRole, "_color"}
+ };
+ sourceModel->setItemRoleNames(roleNames);
+ return sourceModel;
+}
+
+int main(int argc, char *argv[])
+{
+ QLoggingCategory::setFilterRules("qt.remoteobjects.debug=false\n"
+ "qt.remoteobjects.warning=false");
+ QApplication app(argc, argv);
+
+ qDebug() << "Creating registry host";
+//! [RegistryHost setup]
+ QRemoteObjectRegistryHost node(QUrl(QStringLiteral("local:registry")));
+//! [RegistryHost setup]
+
+//! [Model-creation and role-selection]
+ std::unique_ptr<QStandardItemModel> sourceModel = createModel();
+
+ QList<int> roles;
+ roles << Qt::DisplayRole << Qt::BackgroundRole;
+//! [Model-creation and role-selection]
+
+//! [Model-remoting]
+ QRemoteObjectHost node2(QUrl(QStringLiteral("local:replica")), QUrl(QStringLiteral("local:registry")));
+ node2.enableRemoting(sourceModel.get(), QStringLiteral("RemoteModel"), roles);
+//! [Model-remoting]
+
+//! [TreeView-creation]
+ QTreeView view;
+ view.setWindowTitle(QStringLiteral("SourceView"));
+ view.setModel(sourceModel.get());
+ view.show();
+//! [TreeView-creation]
+
+//! [Automated actions]
+ TimerHandler handler;
+ handler.model = sourceModel.get();
+ QTimer::singleShot(5000, &handler, &TimerHandler::changeData);
+ QTimer::singleShot(10000, &handler, &TimerHandler::insertData);
+ QTimer::singleShot(11000, &handler, &TimerHandler::changeFlags);
+ QTimer::singleShot(12000, &handler, &TimerHandler::removeData);
+ QTimer::singleShot(13000, &handler, &TimerHandler::moveData);
+//! [Automated actions]
+
+
+ return app.exec();
+}
+
+#include "main.moc"
--- /dev/null
+QT += widgets remoteobjects
+requires(qtConfig(treeview))
+
+TEMPLATE = app
+
+CONFIG += c++11
+
+SOURCES += main.cpp
+
+target.path = $$[QT_INSTALL_EXAMPLES]/remoteobjects/modelviewserver
+INSTALLS += target
--- /dev/null
+# Generated from plugins.pro.
+
+cmake_minimum_required(VERSION 3.16)
+project(qmlqrotimeexampleplugin LANGUAGES CXX)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(CMAKE_AUTOMOC ON)
+set(CMAKE_AUTORCC ON)
+set(CMAKE_AUTOUIC ON)
+
+if(NOT DEFINED INSTALL_EXAMPLESDIR)
+ set(INSTALL_EXAMPLESDIR "examples")
+endif()
+
+set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/remoteobjects/plugins/imports/TimeExample")
+
+find_package(Qt6 COMPONENTS Core)
+find_package(Qt6 COMPONENTS Gui)
+find_package(Qt6 COMPONENTS Qml)
+find_package(Qt6 COMPONENTS RemoteObjects)
+
+qt6_add_qml_module(qmlqrotimeexampleplugin
+ OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/imports/TimeExample"
+ VERSION 1.0
+ URI "TimeExample"
+)
+
+target_sources(qmlqrotimeexampleplugin PRIVATE
+ plugin.cpp
+)
+set_target_properties(qmlqrotimeexampleplugin PROPERTIES
+ WIN32_EXECUTABLE TRUE
+ MACOSX_BUNDLE TRUE
+)
+target_link_libraries(qmlqrotimeexampleplugin PUBLIC
+ Qt::Core
+ Qt::Gui
+ Qt::Qml
+ Qt::RemoteObjects
+)
+
+qt6_add_repc_replicas(qmlqrotimeexampleplugin
+ ../timemodel.rep
+)
+
+install(TARGETS qmlqrotimeexampleplugin
+ RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
+ BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
+ LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
+)
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+
+Rectangle {
+ id: clock
+ width: 200; height: 200; color: "gray"
+
+ property alias city: cityLabel.text
+ property variant hours
+ property variant minutes
+ property variant shift : 0
+
+ Image { id: background; source: "clock.png" }
+
+ Image {
+ x: 92.5; y: 27
+ source: "hour.png"
+ transform: Rotation {
+ id: hourRotation
+ origin.x: 7.5; origin.y: 73;
+ angle: (clock.hours * 30) + (clock.minutes * 0.5)
+ Behavior on angle {
+ SpringAnimation{ spring: 2; damping: 0.2; modulus: 360 }
+ }
+ }
+ }
+
+ Image {
+ x: 93.5; y: 17
+ source: "minute.png"
+ transform: Rotation {
+ id: minuteRotation
+ origin.x: 6.5; origin.y: 83;
+ angle: clock.minutes * 6
+ Behavior on angle {
+ SpringAnimation{ spring: 2; damping: 0.2; modulus: 360 }
+ }
+ }
+ }
+
+ Image {
+ anchors.centerIn: background; source: "center.png"
+ }
+
+ Text {
+ id: cityLabel; font.bold: true; font.pixelSize: 14; y:200; color: "white"
+ anchors.horizontalCenter: parent.horizontalCenter
+ }
+}
--- /dev/null
+module TimeExample
+Clock 1.0 Clock.qml
+plugin qmlqrotimeexampleplugin
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtQml/QQmlExtensionPlugin>
+#include <QtQml/QQmlEngine>
+#include <QtQml/qqml.h>
+#include <QDebug>
+#include <QDateTime>
+#include <QBasicTimer>
+#include <QCoreApplication>
+#include <QRemoteObjectReplica>
+#include <QRemoteObjectNode>
+#include "rep_timemodel_replica.h"
+
+// Implements a "TimeModel" class with hour and minute properties
+// that change on-the-minute yet efficiently sleep the rest
+// of the time.
+
+static QRemoteObjectNode m_client;
+
+class TimeModel : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(int hour READ hour NOTIFY timeChanged)
+ Q_PROPERTY(int minute READ minute NOTIFY timeChanged)
+ Q_PROPERTY(bool isValid READ isValid NOTIFY isValidChanged)
+
+public:
+ TimeModel(QObject *parent = nullptr) : QObject(parent), d_ptr(nullptr)
+ {
+ d_ptr.reset(m_client.acquire< MinuteTimerReplica >());
+ connect(d_ptr.data(), &MinuteTimerReplica::hourChanged, this, &TimeModel::timeChanged);
+ connect(d_ptr.data(), &MinuteTimerReplica::minuteChanged, this, &TimeModel::timeChanged);
+ connect(d_ptr.data(), &MinuteTimerReplica::timeChanged, this, &TimeModel::timeChanged);
+ connect(d_ptr.data(), &MinuteTimerReplica::timeChanged2, this, &TimeModel::test);
+ connect(d_ptr.data(), &MinuteTimerReplica::sendCustom, this, &TimeModel::testCustom);
+ }
+
+ ~TimeModel() override
+ {
+ }
+
+ int minute() const { return d_ptr->minute(); }
+ int hour() const { return d_ptr->hour(); }
+ bool isValid() const { return d_ptr->state() == QRemoteObjectReplica::Valid; }
+
+public slots:
+ //Test a signal with parameters
+ void test(QTime t)
+ {
+ qDebug()<<"Test"<<t;
+ d_ptr->SetTimeZone(t.minute());
+ }
+ //Test a signal with a custom type
+ void testCustom(PresetInfo info)
+ {
+ qDebug()<<"testCustom"<<info.presetNumber()<<info.frequency()<<info.stationName();
+ }
+
+signals:
+ void timeChanged();
+ void timeChanged2(QTime t);
+ void sendCustom(PresetInfo info);
+ void isValidChanged();
+
+private:
+ QScopedPointer<MinuteTimerReplica> d_ptr;
+};
+
+class QExampleQmlPlugin : public QQmlExtensionPlugin
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
+
+public:
+ void initializeEngine(QQmlEngine *engine, const char *uri) override
+ {
+ Q_UNUSED(engine)
+ Q_UNUSED(uri)
+ Q_ASSERT(uri == QLatin1String("TimeExample"));
+ engine->addImportPath(QStringLiteral("qrc:/qml"));
+ m_client.setRegistryUrl(QUrl(QStringLiteral("local:registry")));
+ }
+ void registerTypes(const char *uri) override
+ {
+ Q_ASSERT(uri == QLatin1String("TimeExample"));
+ qmlRegisterType<TimeModel>(uri, 1, 0, "Time");
+ }
+
+};
+
+#include "plugin.moc"
--- /dev/null
+QT += qml remoteobjects
+
+TEMPLATE = lib
+CONFIG += plugin
+
+REPC_REPLICA += $$PWD/../timemodel.rep
+
+DESTDIR = imports/TimeExample
+TARGET = qmlqrotimeexampleplugin
+
+SOURCES += plugin.cpp
+
+pluginfiles.files += \
+ imports/TimeExample/qmldir \
+ imports/TimeExample/center.png \
+ imports/TimeExample/clock.png \
+ imports/TimeExample/Clock.qml \
+ imports/TimeExample/hour.png \
+ imports/TimeExample/minute.png
+
+qml.files = plugins.qml
+qml.path += $$[QT_INSTALL_EXAMPLES]/remoteobjects/plugins
+target.path += $$[QT_INSTALL_EXAMPLES]/remoteobjects/plugins/imports/TimeExample
+pluginfiles.path += $$[QT_INSTALL_EXAMPLES]/remoteobjects/plugins/imports/TimeExample
+
+INSTALLS += target qml pluginfiles
+
+CONFIG += install_ok # Do not cargo-cult this!
+
+contains(QT_CONFIG, c++11): CONFIG += c++11
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2014 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+
+Item {
+ width: 200
+ height: 400
+ property int counter: 0;
+ MouseArea {
+ anchors.fill: parent
+ onClicked:
+ {
+ counter = (counter + 1) % 3;
+ console.log(counter);
+ pageLoader.source = "plugins"+counter+".qml"
+ }
+ }
+ Loader {
+ id: pageLoader
+ source: "plugins0.qml"
+ }
+}
+//![0]
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+//![0]
+import QtQuick 2.0
+
+Rectangle {
+ width: 200
+ height: 400
+ color: "blue"
+}
+//![0]
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+//![0]
+import QtQuick 2.0
+import TimeExample 1.0 // import types from the plugin
+
+Rectangle {
+ width: 200
+ height: 400
+ color: "blue"
+ Clock { // this class is defined in QML (imports/TimeExample/Clock.qml)
+ id: clock1
+ anchors.top: parent.top
+ Time { // this class is defined in C++ (plugin.cpp)
+ id: time
+ }
+
+ hours: time.hour
+ minutes: time.minute
+
+ }
+}
+//![0]
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+//![0]
+import QtQuick 2.0
+import TimeExample 1.0 // import types from the plugin
+
+Rectangle {
+ width: 200
+ height: 400
+ Clock { // this class is defined in QML (imports/TimeExample/Clock.qml)
+ id: clock1
+ anchors.top: parent.top
+ Time { // this class is defined in C++ (plugin.cpp)
+ id: time
+ }
+
+ hours: time.hour
+ minutes: time.minute
+
+ }
+ Clock { // this class is defined in QML (imports/TimeExample/Clock.qml)
+ id: clock2
+ anchors.top: clock1.bottom
+ Time { // this class is defined in C++ (plugin.cpp)
+ id: time2
+ }
+
+ hours: time2.hour
+ minutes: time2.minute
+
+ }
+
+}
+//![0]
--- /dev/null
+# Generated from qmlmodelviewclient.pro.
+
+cmake_minimum_required(VERSION 3.16)
+project(qmlmodelviewclient LANGUAGES CXX)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(CMAKE_AUTOMOC ON)
+set(CMAKE_AUTORCC ON)
+set(CMAKE_AUTOUIC ON)
+
+if(NOT DEFINED INSTALL_EXAMPLESDIR)
+ set(INSTALL_EXAMPLESDIR "examples")
+endif()
+
+set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/remoteobjects/qmlmodelviewclient")
+
+find_package(Qt6 COMPONENTS Core)
+find_package(Qt6 COMPONENTS Gui)
+find_package(Qt6 COMPONENTS Qml)
+find_package(Qt6 COMPONENTS Quick)
+find_package(Qt6 COMPONENTS RemoteObjects)
+
+qt_add_executable(qmlmodelviewclient
+ main.cpp
+)
+set_target_properties(qmlmodelviewclient PROPERTIES
+ WIN32_EXECUTABLE TRUE
+ MACOSX_BUNDLE TRUE
+)
+target_link_libraries(qmlmodelviewclient PUBLIC
+ Qt::Core
+ Qt::Gui
+ Qt::Qml
+ Qt::Quick
+ Qt::RemoteObjects
+)
+
+
+# Resources:
+set(qml_resource_files
+ "main.qml"
+)
+
+qt6_add_resources(qmlmodelviewclient "qml"
+ PREFIX
+ "/"
+ FILES
+ ${qml_resource_files}
+)
+
+install(TARGETS qmlmodelviewclient
+ RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
+ BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
+ LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
+)
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \example qmlmodelviewclient
+ \title QML Model-View Client
+
+ This is an alternate client application you can use along with the
+ \l {Model-View Server}.
+
+ This short example showcases how to quickly make a QAbstractItemModelReplica
+ available to and use from QML. See the \l {Model-View Client} example for a
+ more detailed explanation on how the model is acquired and used.
+*/
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QGuiApplication>
+#include <QQmlApplicationEngine>
+#include <QQmlContext>
+#include <QRemoteObjectNode>
+#include <QAbstractItemModelReplica>
+
+int main(int argc, char *argv[])
+{
+ QLoggingCategory::setFilterRules("qt.remoteobjects.debug=false\n"
+ "qt.remoteobjects.warning=false\n"
+ "qt.remoteobjects.models.debug=false\n"
+ "qt.remoteobjects.models.debug=false");
+
+ QGuiApplication app(argc, argv);
+
+ QRemoteObjectNode node(QUrl(QStringLiteral("local:registry")));
+ QQmlApplicationEngine engine;
+ QScopedPointer<QAbstractItemModelReplica> model(node.acquireModel(QStringLiteral("RemoteModel")));
+ engine.rootContext()->setContextProperty("remoteModel", model.data());
+ engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
+
+ return app.exec();
+}
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2016 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.5
+import QtQuick.Window 2.2
+
+Window {
+ visible: true
+ width: 800
+ height: 600
+ Text {
+ id: dummy
+ }
+
+ ListView {
+ id: view
+ anchors.fill: parent
+ focus: true
+
+ currentIndex: 10
+
+ model: remoteModel
+
+ snapMode: ListView.SnapToItem
+ highlightFollowsCurrentItem: true
+ highlightMoveDuration: 0
+
+ delegate: Rectangle {
+ width: view.width
+ height: dummy.font.pixelSize * 2
+ color: _color
+ Text {
+ anchors.centerIn: parent
+ text: _text
+ }
+ }
+ Keys.onPressed: {
+ switch (event.key) {
+ case Qt.Key_Home:
+ view.currentIndex = 0;
+ break;
+ case Qt.Key_PageUp:
+ currentIndex -= Math.random() * 300;
+ if (currentIndex < 0)
+ currentIndex = 0;
+ break;
+ case Qt.Key_PageDown:
+ currentIndex += Math.random() * 300;
+ if (currentIndex >= count)
+ currentIndex = count - 1;
+ break;
+ case Qt.Key_End:
+ currentIndex = count - 1;
+ break;
+ }
+ }
+ }
+}
--- /dev/null
+<RCC>
+ <qresource prefix="/">
+ <file>main.qml</file>
+ </qresource>
+</RCC>
--- /dev/null
+TEMPLATE = app
+
+QT += qml quick remoteobjects
+CONFIG += c++11
+
+SOURCES += main.cpp
+
+RESOURCES += qml.qrc
+
+target.path = $$[QT_INSTALL_EXAMPLES]/remoteobjects/qmlmodelviewclient
+INSTALLS += target
--- /dev/null
+TEMPLATE = subdirs
+CONFIG += debug_and_release ordered
+SUBDIRS = \
+ remoteobjects_server \
+ cppclient \
+ simpleswitch \
+ websockets
+
+qtHaveModule(widgets) {
+ SUBDIRS += \
+ modelviewclient \
+ modelviewserver
+}
+
+contains(QT_CONFIG, ssl): SUBDIRS += ssl
+
+qtHaveModule(quick) {
+ SUBDIRS += \
+ plugins \
+ clientapp
+
+ unix:!android: SUBDIRS += qmlmodelviewclient
+}
--- /dev/null
+# Generated from server.pro.
+
+cmake_minimum_required(VERSION 3.16)
+project(remoteobjects_server LANGUAGES CXX)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(CMAKE_AUTOMOC ON)
+set(CMAKE_AUTORCC ON)
+set(CMAKE_AUTOUIC ON)
+
+if(NOT DEFINED INSTALL_EXAMPLESDIR)
+ set(INSTALL_EXAMPLESDIR "examples")
+endif()
+
+set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/remoteobjects/remoteobjects_server")
+
+find_package(Qt6 COMPONENTS RemoteObjects)
+find_package(Qt6 COMPONENTS Core)
+
+qt_add_executable(remoteobjects_server
+ main.cpp
+ timemodel.cpp timemodel.h
+)
+set_target_properties(remoteobjects_server PROPERTIES
+ WIN32_EXECUTABLE FALSE
+ MACOSX_BUNDLE TRUE
+)
+target_link_libraries(remoteobjects_server PUBLIC
+ Qt::Core
+ Qt::RemoteObjects
+)
+
+qt6_add_repc_sources(remoteobjects_server
+ ../timemodel.rep
+)
+
+install(TARGETS remoteobjects_server
+ RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
+ BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
+ LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
+)
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "timemodel.h"
+
+#include <QCoreApplication>
+/*
+* http://stackoverflow.com/questions/7404163/windows-handling-ctrlc-in-different-thread
+*/
+
+void SigIntHandler()
+{
+ qDebug()<<"Ctrl-C received. Quitting.";
+ qApp->quit();
+}
+
+#if defined(Q_OS_UNIX) || defined(Q_OS_LINUX) || defined(Q_OS_QNX)
+ #include <signal.h>
+
+ void unix_handler(int s)
+ {
+ if (s==SIGINT)
+ SigIntHandler();
+ }
+
+#elif defined(Q_OS_WIN32)
+ #include <windows.h>
+
+ BOOL WINAPI WinHandler(DWORD CEvent)
+ {
+ switch (CEvent)
+ {
+ case CTRL_C_EVENT:
+ SigIntHandler();
+ break;
+ }
+ return TRUE;
+ }
+#endif
+
+int main(int argc, char *argv[])
+{
+ QCoreApplication app(argc, argv);
+
+ #if defined(Q_OS_UNIX) || defined(Q_OS_LINUX) || defined(Q_OS_QNX)
+ signal(SIGINT, &unix_handler);
+ #elif defined(Q_OS_WIN32)
+ SetConsoleCtrlHandler((PHANDLER_ROUTINE)WinHandler, TRUE);
+ #endif
+ QRemoteObjectHost node(QUrl(QStringLiteral("local:replica")),QUrl(QStringLiteral("local:registry")));
+ QRemoteObjectRegistryHost node2(QUrl(QStringLiteral("local:registry")));
+ MinuteTimer timer;
+ node2.enableRemoting(&timer);
+
+ Q_UNUSED(timer)
+ return app.exec();
+}
--- /dev/null
+CONFIG += console
+
+
+REPC_SOURCE += ../timemodel.rep
+QT = remoteobjects core
+
+SOURCES += timemodel.cpp main.cpp
+HEADERS += timemodel.h
+
+contains(QT_CONFIG, c++11): CONFIG += c++11
+
+target.path = $$[QT_INSTALL_EXAMPLES]/remoteobjects/remoteobjects_server
+INSTALLS += target
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "timemodel.h"
+
+MinuteTimer::MinuteTimer(QObject *parent) : MinuteTimerSimpleSource(parent), zone(0)
+{
+ time = QTime::currentTime();
+ setHour(time.hour());
+ setMinute(time.minute());
+ timer.start(60000-time.second()*1000, this);
+}
+MinuteTimer::~MinuteTimer()
+{
+ timer.stop();
+}
+void MinuteTimer::timerEvent(QTimerEvent *)
+{
+ QTime now = QTime::currentTime();
+ if (now.second() == 59 && now.minute() == time.minute() && now.hour() == time.hour()) {
+ // just missed time tick over, force it, wait extra 0.5 seconds
+ time = time.addSecs(60);
+ timer.start(60500, this);
+ } else {
+ time = now;
+ timer.start(60000-time.second()*1000, this);
+ }
+ qDebug()<<"Time"<<time;
+ setHour(time.hour());
+ setMinute(time.minute());
+ emit timeChanged();
+ emit timeChanged2(time);
+ static PresetInfo bla(3, 93.9f, "Best Station");
+ emit sendCustom(bla);
+}
+void MinuteTimer::SetTimeZone(const int &zn)
+{
+ qDebug()<<"SetTimeZone"<<zn;
+ if (zn != zone)
+ {
+ zone = zn;
+ }
+}
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtCore>
+#include "rep_timemodel_source.h"
+
+class MinuteTimer : public MinuteTimerSimpleSource
+{
+ Q_OBJECT
+public:
+ MinuteTimer(QObject *parent = nullptr);
+ ~MinuteTimer() override;
+
+public slots:
+ void SetTimeZone(const int &zn) override;
+
+protected:
+ void timerEvent(QTimerEvent *) override;
+
+private:
+ QTime time;
+ QBasicTimer timer;
+ int zone;
+};
--- /dev/null
+# Generated from simpleswitch.pro.
+
+qt_internal_add_example(directconnectclient)
+qt_internal_add_example(directconnectdynamicclient)
+qt_internal_add_example(directconnectserver)
+qt_internal_add_example(registryconnectedclient)
+qt_internal_add_example(registryconnectedserver)
--- /dev/null
+# Generated from directconnectclient.pro.
+
+cmake_minimum_required(VERSION 3.16)
+project(directconnectclient LANGUAGES CXX)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(CMAKE_AUTOMOC ON)
+set(CMAKE_AUTORCC ON)
+set(CMAKE_AUTOUIC ON)
+
+if(NOT DEFINED INSTALL_EXAMPLESDIR)
+ set(INSTALL_EXAMPLESDIR "examples")
+endif()
+
+set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/remoteobjects/simpleswitch/directconnectclient")
+
+find_package(Qt6 COMPONENTS Core)
+find_package(Qt6 COMPONENTS RemoteObjects)
+
+qt_add_executable(directconnectclient
+ client.cpp client.h
+ main.cpp
+)
+set_target_properties(directconnectclient PROPERTIES
+ WIN32_EXECUTABLE FALSE
+ MACOSX_BUNDLE FALSE
+)
+target_link_libraries(directconnectclient PUBLIC
+ Qt::Core
+ Qt::RemoteObjects
+)
+
+qt6_add_repc_replicas(directconnectclient
+ simpleswitch.rep
+)
+
+install(TARGETS directconnectclient
+ RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
+ BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
+ LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
+)
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "client.h"
+
+// constructor
+Client::Client(QSharedPointer<SimpleSwitchReplica> ptr) :
+ QObject(nullptr), clientSwitchState(false), reptr(ptr)
+{
+ //connect signal for replica initialized with initialization slot
+ initConnections();
+ // We can connect to SimpleSwitchReplica signals/slots
+ //directly because our Replica was generated by repc
+}
+
+//destructor
+Client::~Client()
+{
+
+}
+
+
+void Client::initConnections(void)
+{
+ // initialize connections between signals and slots
+
+ // connect source replica signal currStateChanged() with client's recSwitchState() slot to receive source's current state
+ QObject::connect(reptr.data(), &SimpleSwitchReplica::currStateChanged, this, &Client::recSwitchState_slot);
+ // connect client's echoSwitchState(..) signal with replica's server_slot(..) to echo back received state
+ QObject::connect(this, &Client::echoSwitchState, reptr.data(), &SimpleSwitchReplica::server_slot);
+}
+
+void Client::recSwitchState_slot(bool value)
+{
+ qDebug() << "Received source state "<< value << reptr.data()->currState();
+ clientSwitchState = reptr.data()->currState();
+ Q_EMIT echoSwitchState(clientSwitchState); // Emit signal to echo received state back to server
+}
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef _CLIENT_H
+#define _CLIENT_H
+
+#include <QObject>
+#include <QSharedPointer>
+
+#include "rep_simpleswitch_replica.h"
+
+class Client : public QObject
+{
+ Q_OBJECT
+public:
+ Client(QSharedPointer<SimpleSwitchReplica> ptr);
+ ~Client() override;
+ void initConnections();// function connect signals and slots of source and client
+
+Q_SIGNALS:
+ void echoSwitchState(bool switchState);// this signal is connected with server_slot(..) on the source object and echoes back switch state received from source
+
+public Q_SLOTS:
+ void recSwitchState_slot(bool); // slot to receive source state
+private:
+ bool clientSwitchState; // holds received server switch state
+ QSharedPointer<SimpleSwitchReplica> reptr;// holds reference to replica
+
+ };
+
+#endif
--- /dev/null
+QT += remoteobjects core
+
+QT -= gui
+
+TARGET = directconnectclient
+CONFIG += console
+CONFIG -= app_bundle
+
+REPC_REPLICA = simpleswitch.rep
+
+TEMPLATE = app
+
+target.path = $$[QT_INSTALL_EXAMPLES]/remoteobjects/simpleswitch/directconnectclient
+INSTALLS += target
+
+SOURCES += main.cpp \
+ client.cpp
+
+HEADERS += \
+ client.h
+
+DISTFILES += \
+ simpleswitch.rep
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QCoreApplication>
+#include "client.h"
+
+int main(int argc, char *argv[])
+{
+ QCoreApplication a(argc, argv);
+
+
+ QSharedPointer<SimpleSwitchReplica> ptr;
+
+ QRemoteObjectNode repNode; // create remote object node
+ repNode.connectToNode(QUrl(QStringLiteral("local:replica"))); // connect with remote host node
+
+ ptr.reset(repNode.acquire<SimpleSwitchReplica>()); // acquire replica of source from host node
+
+ Client rswitch(ptr); // create client switch object and pass reference of replica to it
+
+ return a.exec();
+}
--- /dev/null
+#include <QtCore>
+
+class SimpleSwitch
+{
+ PROP(bool currState=false);
+ SLOT(void server_slot(bool clientState));
+};
--- /dev/null
+# Generated from directconnectdynamicclient.pro.
+
+cmake_minimum_required(VERSION 3.16)
+project(directconnectdynamicclient LANGUAGES CXX)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(CMAKE_AUTOMOC ON)
+set(CMAKE_AUTORCC ON)
+set(CMAKE_AUTOUIC ON)
+
+if(NOT DEFINED INSTALL_EXAMPLESDIR)
+ set(INSTALL_EXAMPLESDIR "examples")
+endif()
+
+set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/remoteobjects/simpleswitch/directconnectdynamicclient")
+
+find_package(Qt6 COMPONENTS Core)
+find_package(Qt6 COMPONENTS RemoteObjects)
+
+qt_add_executable(directconnectdynamicclient
+ dynamicclient.cpp dynamicclient.h
+ main.cpp
+)
+set_target_properties(directconnectdynamicclient PROPERTIES
+ WIN32_EXECUTABLE FALSE
+ MACOSX_BUNDLE FALSE
+)
+target_link_libraries(directconnectdynamicclient PUBLIC
+ Qt::Core
+ Qt::RemoteObjects
+)
+
+install(TARGETS directconnectdynamicclient
+ RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
+ BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
+ LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
+)
--- /dev/null
+QT += remoteobjects core
+
+QT -= gui
+
+TARGET = directconnectdynamicclient
+CONFIG += console
+CONFIG -= app_bundle
+
+TEMPLATE = app
+
+target.path = $$[QT_INSTALL_EXAMPLES]/remoteobjects/simpleswitch/directconnectdynamicclient
+INSTALLS += target
+
+SOURCES += main.cpp \
+ dynamicclient.cpp
+
+HEADERS += \
+ dynamicclient.h
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "dynamicclient.h"
+ #include <QMetaMethod>
+
+// constructor
+DynamicClient::DynamicClient(QSharedPointer<QRemoteObjectDynamicReplica> ptr) :
+ QObject(nullptr), clientSwitchState(false), reptr(ptr)
+{
+ //connect signal for replica valid changed with signal slot initialization
+ QObject::connect(reptr.data(), &QRemoteObjectDynamicReplica::initialized, this,
+ &DynamicClient::initConnection_slot);
+}
+
+//destructor
+DynamicClient::~DynamicClient()
+{
+
+}
+
+// Function to initialize connections between slots and signals
+void DynamicClient::initConnection_slot()
+{
+
+ // connect source replica signal currStateChanged() with client's recSwitchState() slot to receive source's current state
+ QObject::connect(reptr.data(), SIGNAL(currStateChanged(bool)), this, SLOT(recSwitchState_slot(bool)));
+ // connect client's echoSwitchState(..) signal with replica's server_slot(..) to echo back received state
+ QObject::connect(this, SIGNAL(echoSwitchState(bool)),reptr.data(), SLOT(server_slot(bool)));
+}
+
+
+void DynamicClient::recSwitchState_slot(bool value)
+{
+ clientSwitchState = reptr->property("currState").toBool(); // use replica property to get "currState" from source
+ qDebug() << "Received source state " << value << clientSwitchState;
+ Q_EMIT echoSwitchState(clientSwitchState); // Emit signal to echo received state back to server
+}
+
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef _DYNAMICCLIENT_H
+#define _DYNAMICCLIENT_H
+
+#include <QObject>
+#include <QSharedPointer>
+
+#include <QRemoteObjectNode>
+#include <qremoteobjectdynamicreplica.h>
+
+class DynamicClient : public QObject
+{
+ Q_OBJECT
+public:
+ DynamicClient(QSharedPointer<QRemoteObjectDynamicReplica> ptr);
+ ~DynamicClient() override;
+
+Q_SIGNALS:
+ void echoSwitchState(bool switchState);// this signal is connected with server_slot(..) slot of source object and echoes back switch state received from source
+
+public Q_SLOTS:
+ void recSwitchState_slot(bool); // slot to receive source state
+ void initConnection_slot();
+
+private:
+ bool clientSwitchState; // holds received server switch state
+ QSharedPointer<QRemoteObjectDynamicReplica> reptr;// holds reference to replica
+ };
+
+#endif
+
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QCoreApplication>
+
+#include "dynamicclient.h"
+
+int main(int argc, char *argv[])
+{
+ QCoreApplication a(argc, argv);
+
+ QSharedPointer<QRemoteObjectDynamicReplica> ptr; // shared pointer to hold replica
+
+ QRemoteObjectNode repNode; // create remote object node
+ repNode.connectToNode(QUrl(QStringLiteral("local:replica"))); // connect with remote host node
+
+ ptr.reset(repNode.acquireDynamic("SimpleSwitch")); // acquire replica of source from host node
+
+ DynamicClient rswitch(ptr); // create client switch object and pass replica reference to it
+
+ return a.exec();
+}
--- /dev/null
+# Generated from directconnectserver.pro.
+
+cmake_minimum_required(VERSION 3.16)
+project(directconnectserver LANGUAGES CXX)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(CMAKE_AUTOMOC ON)
+set(CMAKE_AUTORCC ON)
+set(CMAKE_AUTOUIC ON)
+
+if(NOT DEFINED INSTALL_EXAMPLESDIR)
+ set(INSTALL_EXAMPLESDIR "examples")
+endif()
+
+set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/remoteobjects/simpleswitch/directconnectserver")
+
+find_package(Qt6 COMPONENTS Core)
+find_package(Qt6 COMPONENTS RemoteObjects)
+
+qt_add_executable(directconnectserver
+ main.cpp
+ simpleswitch.cpp simpleswitch.h
+)
+set_target_properties(directconnectserver PROPERTIES
+ WIN32_EXECUTABLE FALSE
+ MACOSX_BUNDLE FALSE
+)
+target_link_libraries(directconnectserver PUBLIC
+ Qt::Core
+ Qt::RemoteObjects
+)
+
+qt6_add_repc_sources(directconnectserver
+ simpleswitch.rep
+)
+
+install(TARGETS directconnectserver
+ RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
+ BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
+ LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
+)
--- /dev/null
+QT += remoteobjects core
+
+QT -= gui
+
+TARGET = directconnectserver
+CONFIG += console
+CONFIG -= app_bundle
+
+REPC_SOURCE = simpleswitch.rep
+
+TEMPLATE = app
+
+target.path = $$[QT_INSTALL_EXAMPLES]/remoteobjects/simpleswitch/directconnectserver
+INSTALLS += target
+
+SOURCES += main.cpp \
+ simpleswitch.cpp
+
+
+HEADERS += \
+ simpleswitch.h
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QCoreApplication>
+#include "simpleswitch.h"
+
+int main(int argc, char *argv[])
+{
+ QCoreApplication a(argc, argv);
+
+ SimpleSwitch srcSwitch; // create simple switch
+
+ QRemoteObjectHost srcNode(QUrl(QStringLiteral("local:replica"))); // create host node without Registry
+ srcNode.enableRemoting(&srcSwitch); // enable remoting/Sharing
+
+ return a.exec();
+}
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "simpleswitch.h"
+
+// constructor
+SimpleSwitch::SimpleSwitch(QObject *parent) : SimpleSwitchSimpleSource(parent)
+{
+ stateChangeTimer = new QTimer(this); // Initialize timer
+ QObject::connect(stateChangeTimer, &QTimer::timeout, this, &SimpleSwitch::timeout_slot); // connect timeout() signal from stateChangeTimer to timeout_slot() of simpleSwitch
+ stateChangeTimer->start(2000); // Start timer and set timout to 2 seconds
+ qDebug() << "Source Node Started";
+}
+
+//destructor
+SimpleSwitch::~SimpleSwitch()
+{
+ stateChangeTimer->stop();
+}
+
+void SimpleSwitch::server_slot(bool clientState)
+{
+ qDebug() << "Replica state is " << clientState; // print switch state echoed back by client
+}
+
+void SimpleSwitch::timeout_slot(void)
+{
+ // slot called on timer timeout
+ if (currState()) // check if current state is true, currState() is defined in repc generated rep_simpleswitch_source.h
+ setCurrState(false); // set state to false
+ else
+ setCurrState(true); // set state to true
+ qDebug() << "Source State is "<<currState();
+
+}
+
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef SIMPLESWITCH_H
+#define SIMPLESWITCH_H
+
+#include "rep_simpleswitch_source.h"
+
+class SimpleSwitch : public SimpleSwitchSimpleSource
+{
+ Q_OBJECT
+public:
+ SimpleSwitch(QObject *parent = nullptr);
+ ~SimpleSwitch() override;
+ void server_slot(bool clientState) override;
+public Q_SLOTS:
+ void timeout_slot();
+private:
+ QTimer *stateChangeTimer;
+};
+
+#endif
--- /dev/null
+#include <QtCore>
+
+class SimpleSwitch
+{
+ PROP(bool currState=false);
+ SLOT(void server_slot(bool clientState));
+};
--- /dev/null
+# Generated from registryconnectedclient.pro.
+
+cmake_minimum_required(VERSION 3.16)
+project(registryconnectedclient LANGUAGES CXX)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(CMAKE_AUTOMOC ON)
+set(CMAKE_AUTORCC ON)
+set(CMAKE_AUTOUIC ON)
+
+if(NOT DEFINED INSTALL_EXAMPLESDIR)
+ set(INSTALL_EXAMPLESDIR "examples")
+endif()
+
+set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/remoteobjects/simpleswitch/registryconnectedclient")
+
+find_package(Qt6 COMPONENTS Core)
+find_package(Qt6 COMPONENTS RemoteObjects)
+
+qt_add_executable(registryconnectedclient
+ dynamicclient.cpp dynamicclient.h
+ main.cpp
+)
+set_target_properties(registryconnectedclient PROPERTIES
+ WIN32_EXECUTABLE FALSE
+ MACOSX_BUNDLE FALSE
+)
+target_link_libraries(registryconnectedclient PUBLIC
+ Qt::Core
+ Qt::RemoteObjects
+)
+
+install(TARGETS registryconnectedclient
+ RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
+ BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
+ LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
+)
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "dynamicclient.h"
+ #include <QMetaMethod>
+
+// constructor
+DynamicClient::DynamicClient(QSharedPointer<QRemoteObjectDynamicReplica> ptr) :
+ QObject(nullptr), clientSwitchState(false), reptr(ptr)
+{
+ //connect signal for replica valid changed with signal slot initialization
+ QObject::connect(reptr.data(), &QRemoteObjectDynamicReplica::initialized, this,
+ &DynamicClient::initConnection_slot);
+}
+
+//destructor
+DynamicClient::~DynamicClient()
+{
+
+}
+
+// Function to initialize connections between slots and signals
+void DynamicClient::initConnection_slot()
+{
+
+ // connect source replica signal currStateChanged() with client's recSwitchState() slot to receive source's current state
+ QObject::connect(reptr.data(), SIGNAL(currStateChanged(bool)), this, SLOT(recSwitchState_slot(bool)));
+ // connect client's echoSwitchState(..) signal with replica's server_slot(..) to echo back received state
+ QObject::connect(this, SIGNAL(echoSwitchState(bool)),reptr.data(), SLOT(server_slot(bool)));
+}
+
+
+void DynamicClient::recSwitchState_slot(bool value)
+{
+ clientSwitchState = reptr->property("currState").toBool(); // use replica property to get "currState" from source
+ qDebug() << "Received source state " << value << clientSwitchState;
+ Q_EMIT echoSwitchState(clientSwitchState); // Emit signal to echo received state back to server
+}
+
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef _DYNAMICCLIENT_H
+#define _DYNAMICCLIENT_H
+
+#include <QObject>
+#include <QSharedPointer>
+
+#include <QRemoteObjectNode>
+#include <qremoteobjectdynamicreplica.h>
+
+class DynamicClient : public QObject
+{
+ Q_OBJECT
+public:
+ DynamicClient(QSharedPointer<QRemoteObjectDynamicReplica> ptr);
+ ~DynamicClient() override;
+
+Q_SIGNALS:
+ void echoSwitchState(bool switchState);// this signal is connected with server_slot(..) slot of source object and echoes back switch state received from source
+
+public Q_SLOTS:
+ void recSwitchState_slot(bool); // slot to receive source state
+ void initConnection_slot();
+
+private:
+ bool clientSwitchState; // holds received server switch state
+ QSharedPointer<QRemoteObjectDynamicReplica> reptr;// holds reference to replica
+ };
+
+#endif
+
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QCoreApplication>
+#include "dynamicclient.h"
+
+int main(int argc, char *argv[])
+{
+ QCoreApplication a(argc, argv);
+
+ QSharedPointer<QRemoteObjectDynamicReplica> ptr; // shared pointer to hold replica
+
+ QRemoteObjectNode repNode(QUrl(QStringLiteral("local:registry")));
+
+ ptr.reset(repNode.acquireDynamic("SimpleSwitch")); // acquire replica of source from host node
+
+ DynamicClient rswitch(ptr); // create client switch object and pass replica reference to it
+
+ return a.exec();
+}
--- /dev/null
+#-------------------------------------------------
+#
+# Project created by QtCreator 2015-02-13T15:22:50
+#
+#-------------------------------------------------
+
+QT += remoteobjects core
+
+QT -= gui
+
+TARGET = registryconnectedclient
+CONFIG += console
+CONFIG -= app_bundle
+
+TEMPLATE = app
+
+target.path = $$[QT_INSTALL_EXAMPLES]/remoteobjects/simpleswitch/registryconnectedclient
+INSTALLS += target
+
+SOURCES += main.cpp \
+ dynamicclient.cpp
+
+HEADERS += \
+ dynamicclient.h
--- /dev/null
+# Generated from registryconnectedserver.pro.
+
+cmake_minimum_required(VERSION 3.16)
+project(registryconnectedserver LANGUAGES CXX)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(CMAKE_AUTOMOC ON)
+set(CMAKE_AUTORCC ON)
+set(CMAKE_AUTOUIC ON)
+
+if(NOT DEFINED INSTALL_EXAMPLESDIR)
+ set(INSTALL_EXAMPLESDIR "examples")
+endif()
+
+set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/remoteobjects/simpleswitch/registryconnectedserver")
+
+find_package(Qt6 COMPONENTS Core)
+find_package(Qt6 COMPONENTS RemoteObjects)
+
+qt_add_executable(registryconnectedserver
+ main.cpp
+ simpleswitch.cpp simpleswitch.h
+)
+set_target_properties(registryconnectedserver PROPERTIES
+ WIN32_EXECUTABLE FALSE
+ MACOSX_BUNDLE FALSE
+)
+target_link_libraries(registryconnectedserver PUBLIC
+ Qt::Core
+ Qt::RemoteObjects
+)
+
+qt6_add_repc_sources(registryconnectedserver
+ simpleswitch.rep
+)
+
+install(TARGETS registryconnectedserver
+ RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
+ BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
+ LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
+)
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QCoreApplication>
+#include "simpleswitch.h"
+
+int main(int argc, char *argv[])
+{
+ QCoreApplication a(argc, argv);
+
+ SimpleSwitch srcSwitch; // create simple switch
+
+ QRemoteObjectRegistryHost regNode(QUrl(QStringLiteral("local:registry"))); // create node that hosts registy
+ QRemoteObjectHost srcNode(QUrl(QStringLiteral("local:replica")), QUrl(QStringLiteral("local:registry"))); // create node that will host source and connect to registry
+
+ //Note, you can add srcSwitch directly to regNode if desired.
+ //We use two Nodes here, as the regNode could easily be in a third process.
+
+ srcNode.enableRemoting(&srcSwitch); // enable remoting of source object
+
+ return a.exec();
+}
+
--- /dev/null
+#-------------------------------------------------
+#
+# Project created by QtCreator 2015-02-13T15:02:06
+#
+#-------------------------------------------------
+
+QT += remoteobjects core
+
+QT -= gui
+
+TARGET = registryconnectedserver
+CONFIG += console
+CONFIG -= app_bundle
+
+REPC_SOURCE = simpleswitch.rep
+
+
+TEMPLATE = app
+
+target.path = $$[QT_INSTALL_EXAMPLES]/remoteobjects/simpleswitch/registryconnectedserver
+INSTALLS += target
+
+SOURCES += main.cpp \
+ simpleswitch.cpp
+
+HEADERS += \
+ simpleswitch.h
+
+DISTFILES += \
+ simpleswitch.rep
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "simpleswitch.h"
+
+// constructor
+SimpleSwitch::SimpleSwitch(QObject *parent) : SimpleSwitchSimpleSource(parent)
+{
+ stateChangeTimer = new QTimer(this); // Initialize timer
+ QObject::connect(stateChangeTimer, &QTimer::timeout, this, &SimpleSwitch::timeout_slot); // connect timeout() signal from stateChangeTimer to timeout_slot() of simpleSwitch
+ stateChangeTimer->start(2000); // Start timer and set timout to 2 seconds
+ qDebug() << "Source Node Started";
+}
+
+//destructor
+SimpleSwitch::~SimpleSwitch()
+{
+ stateChangeTimer->stop();
+}
+
+void SimpleSwitch::server_slot(bool clientState)
+{
+ qDebug() << "Replica state is " << clientState; // print switch state echoed back by client
+}
+
+void SimpleSwitch::timeout_slot(void)
+{
+ // slot called on timer timeout
+ if (currState()) // check if current state is true, currState() is defined in repc generated rep_simpleswitch_source.h
+ setCurrState(false); // set state to false
+ else
+ setCurrState(true); // set state to true
+ qDebug() << "Source State is "<<currState();
+
+}
+
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef SIMPLESWITCH_H
+#define SIMPLESWITCH_H
+
+#include "rep_simpleswitch_source.h"
+
+class SimpleSwitch : public SimpleSwitchSimpleSource
+{
+ Q_OBJECT
+public:
+ SimpleSwitch(QObject *parent = nullptr);
+ ~SimpleSwitch() override;
+ void server_slot(bool clientState) override;
+public Q_SLOTS:
+ void timeout_slot();
+private:
+ QTimer *stateChangeTimer;
+};
+
+#endif
--- /dev/null
+#include <QtCore>
+
+class SimpleSwitch
+{
+ PROP(bool currState=false);
+ SLOT(void server_slot(bool clientState));
+};
+
--- /dev/null
+TEMPLATE = subdirs
+
+SUBDIRS += \
+ directconnectclient \
+ directconnectdynamicclient \
+ directconnectserver \
+ registryconnectedclient \
+ registryconnectedserver
--- /dev/null
+# Generated from ssl.pro.
+
+qt_internal_add_example(sslserver)
+qt_internal_add_example(sslcppclient)
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \example ssl
+ \title QtRemoteObjects SSL Example
+
+ This example shows how you can set up a secure Remote Object network using
+ QSslSockets! Encrypting communication is critical when you need to pass data
+ through a network you don't have full control over.
+*/
--- /dev/null
+TEMPLATE = subdirs
+CONFIG += debug_and_release ordered
+
+SUBDIRS = \
+ sslserver \
+ sslcppclient
--- /dev/null
+# Generated from sslcppclient.pro.
+
+cmake_minimum_required(VERSION 3.16)
+project(SslCppClient LANGUAGES CXX)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(CMAKE_AUTOMOC ON)
+set(CMAKE_AUTORCC ON)
+set(CMAKE_AUTOUIC ON)
+
+if(NOT DEFINED INSTALL_EXAMPLESDIR)
+ set(INSTALL_EXAMPLESDIR "examples")
+endif()
+
+set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/remoteobjects/ssl/sslcppclient")
+
+find_package(Qt6 COMPONENTS RemoteObjects)
+find_package(Qt6 COMPONENTS Core)
+
+qt_add_executable(SslCppClient
+ main.cpp
+)
+set_target_properties(SslCppClient PROPERTIES
+ WIN32_EXECUTABLE TRUE
+ MACOSX_BUNDLE FALSE
+)
+target_link_libraries(SslCppClient PUBLIC
+ # Remove: gui
+ Qt::Core
+ Qt::RemoteObjects
+ Qt::RemoteObjectsPrivate
+)
+
+
+# Resources:
+set(cert_resource_files
+ "../sslserver/cert/client.crt"
+ "../sslserver/cert/client.key"
+ "../sslserver/cert/rootCA.key"
+ "../sslserver/cert/rootCA.pem"
+ "../sslserver/cert/rootCA.srl"
+ "../sslserver/cert/server.crt"
+ "../sslserver/cert/server.key"
+)
+
+qt6_add_resources(SslCppClient "cert"
+ PREFIX
+ "/sslcert"
+ BASE
+ "../sslserver/cert"
+ FILES
+ ${cert_resource_files}
+)
+
+qt6_add_repc_replicas(SslCppClient
+ timemodel.rep
+)
+
+install(TARGETS SslCppClient
+ RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
+ BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
+ LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
+)
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QCoreApplication>
+#include <QHostAddress>
+#include <QSslSocket>
+#include <QSslConfiguration>
+#include <QSslKey>
+#include <QTimer>
+#include "rep_timemodel_replica.h"
+
+#include <QRemoteObjectNode>
+
+class tester : public QObject
+{
+ Q_OBJECT
+public:
+ tester() : QObject(nullptr)
+ {
+ QRemoteObjectNode m_client;
+ auto socket = setupConnection();
+ connect(socket, &QSslSocket::errorOccurred,
+ socket, [](QAbstractSocket::SocketError error){
+ qDebug() << "QSslSocket::error" << error;
+ }) ;
+ m_client.addClientSideConnection(socket);
+
+ ptr1.reset(m_client.acquire< MinuteTimerReplica >());
+ ptr2.reset(m_client.acquire< MinuteTimerReplica >());
+ ptr3.reset(m_client.acquire< MinuteTimerReplica >());
+ QTimer::singleShot(0, this, &tester::clear);
+ QTimer::singleShot(1, this, &tester::clear);
+ QTimer::singleShot(10000, this, &tester::clear);
+ QTimer::singleShot(11000, this, &tester::clear);
+ }
+public slots:
+ void clear()
+ {
+ static int i = 0;
+ if (i == 0) {
+ i++;
+ ptr1.reset();
+ } else if (i == 1) {
+ i++;
+ ptr2.reset();
+ } else if (i == 2) {
+ i++;
+ ptr3.reset();
+ } else {
+ qApp->quit();
+ }
+ }
+
+private:
+ QScopedPointer<MinuteTimerReplica> ptr1, ptr2, ptr3;
+
+ QSslSocket *setupConnection()
+ {
+ auto socketClient = new QSslSocket;
+ socketClient->setLocalCertificate(QStringLiteral(":/sslcert/client.crt"));
+ socketClient->setPrivateKey(QStringLiteral(":/sslcert/client.key"));
+ socketClient->setPeerVerifyMode(QSslSocket::VerifyPeer);
+ socketClient->connectToHostEncrypted(QStringLiteral("127.0.0.1"), 65511);
+ if (!socketClient->waitForEncrypted(-1)) {
+ qWarning("Failed to connect to server %s",
+ qPrintable(socketClient->errorString()));
+ exit(0);
+ }
+ return socketClient;
+ }
+};
+
+int main(int argc, char *argv[])
+{
+ QCoreApplication a(argc, argv);
+
+ auto config = QSslConfiguration::defaultConfiguration();
+ config.setCaCertificates(QSslCertificate::fromPath(QStringLiteral(":/sslcert/rootCA.pem")));
+ QSslConfiguration::setDefaultConfiguration(config);
+
+ tester t;
+ return a.exec();
+}
+
+#include "main.moc"
--- /dev/null
+QT_FOR_CONFIG += network
+requires(qtConfig(ssl))
+
+REPC_REPLICA += timemodel.rep
+QT = remoteobjects remoteobjects-private core
+
+QT -= gui
+
+TARGET = SslCppClient
+CONFIG -= app_bundle
+
+TEMPLATE = app
+
+SOURCES += main.cpp
+
+OTHER_FILES += \
+ timemodel.rep
+
+RESOURCES += \
+ ../sslserver/cert/cert.qrc
+
+
+target.path = $$[QT_INSTALL_EXAMPLES]/remoteobjects/ssl/sslcppclient
+INSTALLS += target
--- /dev/null
+#include <QtCore>
+
+POD PresetInfo(int presetNumber, float frequency, QString stationName)
+class MinuteTimer
+{
+ PROP(int hour=1);
+ PROP(int minute=51);
+ SIGNAL(timeChanged());
+ SIGNAL(timeChanged2(QTime t));
+ SIGNAL(sendCustom(PresetInfo info));
+ SLOT(void SetTimeZone(int zn));
+};
--- /dev/null
+# Generated from sslserver.pro.
+
+cmake_minimum_required(VERSION 3.16)
+project(sslserver LANGUAGES CXX)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(CMAKE_AUTOMOC ON)
+set(CMAKE_AUTORCC ON)
+set(CMAKE_AUTOUIC ON)
+
+if(NOT DEFINED INSTALL_EXAMPLESDIR)
+ set(INSTALL_EXAMPLESDIR "examples")
+endif()
+
+set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/remoteobjects/ssl/sslserver")
+
+find_package(Qt6 COMPONENTS RemoteObjects)
+find_package(Qt6 COMPONENTS Core)
+
+qt_add_executable(sslserver
+ main.cpp
+ sslserver.cpp sslserver.h
+ timemodel.cpp timemodel.h
+)
+set_target_properties(sslserver PROPERTIES
+ WIN32_EXECUTABLE FALSE
+ MACOSX_BUNDLE TRUE
+)
+target_link_libraries(sslserver PUBLIC
+ Qt::Core
+ Qt::RemoteObjects
+ Qt::RemoteObjectsPrivate
+)
+
+
+# Resources:
+set(cert_resource_files
+ "cert/client.crt"
+ "cert/client.key"
+ "cert/rootCA.key"
+ "cert/rootCA.pem"
+ "cert/rootCA.srl"
+ "cert/server.crt"
+ "cert/server.key"
+)
+
+qt6_add_resources(sslserver "cert"
+ PREFIX
+ "/sslcert"
+ BASE
+ "cert"
+ FILES
+ ${cert_resource_files}
+)
+
+qt6_add_repc_sources(sslserver
+ ../../timemodel.rep
+)
+
+install(TARGETS sslserver
+ RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
+ BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
+ LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
+)
--- /dev/null
+<RCC>
+ <qresource prefix="/sslcert">
+ <file>client.crt</file>
+ <file>client.key</file>
+ <file>rootCA.key</file>
+ <file>rootCA.pem</file>
+ <file>rootCA.srl</file>
+ <file>server.crt</file>
+ <file>server.key</file>
+ </qresource>
+</RCC>
--- /dev/null
+-----BEGIN CERTIFICATE-----
+MIICrTCCAZUCFHOQggvUf1o8c5i3yNyiGLNcLC4pMA0GCSqGSIb3DQEBCwUAMBIx
+EDAOBgNVBAMMB1F0Uk8gQ0EwHhcNMjEwMjI0MTEzMzU1WhcNMjMwNTMwMTEzMzU1
+WjAUMRIwEAYDVQQDDAkxMjcuMC4wLjEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
+ggEKAoIBAQDbl9iuedw0oSbtpC2m30YdzwRmemijasP9SQGQ6+piUOFUKCZsoGWc
+RcEnLGzC+KJ7FXh8jA1kTXSW6ghqvrUysN8VzjgmcCLFee4JAkCUY8yNrlq13ciR
+19BE09kJdOPZeI57pCSBNA6iy03Q4nc/GJpG63QTqJv/WUUgMek0UsmZIzDcWaqr
+MCMnLMaRi5oKFCnnl8E0XDuRm1nqPAzT+us/4upMv+7Q2xs4QFXbLUpSIToNc1wm
+tP6OAGaYClbJZgZbUNowj0wJeCUAwGGcDpliYj1JB8R015z8Kd8pDCvdD7XL35JR
+rT+eaBFNLUrl30aIl3lWf/buv3OoRmuVAgMBAAEwDQYJKoZIhvcNAQELBQADggEB
+AJjdfuy2pb3KgnpxYiXfKXCqGlN7E1RyoCIsMhldWcxAN5cwIJCrvde5MNI8kDvd
+0SfDpRpCP/hZqpR6DsR9iNYJprXlQNZ7Rs41Eswwlb66DqmBlb5ZQcYl8KsKV5fw
+7PhvLpjC5hEg1OBg1Ooz+aNvI9OJYIRFUJ1smtRzwXWuQd5QoqYVRpzvmrFawnGa
+2NHywiwgKyGvY/y82pPuj1rt0L+bae85cZm32f6gp1me9OuLIqA2G5UafSiigWBY
+YL249Rd4rrT87GAeaiBo8ZxZ8de8O7TOBjSNrfAMySepDWjfFfoNpyp+4foRKmpE
+aZmgGTIj5rfhYh4Gcj1nZBw=
+-----END CERTIFICATE-----
--- /dev/null
+-----BEGIN RSA PRIVATE KEY-----
+MIIEogIBAAKCAQEA25fYrnncNKEm7aQtpt9GHc8EZnpoo2rD/UkBkOvqYlDhVCgm
+bKBlnEXBJyxswviiexV4fIwNZE10luoIar61MrDfFc44JnAixXnuCQJAlGPMja5a
+td3IkdfQRNPZCXTj2XiOe6QkgTQOostN0OJ3PxiaRut0E6ib/1lFIDHpNFLJmSMw
+3FmqqzAjJyzGkYuaChQp55fBNFw7kZtZ6jwM0/rrP+LqTL/u0NsbOEBV2y1KUiE6
+DXNcJrT+jgBmmApWyWYGW1DaMI9MCXglAMBhnA6ZYmI9SQfEdNec/CnfKQwr3Q+1
+y9+SUa0/nmgRTS1K5d9GiJd5Vn/27r9zqEZrlQIDAQABAoIBAEDLm4pQNuPosV3p
+1fapZz0gesHqWLnvpQk145ppom2ERBjbCAuBgLoN8yKl/ynAx+DdwwGtKb5xBHgL
+cpRc1YaxngIHKZZd/ESc59oMqhWfJRqhWe7UFHzEW5YTlLUvopPm+NQO6R6ex7rN
+lpaOXHVnww4uJ8AtPmqoYrdPQurG/txveRMLo84JJT+IH2YVWOzccp809zw4WZZD
+qBcgm/dV8ir+8nUHQlR+loMMrEoKeacNxtHUXWL6d6P93Q72L07t41/l0XmXXq7I
+cVJnGxcJtkeqj03FSHqDU3XM5fRg6f+XnnSnhnd4AUmHe8cvyeCnEf4bdh4UpzBG
+sCie+XkCgYEA93FU0X6ttWdb+rJNHRnHmb4DxOVo2LeXEk1A1ul+Yj+jFP+TwJH+
+bm8PbV7ALdyH2u66ElQG60gW9ztu86xl5ZLVdhijWJpjHKB45eXVhnRcb2Fy9tDc
+pUeRs8+IrrYbWDrNZZYWby83MqPHimCLTmAZl11NMB2ohyFDxr5voGMCgYEA4y/0
+2WN8r74H9I3L2Ghfe8e3i/W35BpjtElJxiL3L1vzGdU5Wo1hDnvjoHvdTxB7LtGU
+I+P0l77fwuAC8G8bh4SZ59jcxlqCmbXy7wDAyrYaCja5OWK9xWXvYuya5CCPrg6h
+wo7TcrxjdEvEVQ97PMZcq6HVBOtINZGfJeSieacCgYAHyQsQJFo20O+17ZI7jioX
+jkD0Gvu3hd889i1KFcKiOLpa2Me/UVieBOSJXmfRiZTEsKouFXK6SGRglwAgrpXu
+KTaKJrBNA16G8g2bviV/u32FC53gYiXvFVdiPu9f/97QYdlAjv5ZtTSZZUnL8smv
+R5rGhmr9TpGU3tkREcDVXQKBgBUfJ0dyvWvlYf31lOcYxQ/QAJuNi7w0S+K+EZLP
+O2X2yYI0VbG6hTSAhigse+XW5Wzz5S71CY92Gn2WsA9EdS3DQT/R5Ky4S34Y8W4R
+BtuR1JfwgIX6TSRmFrx+vOPKtzD6gUWCW9xF8YUlaipyVwXOd10pnZFogn0gfchb
+GlPvAoGAG2xikjlCTrnKv7KRF9sxO1eLixfzHwWKiAhrtFBoHSM4AwynrpAb0eMf
+ObSIjXeBy93LhTluVOsD5J9iXA/SKYoXqt/tDMCHRdwpTsJNBa56GMkpFHHLo6oC
+si20nmMXP949gpRIvrYsgYC8WObbi+RQEWDVutv7hVPCF0QvUHs=
+-----END RSA PRIVATE KEY-----
--- /dev/null
+These files are generated by the script located at tests/auto/external_IODevice/cert/generate.sh
+
--- /dev/null
+-----BEGIN RSA PRIVATE KEY-----
+MIIEowIBAAKCAQEAulVnnHwRF6e2aAThSi1cZpUlO3ZdqzPIuf75NBbRY2y9Vm+F
+cyCqUquNxP/qDE02nfQFBd/PUKqUWQs0EXVEVZPEG6s/l7ionYHkMmWSjh+AAWp7
+Iwx3MlHFNi9c5Xrod7iS1igg0YhDQlnT0xGfTXZasUJ/s6NuNoZiN5L6sEKYDSAu
+kzyyqS23WrqE4RvsGAaoaaJqu1MT8DBqI9xoPpIvwb/4gdOZn4YClW2WWrVjCTT2
+zEzUAh1BjdH3dktXogiFfXHuOP4W8suOx46NXDcZ3f5LF8CT/2uq9l8vta+pV2ci
+BAIctGu5z+fEdTCojvCWOvCzYmjtep/yTukT+QIDAQABAoIBAQCRvRjkCRnpUZDW
+vPJk7SO3THIplwPeUwtthqLtfedaB4PzphhPmr39GRcyfSNXadENK/39wTbKlhCf
+sKaR/RFsib26EnATwCeJwj10uYMuTC73bIxRNn/ISLKiFdtn1YEbmq6meA5rNFO/
+Arkt/juF/8shl6yAGZSrauJJK1mOH8ItMaGR+6tVPWLIZOLk6TiOJhj9SXvMTCw/
+HzgNZMgFGfqnbctg1ki/CY0BkIkYNUTCjhoCwjcgBJl4ERCfTQS6UeEG9Ad+beIH
+g8WKzpfjF5+Jnjzqw87aWx1200OdlEdouTt677RXHJFN5naUc+GJZGpmA3RGZA17
+LqA4zBYNAoGBAOGwtg7JQkBOmUC0SiKdXnxG1hVnS4N3DMIDVX2tAe/wWIrP168e
+0UpCvswLD+JqO1IgWqw9+QUPnhJSQ9JbYB+678esOTLsT5Yd18VcsiRxSacvQfUw
+H4YJaHrFuuFlnxYMlMdPYS3knbIPsft9DVQLFBLL7qPVHbrJ3V6Sn4XrAoGBANNb
+mfhgVr5m0n3sQVTlYhWwbJq5K+Htzzl7Xl3JHpMLm2C/GoorP/2zLVhbH20lsE3A
+FyIfjcwRxGRu2TXCVnMc4GttlMX5leTxykEd2VrZuEVnTdrudm45Z6sZQpdf1QTg
+WebwKgN1eCg7Jkuk5YlRX/KwMtuq4MVzPtOvR+CrAoGAA8uC5DDCKm6n6QyfCoH2
+6sQOKYH5JRbFYiXINDrKg4xZEMx55fnwrvz8VFYDSF1c7f6ZR7grDci7cbdsaIcc
+0KvGCGd+9ro+hFmwHSN342D8ShFjXIoYnZpe5WGZyNx6llZT0h4lli338NyOs5ng
+tX8SMVa4hoy42UE3tbVldU0CgYA0l/K0b6SmNIfkdcm8Cmhh5UjhJ3rX+Yk7UIum
+4skM5jJ/3I4KG8EMrG14MxSa4GoCru4Su69ZPIKWS08ZpYZFlsXxdY8zxGucUN53
+XaochVjpTE9/Tx+BRh+Z3+tGJ76mO/2jDdgmjDCeMjnRUPMdPHaXuWiuaNMNzyOv
+IUrNiQKBgGvxEQ0Oe3d/om2Lp/cHbkhZkw/jO/FG5HtodxiO3+1YLhExsDOc5GVn
++x2eNv+dQSIrGagko9TJe1p9WqFnD19Ls+ezqfw2fR5Amg1KHKGUA7k1+Qe/QgoK
+D+T4/RkvdGRoBv/il+Rj1rfmMAhEzdD7Axek9a6rUj8geO22kp7I
+-----END RSA PRIVATE KEY-----
--- /dev/null
+-----BEGIN CERTIFICATE-----
+MIIDBTCCAe2gAwIBAgIUV9eILCYaC+qwZHR7OO23uyd2UjwwDQYJKoZIhvcNAQEL
+BQAwEjEQMA4GA1UEAwwHUXRSTyBDQTAeFw0yMTAyMjQxMTMzNTVaFw0yMzA2MTAx
+MTMzNTVaMBIxEDAOBgNVBAMMB1F0Uk8gQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IB
+DwAwggEKAoIBAQC6VWecfBEXp7ZoBOFKLVxmlSU7dl2rM8i5/vk0FtFjbL1Wb4Vz
+IKpSq43E/+oMTTad9AUF389QqpRZCzQRdURVk8Qbqz+XuKidgeQyZZKOH4ABansj
+DHcyUcU2L1zleuh3uJLWKCDRiENCWdPTEZ9NdlqxQn+zo242hmI3kvqwQpgNIC6T
+PLKpLbdauoThG+wYBqhpomq7UxPwMGoj3Gg+ki/Bv/iB05mfhgKVbZZatWMJNPbM
+TNQCHUGN0fd2S1eiCIV9ce44/hbyy47Hjo1cNxnd/ksXwJP/a6r2Xy+1r6lXZyIE
+Ahy0a7nP58R1MKiO8JY68LNiaO16n/JO6RP5AgMBAAGjUzBRMB0GA1UdDgQWBBSu
+ehS/XLejTiDbCddGU2mMZ1t3CjAfBgNVHSMEGDAWgBSuehS/XLejTiDbCddGU2mM
+Z1t3CjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQB8JzSuhHPK
+cjhLqOHUGMKtKWOd5p9g2D45cAWh6jdzU/AhmslMPbsO5hZkqfE+3xARtcMmQfF2
+k1Qyp3hDTN1ZqHSM6Urq9uR33/wXZbNRUNCD8lAmqKyzF9NF7Q+tmC//IMRtVQhK
+aMN3LciyYGQjT0XhDKFWEz9/AvUQD97mLow2m0/izqE4SI6ekQDNL26IiCWFgFjh
+ScZjcJ1ogluD2a6sEUGywRXLNV/bdSjRgkAbpvJFrok7dDZ8xCNhOg4xJJQJRWm7
+ZusUydiVyfgrFan6MD+EdldRHjAs8S9BJfZ0RTOWnD9V8auKuVomzKDed54QlXXi
+zwowb3Objpqh
+-----END CERTIFICATE-----
--- /dev/null
+7390820BD47F5A3C7398B7C8DCA218B35C2C2E29
--- /dev/null
+-----BEGIN CERTIFICATE-----
+MIIDFTCCAf2gAwIBAgIUc5CCC9R/WjxzmLfI3KIYs1wsLigwDQYJKoZIhvcNAQEL
+BQAwEjEQMA4GA1UEAwwHUXRSTyBDQTAeFw0yMTAyMjQxMTMzNTVaFw0yMzA1MzAx
+MTMzNTVaMBQxEjAQBgNVBAMMCTEyNy4wLjAuMTCCASIwDQYJKoZIhvcNAQEBBQAD
+ggEPADCCAQoCggEBAOKHte9tB66OD+Um/WkqxHtW3sKrBs4IxKuWAef0UMRt3ld6
+5HvWk+xsCZdPxeL53nMOIy9FS6wKGvEWTwYRR4Id9iX2XQsI4cRJWl25qgCYohnm
+Eet9CUkXa3ywbyrSBWFD0r956sS+mwhHU9z05jphd6iZEonHu2b4BFFXMN7+prwj
+00EtGbte5wSWWE9ZfXzeGYd4cZBReNCRjaS5XJ3IgjZ4tfxsB3JzBjVafCfnth7r
+Is8a2SKCGnhYmV+A6Agth4xtSKDho+BSDYSuMux3dftM/eqtxF0wXzlnX5ApNwGB
+zWjcoUL63vjjy17oNEtbs5X2e1g8bGRaGRxGUHUCAwEAAaNhMF8wHwYDVR0jBBgw
+FoAUrnoUv1y3o04g2wnXRlNpjGdbdwowCQYDVR0TBAIwADALBgNVHQ8EBAMCBPAw
+EwYDVR0lBAwwCgYIKwYBBQUHAwEwDwYDVR0RBAgwBocEfwAAATANBgkqhkiG9w0B
+AQsFAAOCAQEAqhBhxRgG9N1ZghwWC3ZhWSx4BFl3YrStWlQcjffcQ6p8NDxsrkFc
+gMG51TmJdaz8J4v2AZW8k9GJlEIaZdV/8czeyEwvjKD4vrUw88waeW7n6o8H+8k+
+ak9fRFvnerFrLEWNpyRqbjJWwm8bQ4T5UKsVNXkZnNLyG2Ha29L9gUHffgSMiyLO
+hWqcanPxsMJaDVhw/Gd8JwqaEC1nRPCGxhog2/D2sh4vCj1UykykjPwNz5fP/vfA
+VujNCA23eXAdgD3lALHu2WrmyPkQCM7Z61g4k8+v0KjhyJjdLSVTwkPePEo87Fv4
+sn4Jp5gPPBf7jDFKp8PDdbPmk0qN+Wm8gA==
+-----END CERTIFICATE-----
--- /dev/null
+-----BEGIN RSA PRIVATE KEY-----
+MIIEogIBAAKCAQEA4oe1720Hro4P5Sb9aSrEe1bewqsGzgjEq5YB5/RQxG3eV3rk
+e9aT7GwJl0/F4vnecw4jL0VLrAoa8RZPBhFHgh32JfZdCwjhxElaXbmqAJiiGeYR
+630JSRdrfLBvKtIFYUPSv3nqxL6bCEdT3PTmOmF3qJkSice7ZvgEUVcw3v6mvCPT
+QS0Zu17nBJZYT1l9fN4Zh3hxkFF40JGNpLlcnciCNni1/GwHcnMGNVp8J+e2Husi
+zxrZIoIaeFiZX4DoCC2HjG1IoOGj4FINhK4y7Hd1+0z96q3EXTBfOWdfkCk3AYHN
+aNyhQvre+OPLXug0S1uzlfZ7WDxsZFoZHEZQdQIDAQABAoIBAGuKEYzALc1oE5Ot
+ls++RdhnvQidOHXHI9ZxOCZtjYoyvkK5TI6dp0utXkA+1qqSBFCKfZmLRAlAItog
+xRMUUOYsYxZShokehk8wo32rDlGKJCo3Vnp8uVPBkn13JM8nNPafxASyVAlikyay
+9dUHTeSZML0RLgPKleSkCSi0Q7cYOFG/HB9aNjp8F5rdut02KrmC3cxlHKF7QXXG
+VU+op1Z9o0V2/iUFJnF5CR40sW2THEbBJkkeYwbvUTnavz4XQtZst//DKsDQEe2r
+UrhsIHduvG4tWiBE77m1vyigTxUWCsLQ2KCnn9O+4KyTg9HWCiQ2QSU3istX/rpI
+zN2lOgECgYEA9PVVMnY+t59Q73IQ9LRg5KRqg6YyGQOrwJKbCUxDrA6ikh3MDgwV
+CkC6Jdl6e4DMog51l3CizrfR2+mtNSTUJDGFE1iGgI+Faem4aopRtFRiLWJ8n4m7
+U8pl3XTP0XFT68aBCAE6O/xVPXs0I/eKNvaF5vokB5zm4R79o37WP+UCgYEA7L26
+TiCFA73Fil/bPupqWJnvm896RlO1S+IBOKlPyCHVvxiGLvtv+YTucCFwXQ4FeNRh
+bQEWlURsgeNr7PHATtFUZ/zo/7l1WYNLXZDZwWD+JYllVPwskJOJMx5Rc77Q0aQ6
+7v60XMGwD5cxQ29RHuJs09Iwc9b1WqwOAEJAJVECgYBNsxQXMZKrRAm0KgZe2Ghz
+ngN7RthVPujX6KjsxhghF3NRzcnQGt0Bp45kOxuy2SQPs25xXvUFhSE4FGMwnEH+
+SQbhIA9p8BxtgAlTIhTQkoOhyb+mC1Y0Odsd59OTp9Lq0shS9bC3Hk8bdV0Qm5Bn
+5sKKhYWwNIC3n9Dsb2seUQKBgAS7biPtpnsCqhYwAFPrn6CRwyZcKVeKiM8xf1DA
+oaWgd4NQXC5IPF7Cd3mqUXKquxVFOYVSRj9JlNmr0BZ2Zp+ss4E4nvetn1jgtPrz
+0EZ7R9k8O9hNCh8Bs/ZfnsUvhUELhVoNoVFRVdGZ9hQg/4AcioxZYTqPi2v6kHUU
+3e9hAoGAec7anF5TiTx2jjcDFS9hrRw0w2PsNX24qjqPFqeuzDIorh6rq4Ip4aA0
+7rxeIXmxjmYA7pPCT9rPxtpEp4BQovF9kHMutd8lyB4rGbLpNpOY4m5v8Oo7cLQ3
+kLAwE+jrEwLNtuq+kUlGwK7YLeiGUm4Rsof5IXlSkXzL/99gHC4=
+-----END RSA PRIVATE KEY-----
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "timemodel.h"
+
+#include <QCoreApplication>
+#include <QSslConfiguration>
+
+#include "sslserver.h"
+
+#include <QRemoteObjectHost>
+/*
+* http://stackoverflow.com/questions/7404163/windows-handling-ctrlc-in-different-thread
+*/
+
+void SigIntHandler()
+{
+ qDebug()<<"Ctrl-C received. Quitting.";
+ qApp->quit();
+}
+
+#if defined(Q_OS_UNIX) || defined(Q_OS_LINUX) || defined(Q_OS_QNX)
+#include <signal.h>
+
+void unix_handler(int s)
+{
+ if (s==SIGINT)
+ SigIntHandler();
+}
+
+#elif defined(Q_OS_WIN32)
+#include <windows.h>
+
+BOOL WINAPI WinHandler(DWORD CEvent)
+{
+ switch (CEvent)
+ {
+ case CTRL_C_EVENT:
+ SigIntHandler();
+ break;
+ }
+ return TRUE;
+}
+#endif
+
+int main(int argc, char *argv[])
+{
+ QCoreApplication app(argc, argv);
+
+ auto config = QSslConfiguration::defaultConfiguration();
+ config.setCaCertificates(QSslCertificate::fromPath(QStringLiteral(":/sslcert/rootCA.pem")));
+ QSslConfiguration::setDefaultConfiguration(config);
+
+#if defined(Q_OS_UNIX) || defined(Q_OS_LINUX) || defined(Q_OS_QNX)
+ signal(SIGINT, &unix_handler);
+#elif defined(Q_OS_WIN32)
+ SetConsoleCtrlHandler((PHANDLER_ROUTINE)WinHandler, TRUE);
+#endif
+ QRemoteObjectHost host;
+ SslServer server;
+ server.listen(QHostAddress::Any, 65511);
+
+ host.setHostUrl(server.serverAddress().toString(), QRemoteObjectHost::AllowExternalRegistration);
+
+ QObject::connect(&server, &SslServer::encryptedSocketReady, &server, [&host](QSslSocket *socket) {
+ QObject::connect(socket, &QSslSocket::errorOccurred,
+ socket, [](QAbstractSocket::SocketError error){
+ qDebug() << "QSslSocket::error" << error;
+ }) ;
+ host.addHostSideConnection(socket);
+ });
+
+ MinuteTimer timer;
+ host.enableRemoting(&timer);
+
+ Q_UNUSED(timer)
+ return app.exec();
+}
+
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2018 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "sslserver.h"
+#include <QSslSocket>
+
+SslServer::SslServer(QObject *parent)
+ : QTcpServer(parent)
+{}
+
+
+void SslServer::incomingConnection(qintptr socketDescriptor)
+{
+ auto serverSocket = new QSslSocket;
+ if (serverSocket->setSocketDescriptor(socketDescriptor)) {
+ addPendingConnection(serverSocket);
+ connect(serverSocket, &QSslSocket::encrypted, this, [this, serverSocket] {
+ Q_EMIT encryptedSocketReady(serverSocket);
+ });
+ connect(serverSocket, static_cast<void (QSslSocket::*)(const QList<QSslError>&)>(&QSslSocket::sslErrors),
+ this, [serverSocket](const QList<QSslError>& errors){
+ qWarning() << "Error:" << serverSocket << errors;
+ delete serverSocket;
+ });
+ serverSocket->setPeerVerifyMode(QSslSocket::VerifyPeer);
+ serverSocket->setLocalCertificate(QStringLiteral(":/sslcert/server.crt"));
+ serverSocket->setPrivateKey(QStringLiteral(":/sslcert/server.key"));
+ serverSocket->startServerEncryption();
+ } else {
+ delete serverSocket;
+ }
+}
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2018 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef SSLSERVER_H
+#define SSLSERVER_H
+
+#include <QTcpServer>
+
+QT_BEGIN_NAMESPACE
+class QSslSocket;
+QT_END_NAMESPACE
+
+class SslServer : public QTcpServer
+{
+ Q_OBJECT
+public:
+ SslServer(QObject *parent=nullptr);
+ void incomingConnection(qintptr socketDescriptor) override;
+
+signals:
+ void encryptedSocketReady(QSslSocket *socket);
+};
+
+#endif // SSLSERVER_H
--- /dev/null
+QT_FOR_CONFIG += network
+requires(qtConfig(ssl))
+
+CONFIG += console
+
+
+REPC_SOURCE += ../../timemodel.rep
+QT = remoteobjects remoteobjects-private core
+
+SOURCES += timemodel.cpp main.cpp \
+ sslserver.cpp
+HEADERS += timemodel.h \
+ sslserver.h
+
+contains(QT_CONFIG, c++11): CONFIG += c++11
+
+target.path = $$[QT_INSTALL_EXAMPLES]/remoteobjects/ssl/sslserver
+INSTALLS += target
+
+RESOURCES += \
+ cert/cert.qrc
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "timemodel.h"
+
+MinuteTimer::MinuteTimer(QObject *parent) : MinuteTimerSimpleSource(parent), zone(0)
+{
+ time = QTime::currentTime();
+ setHour(time.hour());
+ setMinute(time.minute());
+ timer.start(60000-time.second()*1000, this);
+}
+MinuteTimer::~MinuteTimer()
+{
+ timer.stop();
+}
+void MinuteTimer::timerEvent(QTimerEvent *)
+{
+ QTime now = QTime::currentTime();
+ if (now.second() == 59 && now.minute() == time.minute() && now.hour() == time.hour()) {
+ // just missed time tick over, force it, wait extra 0.5 seconds
+ time = time.addSecs(60);
+ timer.start(60500, this);
+ } else {
+ time = now;
+ timer.start(60000-time.second()*1000, this);
+ }
+ qDebug()<<"Time"<<time;
+ setHour(time.hour());
+ setMinute(time.minute());
+ emit timeChanged();
+ emit timeChanged2(time);
+ static PresetInfo bla(3, 93.9f, "Best Station");
+ emit sendCustom(bla);
+}
+void MinuteTimer::SetTimeZone(const int &zn)
+{
+ qDebug()<<"SetTimeZone"<<zn;
+ if (zn != zone)
+ {
+ zone = zn;
+ }
+}
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtCore>
+#include "rep_timemodel_source.h"
+
+class MinuteTimer : public MinuteTimerSimpleSource
+{
+ Q_OBJECT
+public:
+ MinuteTimer(QObject *parent = nullptr);
+ ~MinuteTimer() override;
+
+public slots:
+ void SetTimeZone(const int &zn) override;
+
+protected:
+ void timerEvent(QTimerEvent *) override;
+
+private:
+ QTime time;
+ QBasicTimer timer;
+ int zone;
+};
--- /dev/null
+#include <QtCore>
+
+POD PresetInfo(int presetNumber, float frequency, QString stationName)
+POD PresetData(QList<QString> bla)
+class MinuteTimer
+{
+ PROP(int hour=1);
+ PROP(int minute=51);
+ SIGNAL(timeChanged());
+ SIGNAL(timeChanged2(QTime t));
+ SIGNAL(sendCustom(PresetInfo info));
+ SIGNAL(foo(QMap<QString, QString> foo));
+ SLOT(void SetTimeZone(const int &));
+};
--- /dev/null
+# Generated from websockets.pro.
+
+if(TARGET Qt::WebSockets AND TARGET Qt::Widgets)
+ qt_internal_add_example(wsclient)
+ qt_internal_add_example(wsserver)
+endif()
--- /dev/null
+<RCC>
+ <qresource prefix="/sslcert">
+ <file>client.crt</file>
+ <file>client.key</file>
+ <file>rootCA.key</file>
+ <file>rootCA.pem</file>
+ <file>rootCA.srl</file>
+ <file>server.crt</file>
+ <file>server.key</file>
+ </qresource>
+</RCC>
--- /dev/null
+-----BEGIN CERTIFICATE-----
+MIICrTCCAZUCFHOQggvUf1o8c5i3yNyiGLNcLC4pMA0GCSqGSIb3DQEBCwUAMBIx
+EDAOBgNVBAMMB1F0Uk8gQ0EwHhcNMjEwMjI0MTEzMzU1WhcNMjMwNTMwMTEzMzU1
+WjAUMRIwEAYDVQQDDAkxMjcuMC4wLjEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
+ggEKAoIBAQDbl9iuedw0oSbtpC2m30YdzwRmemijasP9SQGQ6+piUOFUKCZsoGWc
+RcEnLGzC+KJ7FXh8jA1kTXSW6ghqvrUysN8VzjgmcCLFee4JAkCUY8yNrlq13ciR
+19BE09kJdOPZeI57pCSBNA6iy03Q4nc/GJpG63QTqJv/WUUgMek0UsmZIzDcWaqr
+MCMnLMaRi5oKFCnnl8E0XDuRm1nqPAzT+us/4upMv+7Q2xs4QFXbLUpSIToNc1wm
+tP6OAGaYClbJZgZbUNowj0wJeCUAwGGcDpliYj1JB8R015z8Kd8pDCvdD7XL35JR
+rT+eaBFNLUrl30aIl3lWf/buv3OoRmuVAgMBAAEwDQYJKoZIhvcNAQELBQADggEB
+AJjdfuy2pb3KgnpxYiXfKXCqGlN7E1RyoCIsMhldWcxAN5cwIJCrvde5MNI8kDvd
+0SfDpRpCP/hZqpR6DsR9iNYJprXlQNZ7Rs41Eswwlb66DqmBlb5ZQcYl8KsKV5fw
+7PhvLpjC5hEg1OBg1Ooz+aNvI9OJYIRFUJ1smtRzwXWuQd5QoqYVRpzvmrFawnGa
+2NHywiwgKyGvY/y82pPuj1rt0L+bae85cZm32f6gp1me9OuLIqA2G5UafSiigWBY
+YL249Rd4rrT87GAeaiBo8ZxZ8de8O7TOBjSNrfAMySepDWjfFfoNpyp+4foRKmpE
+aZmgGTIj5rfhYh4Gcj1nZBw=
+-----END CERTIFICATE-----
--- /dev/null
+-----BEGIN RSA PRIVATE KEY-----
+MIIEogIBAAKCAQEA25fYrnncNKEm7aQtpt9GHc8EZnpoo2rD/UkBkOvqYlDhVCgm
+bKBlnEXBJyxswviiexV4fIwNZE10luoIar61MrDfFc44JnAixXnuCQJAlGPMja5a
+td3IkdfQRNPZCXTj2XiOe6QkgTQOostN0OJ3PxiaRut0E6ib/1lFIDHpNFLJmSMw
+3FmqqzAjJyzGkYuaChQp55fBNFw7kZtZ6jwM0/rrP+LqTL/u0NsbOEBV2y1KUiE6
+DXNcJrT+jgBmmApWyWYGW1DaMI9MCXglAMBhnA6ZYmI9SQfEdNec/CnfKQwr3Q+1
+y9+SUa0/nmgRTS1K5d9GiJd5Vn/27r9zqEZrlQIDAQABAoIBAEDLm4pQNuPosV3p
+1fapZz0gesHqWLnvpQk145ppom2ERBjbCAuBgLoN8yKl/ynAx+DdwwGtKb5xBHgL
+cpRc1YaxngIHKZZd/ESc59oMqhWfJRqhWe7UFHzEW5YTlLUvopPm+NQO6R6ex7rN
+lpaOXHVnww4uJ8AtPmqoYrdPQurG/txveRMLo84JJT+IH2YVWOzccp809zw4WZZD
+qBcgm/dV8ir+8nUHQlR+loMMrEoKeacNxtHUXWL6d6P93Q72L07t41/l0XmXXq7I
+cVJnGxcJtkeqj03FSHqDU3XM5fRg6f+XnnSnhnd4AUmHe8cvyeCnEf4bdh4UpzBG
+sCie+XkCgYEA93FU0X6ttWdb+rJNHRnHmb4DxOVo2LeXEk1A1ul+Yj+jFP+TwJH+
+bm8PbV7ALdyH2u66ElQG60gW9ztu86xl5ZLVdhijWJpjHKB45eXVhnRcb2Fy9tDc
+pUeRs8+IrrYbWDrNZZYWby83MqPHimCLTmAZl11NMB2ohyFDxr5voGMCgYEA4y/0
+2WN8r74H9I3L2Ghfe8e3i/W35BpjtElJxiL3L1vzGdU5Wo1hDnvjoHvdTxB7LtGU
+I+P0l77fwuAC8G8bh4SZ59jcxlqCmbXy7wDAyrYaCja5OWK9xWXvYuya5CCPrg6h
+wo7TcrxjdEvEVQ97PMZcq6HVBOtINZGfJeSieacCgYAHyQsQJFo20O+17ZI7jioX
+jkD0Gvu3hd889i1KFcKiOLpa2Me/UVieBOSJXmfRiZTEsKouFXK6SGRglwAgrpXu
+KTaKJrBNA16G8g2bviV/u32FC53gYiXvFVdiPu9f/97QYdlAjv5ZtTSZZUnL8smv
+R5rGhmr9TpGU3tkREcDVXQKBgBUfJ0dyvWvlYf31lOcYxQ/QAJuNi7w0S+K+EZLP
+O2X2yYI0VbG6hTSAhigse+XW5Wzz5S71CY92Gn2WsA9EdS3DQT/R5Ky4S34Y8W4R
+BtuR1JfwgIX6TSRmFrx+vOPKtzD6gUWCW9xF8YUlaipyVwXOd10pnZFogn0gfchb
+GlPvAoGAG2xikjlCTrnKv7KRF9sxO1eLixfzHwWKiAhrtFBoHSM4AwynrpAb0eMf
+ObSIjXeBy93LhTluVOsD5J9iXA/SKYoXqt/tDMCHRdwpTsJNBa56GMkpFHHLo6oC
+si20nmMXP949gpRIvrYsgYC8WObbi+RQEWDVutv7hVPCF0QvUHs=
+-----END RSA PRIVATE KEY-----
--- /dev/null
+These files are generated by the script located at tests/auto/external_IODevice/cert/generate.sh
+
--- /dev/null
+-----BEGIN RSA PRIVATE KEY-----
+MIIEowIBAAKCAQEAulVnnHwRF6e2aAThSi1cZpUlO3ZdqzPIuf75NBbRY2y9Vm+F
+cyCqUquNxP/qDE02nfQFBd/PUKqUWQs0EXVEVZPEG6s/l7ionYHkMmWSjh+AAWp7
+Iwx3MlHFNi9c5Xrod7iS1igg0YhDQlnT0xGfTXZasUJ/s6NuNoZiN5L6sEKYDSAu
+kzyyqS23WrqE4RvsGAaoaaJqu1MT8DBqI9xoPpIvwb/4gdOZn4YClW2WWrVjCTT2
+zEzUAh1BjdH3dktXogiFfXHuOP4W8suOx46NXDcZ3f5LF8CT/2uq9l8vta+pV2ci
+BAIctGu5z+fEdTCojvCWOvCzYmjtep/yTukT+QIDAQABAoIBAQCRvRjkCRnpUZDW
+vPJk7SO3THIplwPeUwtthqLtfedaB4PzphhPmr39GRcyfSNXadENK/39wTbKlhCf
+sKaR/RFsib26EnATwCeJwj10uYMuTC73bIxRNn/ISLKiFdtn1YEbmq6meA5rNFO/
+Arkt/juF/8shl6yAGZSrauJJK1mOH8ItMaGR+6tVPWLIZOLk6TiOJhj9SXvMTCw/
+HzgNZMgFGfqnbctg1ki/CY0BkIkYNUTCjhoCwjcgBJl4ERCfTQS6UeEG9Ad+beIH
+g8WKzpfjF5+Jnjzqw87aWx1200OdlEdouTt677RXHJFN5naUc+GJZGpmA3RGZA17
+LqA4zBYNAoGBAOGwtg7JQkBOmUC0SiKdXnxG1hVnS4N3DMIDVX2tAe/wWIrP168e
+0UpCvswLD+JqO1IgWqw9+QUPnhJSQ9JbYB+678esOTLsT5Yd18VcsiRxSacvQfUw
+H4YJaHrFuuFlnxYMlMdPYS3knbIPsft9DVQLFBLL7qPVHbrJ3V6Sn4XrAoGBANNb
+mfhgVr5m0n3sQVTlYhWwbJq5K+Htzzl7Xl3JHpMLm2C/GoorP/2zLVhbH20lsE3A
+FyIfjcwRxGRu2TXCVnMc4GttlMX5leTxykEd2VrZuEVnTdrudm45Z6sZQpdf1QTg
+WebwKgN1eCg7Jkuk5YlRX/KwMtuq4MVzPtOvR+CrAoGAA8uC5DDCKm6n6QyfCoH2
+6sQOKYH5JRbFYiXINDrKg4xZEMx55fnwrvz8VFYDSF1c7f6ZR7grDci7cbdsaIcc
+0KvGCGd+9ro+hFmwHSN342D8ShFjXIoYnZpe5WGZyNx6llZT0h4lli338NyOs5ng
+tX8SMVa4hoy42UE3tbVldU0CgYA0l/K0b6SmNIfkdcm8Cmhh5UjhJ3rX+Yk7UIum
+4skM5jJ/3I4KG8EMrG14MxSa4GoCru4Su69ZPIKWS08ZpYZFlsXxdY8zxGucUN53
+XaochVjpTE9/Tx+BRh+Z3+tGJ76mO/2jDdgmjDCeMjnRUPMdPHaXuWiuaNMNzyOv
+IUrNiQKBgGvxEQ0Oe3d/om2Lp/cHbkhZkw/jO/FG5HtodxiO3+1YLhExsDOc5GVn
++x2eNv+dQSIrGagko9TJe1p9WqFnD19Ls+ezqfw2fR5Amg1KHKGUA7k1+Qe/QgoK
+D+T4/RkvdGRoBv/il+Rj1rfmMAhEzdD7Axek9a6rUj8geO22kp7I
+-----END RSA PRIVATE KEY-----
--- /dev/null
+-----BEGIN CERTIFICATE-----
+MIIDBTCCAe2gAwIBAgIUV9eILCYaC+qwZHR7OO23uyd2UjwwDQYJKoZIhvcNAQEL
+BQAwEjEQMA4GA1UEAwwHUXRSTyBDQTAeFw0yMTAyMjQxMTMzNTVaFw0yMzA2MTAx
+MTMzNTVaMBIxEDAOBgNVBAMMB1F0Uk8gQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IB
+DwAwggEKAoIBAQC6VWecfBEXp7ZoBOFKLVxmlSU7dl2rM8i5/vk0FtFjbL1Wb4Vz
+IKpSq43E/+oMTTad9AUF389QqpRZCzQRdURVk8Qbqz+XuKidgeQyZZKOH4ABansj
+DHcyUcU2L1zleuh3uJLWKCDRiENCWdPTEZ9NdlqxQn+zo242hmI3kvqwQpgNIC6T
+PLKpLbdauoThG+wYBqhpomq7UxPwMGoj3Gg+ki/Bv/iB05mfhgKVbZZatWMJNPbM
+TNQCHUGN0fd2S1eiCIV9ce44/hbyy47Hjo1cNxnd/ksXwJP/a6r2Xy+1r6lXZyIE
+Ahy0a7nP58R1MKiO8JY68LNiaO16n/JO6RP5AgMBAAGjUzBRMB0GA1UdDgQWBBSu
+ehS/XLejTiDbCddGU2mMZ1t3CjAfBgNVHSMEGDAWgBSuehS/XLejTiDbCddGU2mM
+Z1t3CjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQB8JzSuhHPK
+cjhLqOHUGMKtKWOd5p9g2D45cAWh6jdzU/AhmslMPbsO5hZkqfE+3xARtcMmQfF2
+k1Qyp3hDTN1ZqHSM6Urq9uR33/wXZbNRUNCD8lAmqKyzF9NF7Q+tmC//IMRtVQhK
+aMN3LciyYGQjT0XhDKFWEz9/AvUQD97mLow2m0/izqE4SI6ekQDNL26IiCWFgFjh
+ScZjcJ1ogluD2a6sEUGywRXLNV/bdSjRgkAbpvJFrok7dDZ8xCNhOg4xJJQJRWm7
+ZusUydiVyfgrFan6MD+EdldRHjAs8S9BJfZ0RTOWnD9V8auKuVomzKDed54QlXXi
+zwowb3Objpqh
+-----END CERTIFICATE-----
--- /dev/null
+7390820BD47F5A3C7398B7C8DCA218B35C2C2E29
--- /dev/null
+-----BEGIN CERTIFICATE-----
+MIIDFTCCAf2gAwIBAgIUc5CCC9R/WjxzmLfI3KIYs1wsLigwDQYJKoZIhvcNAQEL
+BQAwEjEQMA4GA1UEAwwHUXRSTyBDQTAeFw0yMTAyMjQxMTMzNTVaFw0yMzA1MzAx
+MTMzNTVaMBQxEjAQBgNVBAMMCTEyNy4wLjAuMTCCASIwDQYJKoZIhvcNAQEBBQAD
+ggEPADCCAQoCggEBAOKHte9tB66OD+Um/WkqxHtW3sKrBs4IxKuWAef0UMRt3ld6
+5HvWk+xsCZdPxeL53nMOIy9FS6wKGvEWTwYRR4Id9iX2XQsI4cRJWl25qgCYohnm
+Eet9CUkXa3ywbyrSBWFD0r956sS+mwhHU9z05jphd6iZEonHu2b4BFFXMN7+prwj
+00EtGbte5wSWWE9ZfXzeGYd4cZBReNCRjaS5XJ3IgjZ4tfxsB3JzBjVafCfnth7r
+Is8a2SKCGnhYmV+A6Agth4xtSKDho+BSDYSuMux3dftM/eqtxF0wXzlnX5ApNwGB
+zWjcoUL63vjjy17oNEtbs5X2e1g8bGRaGRxGUHUCAwEAAaNhMF8wHwYDVR0jBBgw
+FoAUrnoUv1y3o04g2wnXRlNpjGdbdwowCQYDVR0TBAIwADALBgNVHQ8EBAMCBPAw
+EwYDVR0lBAwwCgYIKwYBBQUHAwEwDwYDVR0RBAgwBocEfwAAATANBgkqhkiG9w0B
+AQsFAAOCAQEAqhBhxRgG9N1ZghwWC3ZhWSx4BFl3YrStWlQcjffcQ6p8NDxsrkFc
+gMG51TmJdaz8J4v2AZW8k9GJlEIaZdV/8czeyEwvjKD4vrUw88waeW7n6o8H+8k+
+ak9fRFvnerFrLEWNpyRqbjJWwm8bQ4T5UKsVNXkZnNLyG2Ha29L9gUHffgSMiyLO
+hWqcanPxsMJaDVhw/Gd8JwqaEC1nRPCGxhog2/D2sh4vCj1UykykjPwNz5fP/vfA
+VujNCA23eXAdgD3lALHu2WrmyPkQCM7Z61g4k8+v0KjhyJjdLSVTwkPePEo87Fv4
+sn4Jp5gPPBf7jDFKp8PDdbPmk0qN+Wm8gA==
+-----END CERTIFICATE-----
--- /dev/null
+-----BEGIN RSA PRIVATE KEY-----
+MIIEogIBAAKCAQEA4oe1720Hro4P5Sb9aSrEe1bewqsGzgjEq5YB5/RQxG3eV3rk
+e9aT7GwJl0/F4vnecw4jL0VLrAoa8RZPBhFHgh32JfZdCwjhxElaXbmqAJiiGeYR
+630JSRdrfLBvKtIFYUPSv3nqxL6bCEdT3PTmOmF3qJkSice7ZvgEUVcw3v6mvCPT
+QS0Zu17nBJZYT1l9fN4Zh3hxkFF40JGNpLlcnciCNni1/GwHcnMGNVp8J+e2Husi
+zxrZIoIaeFiZX4DoCC2HjG1IoOGj4FINhK4y7Hd1+0z96q3EXTBfOWdfkCk3AYHN
+aNyhQvre+OPLXug0S1uzlfZ7WDxsZFoZHEZQdQIDAQABAoIBAGuKEYzALc1oE5Ot
+ls++RdhnvQidOHXHI9ZxOCZtjYoyvkK5TI6dp0utXkA+1qqSBFCKfZmLRAlAItog
+xRMUUOYsYxZShokehk8wo32rDlGKJCo3Vnp8uVPBkn13JM8nNPafxASyVAlikyay
+9dUHTeSZML0RLgPKleSkCSi0Q7cYOFG/HB9aNjp8F5rdut02KrmC3cxlHKF7QXXG
+VU+op1Z9o0V2/iUFJnF5CR40sW2THEbBJkkeYwbvUTnavz4XQtZst//DKsDQEe2r
+UrhsIHduvG4tWiBE77m1vyigTxUWCsLQ2KCnn9O+4KyTg9HWCiQ2QSU3istX/rpI
+zN2lOgECgYEA9PVVMnY+t59Q73IQ9LRg5KRqg6YyGQOrwJKbCUxDrA6ikh3MDgwV
+CkC6Jdl6e4DMog51l3CizrfR2+mtNSTUJDGFE1iGgI+Faem4aopRtFRiLWJ8n4m7
+U8pl3XTP0XFT68aBCAE6O/xVPXs0I/eKNvaF5vokB5zm4R79o37WP+UCgYEA7L26
+TiCFA73Fil/bPupqWJnvm896RlO1S+IBOKlPyCHVvxiGLvtv+YTucCFwXQ4FeNRh
+bQEWlURsgeNr7PHATtFUZ/zo/7l1WYNLXZDZwWD+JYllVPwskJOJMx5Rc77Q0aQ6
+7v60XMGwD5cxQ29RHuJs09Iwc9b1WqwOAEJAJVECgYBNsxQXMZKrRAm0KgZe2Ghz
+ngN7RthVPujX6KjsxhghF3NRzcnQGt0Bp45kOxuy2SQPs25xXvUFhSE4FGMwnEH+
+SQbhIA9p8BxtgAlTIhTQkoOhyb+mC1Y0Odsd59OTp9Lq0shS9bC3Hk8bdV0Qm5Bn
+5sKKhYWwNIC3n9Dsb2seUQKBgAS7biPtpnsCqhYwAFPrn6CRwyZcKVeKiM8xf1DA
+oaWgd4NQXC5IPF7Cd3mqUXKquxVFOYVSRj9JlNmr0BZ2Zp+ss4E4nvetn1jgtPrz
+0EZ7R9k8O9hNCh8Bs/ZfnsUvhUELhVoNoVFRVdGZ9hQg/4AcioxZYTqPi2v6kHUU
+3e9hAoGAec7anF5TiTx2jjcDFS9hrRw0w2PsNX24qjqPFqeuzDIorh6rq4Ip4aA0
+7rxeIXmxjmYA7pPCT9rPxtpEp4BQovF9kHMutd8lyB4rGbLpNpOY4m5v8Oo7cLQ3
+kLAwE+jrEwLNtuq+kUlGwK7YLeiGUm4Rsof5IXlSkXzL/99gHC4=
+-----END RSA PRIVATE KEY-----
--- /dev/null
+CONFIG -= app_bundle
+
+INCLUDEPATH += $$PWD
+
+HEADERS += \
+ $$PWD/websocketiodevice.h
+
+SOURCES += \
+ $$PWD/websocketiodevice.cpp
+
+RESOURCES += $$PWD/cert/cert.qrc
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2019 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "websocketiodevice.h"
+
+#include <QWebSocket>
+
+WebSocketIoDevice::WebSocketIoDevice(QWebSocket *webSocket, QObject *parent)
+ : QIODevice(parent)
+ , m_socket(webSocket)
+{
+ open(QIODevice::ReadWrite);
+ connect(webSocket, &QWebSocket::disconnected, this, &WebSocketIoDevice::disconnected);
+ connect(webSocket, &QWebSocket::binaryMessageReceived, this, [this](const QByteArray &message){
+ m_buffer.append(message);
+ emit readyRead();
+ });
+ connect(webSocket, &QWebSocket::bytesWritten, this, &WebSocketIoDevice::bytesWritten);
+}
+
+qint64 WebSocketIoDevice::bytesAvailable() const
+{
+ return QIODevice::bytesAvailable() + m_buffer.size();
+}
+
+bool WebSocketIoDevice::isSequential() const
+{
+ return true;
+}
+
+void WebSocketIoDevice::close()
+{
+ if (m_socket)
+ m_socket->close();
+}
+
+qint64 WebSocketIoDevice::readData(char *data, qint64 maxlen)
+{
+ auto sz = std::min(maxlen, qint64(m_buffer.size()));
+ if (sz <= 0)
+ return sz;
+ memcpy(data, m_buffer.constData(), size_t(sz));
+ m_buffer.remove(0, sz);
+ return sz;
+}
+
+qint64 WebSocketIoDevice::writeData(const char *data, qint64 len)
+{
+ if (m_socket)
+ return m_socket->sendBinaryMessage(QByteArray{data, int(len)});
+ return -1;
+}
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2019 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef WEBSOCKETIODEVICE_H
+#define WEBSOCKETIODEVICE_H
+
+#include <QBuffer>
+#include <QIODevice>
+#include <QPointer>
+
+class QWebSocket;
+
+class WebSocketIoDevice : public QIODevice
+{
+ Q_OBJECT
+public:
+ WebSocketIoDevice(QWebSocket *webSocket, QObject *parent = nullptr);
+
+signals:
+ void disconnected();
+
+ // QIODevice interface
+public:
+ qint64 bytesAvailable() const override;
+ bool isSequential() const override;
+ void close() override;
+
+protected:
+ qint64 readData(char *data, qint64 maxlen) override;
+ qint64 writeData(const char *data, qint64 len) override;
+
+private:
+ QPointer<QWebSocket> m_socket;
+ QByteArray m_buffer;
+};
+
+#endif // WEBSOCKETIODEVICE_H
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \example websockets
+ \title QtRemoteObjects WebSockets Example
+
+ This example shows how you could use a non-QIODevice-based transport
+ (QWebSocket) with QtRemoteObjects. This is achieved by implementing a
+ small QIODevice-derived wrapper for QWebSocket.
+*/
--- /dev/null
+TEMPLATE = subdirs
+
+qtHaveModule(widgets): qtHaveModule(websockets) {
+ SUBDIRS += \
+ wsclient \
+ wsserver
+}
--- /dev/null
+# Generated from wsclient.pro.
+
+cmake_minimum_required(VERSION 3.16)
+project(wsclient LANGUAGES CXX)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(CMAKE_AUTOMOC ON)
+set(CMAKE_AUTORCC ON)
+set(CMAKE_AUTOUIC ON)
+
+if(NOT DEFINED INSTALL_EXAMPLESDIR)
+ set(INSTALL_EXAMPLESDIR "examples")
+endif()
+
+set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/remoteobjects/websockets/wsclient")
+
+find_package(Qt6 COMPONENTS Core)
+find_package(Qt6 COMPONENTS Gui)
+find_package(Qt6 COMPONENTS Widgets)
+find_package(Qt6 COMPONENTS RemoteObjects)
+find_package(Qt6 COMPONENTS WebSockets)
+
+qt_add_executable(wsclient
+ ../common/websocketiodevice.cpp ../common/websocketiodevice.h
+ main.cpp
+)
+set_target_properties(wsclient PROPERTIES
+ WIN32_EXECUTABLE TRUE
+ MACOSX_BUNDLE FALSE
+)
+target_include_directories(wsclient PUBLIC
+ ../common
+)
+
+target_link_libraries(wsclient PUBLIC
+ Qt::Core
+ Qt::Gui
+ Qt::RemoteObjects
+ Qt::WebSockets
+ Qt::Widgets
+)
+
+
+# Resources:
+set(cert_resource_files
+ "../common/cert/client.crt"
+ "../common/cert/client.key"
+ "../common/cert/rootCA.key"
+ "../common/cert/rootCA.pem"
+ "../common/cert/rootCA.srl"
+ "../common/cert/server.crt"
+ "../common/cert/server.key"
+)
+
+qt6_add_resources(wsclient "cert"
+ PREFIX
+ "/sslcert"
+ BASE
+ "../common/cert"
+ FILES
+ ${cert_resource_files}
+)
+
+install(TARGETS wsclient
+ RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
+ BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
+ LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
+)
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2019 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QTreeView>
+#include <QApplication>
+#include <QRemoteObjectNode>
+#include <QAbstractItemModelReplica>
+#include <QWebSocket>
+
+#ifndef QT_NO_SSL
+# include <QFile>
+# include <QSslConfiguration>
+# include <QSslKey>
+#endif
+#include "websocketiodevice.h"
+
+int main(int argc, char **argv)
+{
+
+ QLoggingCategory::setFilterRules("qt.remoteobjects.debug=false\n"
+ "qt.remoteobjects.warning=false\n"
+ "qt.remoteobjects.models.debug=false\n"
+ "qt.remoteobjects.models.debug=false");
+
+ QApplication app(argc, argv);
+
+
+
+ QScopedPointer<QWebSocket> webSocket{new QWebSocket};
+ WebSocketIoDevice socket(webSocket.data());
+#ifndef QT_NO_SSL
+ // Always use secure connections when available
+ QSslConfiguration sslConf;
+ QFile certFile(QStringLiteral(":/sslcert/client.crt"));
+ if (!certFile.open(QIODevice::ReadOnly))
+ qFatal("Can't open client.crt file");
+ sslConf.setLocalCertificate(QSslCertificate{certFile.readAll()});
+
+ QFile keyFile(QStringLiteral(":/sslcert/client.key"));
+ if (!keyFile.open(QIODevice::ReadOnly))
+ qFatal("Can't open client.key file");
+ sslConf.setPrivateKey(QSslKey{keyFile.readAll(), QSsl::Rsa});
+
+ sslConf.setPeerVerifyMode(QSslSocket::VerifyPeer);
+ webSocket->setSslConfiguration(sslConf);
+#endif
+ QRemoteObjectNode node;
+ node.addClientSideConnection(&socket);
+ node.setHeartbeatInterval(1000);
+ webSocket->open(QStringLiteral("ws://localhost:8088"));
+
+ QTreeView view;
+ view.setWindowTitle(QStringLiteral("RemoteView"));
+ view.resize(640,480);
+ QScopedPointer<QAbstractItemModelReplica> model(node.acquireModel(QStringLiteral("RemoteModel")));
+ view.setModel(model.data());
+ view.show();
+
+ return app.exec();
+}
--- /dev/null
+QT += widgets remoteobjects websockets
+requires(qtConfig(treeview))
+
+SOURCES += main.cpp
+
+include(../common/common.pri)
+
+target.path = $$[QT_INSTALL_EXAMPLES]/remoteobjects/websockets/wsclient
+INSTALLS += target
--- /dev/null
+# Generated from wsserver.pro.
+
+cmake_minimum_required(VERSION 3.16)
+project(wsserver LANGUAGES CXX)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(CMAKE_AUTOMOC ON)
+set(CMAKE_AUTORCC ON)
+set(CMAKE_AUTOUIC ON)
+
+if(NOT DEFINED INSTALL_EXAMPLESDIR)
+ set(INSTALL_EXAMPLESDIR "examples")
+endif()
+
+set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/remoteobjects/websockets/wsserver")
+
+find_package(Qt6 COMPONENTS Core)
+find_package(Qt6 COMPONENTS Gui)
+find_package(Qt6 COMPONENTS Widgets)
+find_package(Qt6 COMPONENTS RemoteObjects)
+find_package(Qt6 COMPONENTS WebSockets)
+
+qt_add_executable(wsserver
+ ../common/websocketiodevice.cpp ../common/websocketiodevice.h
+ main.cpp
+)
+set_target_properties(wsserver PROPERTIES
+ WIN32_EXECUTABLE TRUE
+ MACOSX_BUNDLE FALSE
+)
+target_include_directories(wsserver PUBLIC
+ ../common
+)
+
+target_link_libraries(wsserver PUBLIC
+ Qt::Core
+ Qt::Gui
+ Qt::RemoteObjects
+ Qt::WebSockets
+ Qt::Widgets
+)
+
+
+# Resources:
+set(cert_resource_files
+ "../common/cert/client.crt"
+ "../common/cert/client.key"
+ "../common/cert/rootCA.key"
+ "../common/cert/rootCA.pem"
+ "../common/cert/rootCA.srl"
+ "../common/cert/server.crt"
+ "../common/cert/server.key"
+)
+
+qt6_add_resources(wsserver "cert"
+ PREFIX
+ "/sslcert"
+ BASE
+ "../common/cert"
+ FILES
+ ${cert_resource_files}
+)
+
+install(TARGETS wsserver
+ RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
+ BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
+ LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
+)
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2019 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include <QTreeView>
+#include <QApplication>
+#include <QRemoteObjectNode>
+#include <QTimer>
+#include <QStandardItemModel>
+#include <QStandardItem>
+#include <QWebSocket>
+#include <QWebSocketServer>
+
+#ifndef QT_NO_SSL
+# include <QFile>
+# include <QSslConfiguration>
+# include <QSslKey>
+#endif
+
+#include "websocketiodevice.h"
+
+struct TimerHandler : public QObject
+{
+ Q_OBJECT
+public:
+ QStandardItemModel *model;
+public Q_SLOTS:
+ void changeData() {
+ Q_ASSERT(model);
+ Q_ASSERT(model->rowCount() > 50);
+ Q_ASSERT(model->columnCount() > 1);
+ for (int i = 10; i < 50; ++i)
+ model->setData(model->index(i, 1), QColor(Qt::blue), Qt::BackgroundRole);
+ }
+ void insertData() {
+ Q_ASSERT(model);
+ Q_ASSERT(model->rowCount() > 50);
+ Q_ASSERT(model->columnCount() > 1);
+ model->insertRows(2, 9);
+ for (int i = 2; i < 11; ++i) {
+ model->setData(model->index(i, 1), QColor(Qt::green), Qt::BackgroundRole);
+ model->setData(model->index(i, 1), QLatin1String("InsertedRow"), Qt::DisplayRole);
+ }
+ }
+ void removeData() {
+ model->removeRows(2, 4);
+ }
+
+ void changeFlags() {
+ QStandardItem *item = model->item(0, 0);
+ item->setEnabled(false);
+ item = item->child(0, 0);
+ item->setFlags(item->flags() & Qt::ItemIsSelectable);
+ }
+
+ void moveData() {
+ model->moveRows(QModelIndex(), 2, 4, QModelIndex(), 10);
+ }
+};
+
+QList<QStandardItem*> addChild(int numChildren, int nestingLevel)
+{
+ QList<QStandardItem*> result;
+ if (nestingLevel == 0)
+ return result;
+ for (int i = 0; i < numChildren; ++i) {
+ QStandardItem *child = new QStandardItem(QStringLiteral("Child num %1, nesting Level %2").arg(i+1).arg(nestingLevel));
+ if (i == 0)
+ child->appendRow(addChild(numChildren, nestingLevel -1));
+ result.push_back(child);
+ }
+ return result;
+}
+
+int main(int argc, char *argv[])
+{
+ QLoggingCategory::setFilterRules("qt.remoteobjects.debug=false\n"
+ "qt.remoteobjects.warning=false");
+ QApplication app(argc, argv);
+
+ const int modelSize = 100000;
+ QStringList list;
+ QStandardItemModel sourceModel;
+ QStringList hHeaderList;
+ hHeaderList << QStringLiteral("First Column with spacing") << QStringLiteral("Second Column with spacing");
+ sourceModel.setHorizontalHeaderLabels(hHeaderList);
+ list.reserve(modelSize);
+ for (int i = 0; i < modelSize; ++i) {
+ QStandardItem *firstItem = new QStandardItem(QStringLiteral("FancyTextNumber %1").arg(i));
+ if (i == 0)
+ firstItem->appendRow(addChild(2, 2));
+ QStandardItem *secondItem = new QStandardItem(QStringLiteral("FancyRow2TextNumber %1").arg(i));
+ if (i % 2 == 0)
+ firstItem->setBackground(Qt::red);
+ QList<QStandardItem*> row;
+ row << firstItem << secondItem;
+ sourceModel.invisibleRootItem()->appendRow(row);
+ //sourceModel.appendRow(row);
+ list << QStringLiteral("FancyTextNumber %1").arg(i);
+ }
+
+ // Needed by QMLModelViewClient
+ QHash<int,QByteArray> roleNames = {
+ {Qt::DisplayRole, "_text"},
+ {Qt::BackgroundRole, "_color"}
+ };
+ sourceModel.setItemRoleNames(roleNames);
+
+ QList<int> roles;
+ roles << Qt::DisplayRole << Qt::BackgroundRole;
+
+ QWebSocketServer webSockServer{QStringLiteral("WS QtRO"), QWebSocketServer::NonSecureMode};
+ webSockServer.listen(QHostAddress::Any, 8088);
+
+ QRemoteObjectHost hostNode;
+ hostNode.setHostUrl(webSockServer.serverAddress().toString(), QRemoteObjectHost::AllowExternalRegistration);
+
+ hostNode.enableRemoting(&sourceModel, QStringLiteral("RemoteModel"), roles);
+
+ QObject::connect(&webSockServer, &QWebSocketServer::newConnection, &hostNode, [&hostNode, &webSockServer]{
+ while (auto conn = webSockServer.nextPendingConnection()) {
+#ifndef QT_NO_SSL
+ // Always use secure connections when available
+ QSslConfiguration sslConf;
+ QFile certFile(QStringLiteral(":/sslcert/server.crt"));
+ if (!certFile.open(QIODevice::ReadOnly))
+ qFatal("Can't open client.crt file");
+ sslConf.setLocalCertificate(QSslCertificate{certFile.readAll()});
+
+ QFile keyFile(QStringLiteral(":/sslcert/server.key"));
+ if (!keyFile.open(QIODevice::ReadOnly))
+ qFatal("Can't open client.key file");
+ sslConf.setPrivateKey(QSslKey{keyFile.readAll(), QSsl::Rsa});
+
+ sslConf.setPeerVerifyMode(QSslSocket::VerifyPeer);
+ conn->setSslConfiguration(sslConf);
+ QObject::connect(conn, &QWebSocket::sslErrors, conn, &QWebSocket::deleteLater);
+#endif
+ QObject::connect(conn, &QWebSocket::disconnected, conn, &QWebSocket::deleteLater);
+ QObject::connect(conn, QOverload<QAbstractSocket::SocketError>::of(&QWebSocket::error), conn, &QWebSocket::deleteLater);
+ auto ioDevice = new WebSocketIoDevice(conn);
+ QObject::connect(conn, &QWebSocket::destroyed, ioDevice, &WebSocketIoDevice::deleteLater);
+ hostNode.addHostSideConnection(ioDevice);
+ }
+ });
+
+ QTreeView view;
+ view.setWindowTitle(QStringLiteral("SourceView"));
+ view.setModel(&sourceModel);
+ view.show();
+ TimerHandler handler;
+ handler.model = &sourceModel;
+ QTimer::singleShot(5000, &handler, &TimerHandler::changeData);
+ QTimer::singleShot(10000, &handler, &TimerHandler::insertData);
+ QTimer::singleShot(11000, &handler, &TimerHandler::changeFlags);
+ QTimer::singleShot(12000, &handler, &TimerHandler::removeData);
+ QTimer::singleShot(13000, &handler, &TimerHandler::moveData);
+
+ return app.exec();
+}
+
+#include "main.moc"
--- /dev/null
+QT += widgets remoteobjects websockets
+requires(qtConfig(treeview))
+
+SOURCES += main.cpp
+
+include(../common/common.pri)
+
+target.path = $$[QT_INSTALL_EXAMPLES]/remoteobjects/websockets/wsserver
+INSTALLS += target
--- /dev/null
+#include "../../../../../src/remoteobjects/qconnection_local_backend_p.h"
--- /dev/null
+#include "../../../../../src/remoteobjects/qconnection_qnx_backend_p.h"
--- /dev/null
+#include "../../../../../src/remoteobjects/qconnection_qnx_global_p.h"
--- /dev/null
+#include "../../../../../src/remoteobjects/qconnection_qnx_qiodevices_p.h"
--- /dev/null
+#include "../../../../../src/remoteobjects/qconnection_qnx_server_p.h"
--- /dev/null
+#include "../../../../../src/remoteobjects/qconnection_tcpip_backend_p.h"
--- /dev/null
+#include "../../../../../src/remoteobjects/qconnectionfactories_p.h"
--- /dev/null
+#include "../../../../../src/remoteobjects/qremoteobjectabstractitemmodeladapter_p.h"
--- /dev/null
+#include "../../../../../src/remoteobjects/qremoteobjectabstractitemmodelreplica_p.h"
--- /dev/null
+#include "../../../../../src/remoteobjects/qremoteobjectabstractitemmodeltypes_p.h"
--- /dev/null
+#include "../../../../../src/remoteobjects/qremoteobjectcontainers_p.h"
--- /dev/null
+#include "../../../../../src/remoteobjects/qremoteobjectnode_p.h"
--- /dev/null
+#include "../../../../../src/remoteobjects/qremoteobjectpacket_p.h"
--- /dev/null
+#include "../../../../../src/remoteobjects/qremoteobjectpendingcall_p.h"
--- /dev/null
+#include "../../../../../src/remoteobjects/qremoteobjectregistrysource_p.h"
--- /dev/null
+#include "../../../../../src/remoteobjects/qremoteobjectreplica_p.h"
--- /dev/null
+#include "../../../../../src/remoteobjects/qremoteobjectsource_p.h"
--- /dev/null
+#include "../../../../../src/remoteobjects/qremoteobjectsourceio_p.h"
--- /dev/null
+#include "qremoteobjectabstractitemmodelreplica.h"
--- /dev/null
+#include "qconnectionfactories.h"
--- /dev/null
+#include "qconnection_qnx_qiodevices.h"
--- /dev/null
+#include "qtremoteobjectglobal.h"
--- /dev/null
+#include "qconnection_qnx_qiodevices.h"
--- /dev/null
+#include "qconnection_qnx_server.h"
--- /dev/null
+#include "qremoteobjectnode.h"
--- /dev/null
+#include "qremoteobjectdynamicreplica.h"
--- /dev/null
+#include "qremoteobjectnode.h"
--- /dev/null
+#include "qremoteobjectnode.h"
--- /dev/null
+#include "qremoteobjectnode.h"
--- /dev/null
+#include "qremoteobjectpendingcall.h"
--- /dev/null
+#include "qremoteobjectpendingcall.h"
--- /dev/null
+#include "qremoteobjectpendingcall.h"
--- /dev/null
+#include "qremoteobjectregistry.h"
--- /dev/null
+#include "qremoteobjectnode.h"
--- /dev/null
+#include "qremoteobjectreplica.h"
--- /dev/null
+#include "qremoteobjectsettingsstore.h"
--- /dev/null
+#include "qtremoteobjectglobal.h"
--- /dev/null
+#include "qtremoteobjectglobal.h"
--- /dev/null
+#include "qtremoteobjectglobal.h"
--- /dev/null
+#include "qconnectionfactories.h"
--- /dev/null
+#include "qconnectionfactories.h"
--- /dev/null
+#include "qconnectionfactories.h"
--- /dev/null
+#include "qconnectionfactories.h"
--- /dev/null
+#include "qconnectionfactories.h"
--- /dev/null
+#ifndef QT_QTREMOTEOBJECTS_MODULE_H
+#define QT_QTREMOTEOBJECTS_MODULE_H
+#include <QtRemoteObjects/QtRemoteObjectsDepends>
+#include "qtremoteobjectglobal.h"
+#include "qconnectionfactories.h"
+#include "qremoteobjectabstractitemmodelreplica.h"
+#include "qremoteobjectdynamicreplica.h"
+#include "qremoteobjectnode.h"
+#include "qremoteobjectpendingcall.h"
+#include "qremoteobjectregistry.h"
+#include "qremoteobjectreplica.h"
+#include "qremoteobjectsettingsstore.h"
+#include "qremoteobjectsource.h"
+#include "qtremoteobjectsversion.h"
+#endif
--- /dev/null
+#include "qtremoteobjectsversion.h"
--- /dev/null
+SYNCQT.HEADER_FILES = qconnection_qnx_qiodevices.h qconnection_qnx_server.h qconnectionfactories.h qremoteobjectabstractitemmodelreplica.h qremoteobjectdynamicreplica.h qremoteobjectnode.h qremoteobjectpendingcall.h qremoteobjectregistry.h qremoteobjectreplica.h qremoteobjectsettingsstore.h qremoteobjectsource.h qtremoteobjectglobal.h
+SYNCQT.GENERATED_HEADER_FILES = QQnxNativeIo QIOQnxSource QQnxNativeServer QtROIoDeviceBase QtROServerIoDevice QConnectionAbstractServer QtROClientIoDevice QtROServerFactory QtROClientFactory QAbstractItemModelReplica QRemoteObjectDynamicReplica QRemoteObjectAbstractPersistedStore QRemoteObjectNode QRemoteObjectHostBase QRemoteObjectHost QRemoteObjectRegistryHost QRemoteObjectPendingCall QRemoteObjectPendingCallWatcher QRemoteObjectPendingReply QRemoteObjectRegistry QRemoteObjectReplica QRemoteObjectSettingsStore QRemoteObjectSourceLocationInfo QRemoteObjectSourceLocation QRemoteObjectSourceLocations QIntHash qtremoteobjectsversion.h QtRemoteObjectsVersion QtRemoteObjects
+SYNCQT.PRIVATE_HEADER_FILES = qconnection_local_backend_p.h qconnection_qnx_backend_p.h qconnection_qnx_global_p.h qconnection_qnx_qiodevices_p.h qconnection_qnx_server_p.h qconnection_tcpip_backend_p.h qconnectionfactories_p.h qremoteobjectabstractitemmodeladapter_p.h qremoteobjectabstractitemmodelreplica_p.h qremoteobjectabstractitemmodeltypes_p.h qremoteobjectcontainers_p.h qremoteobjectnode_p.h qremoteobjectpacket_p.h qremoteobjectpendingcall_p.h qremoteobjectregistrysource_p.h qremoteobjectreplica_p.h qremoteobjectsource_p.h qremoteobjectsourceio_p.h
+SYNCQT.QPA_HEADER_FILES =
+SYNCQT.CLEAN_HEADER_FILES = qconnection_qnx_qiodevices.h qconnection_qnx_server.h qconnectionfactories.h qremoteobjectabstractitemmodelreplica.h qremoteobjectdynamicreplica.h qremoteobjectnode.h qremoteobjectpendingcall.h qremoteobjectregistry.h qremoteobjectreplica.h qremoteobjectsettingsstore.h qremoteobjectsource.h qtremoteobjectglobal.h
+SYNCQT.INJECTIONS =
--- /dev/null
+#include "../../src/remoteobjects/qconnection_qnx_qiodevices.h"
--- /dev/null
+#include "../../src/remoteobjects/qconnection_qnx_server.h"
--- /dev/null
+#include "../../src/remoteobjects/qconnectionfactories.h"
--- /dev/null
+#include "../../src/remoteobjects/qremoteobjectabstractitemmodelreplica.h"
--- /dev/null
+#include "../../src/remoteobjects/qremoteobjectdynamicreplica.h"
--- /dev/null
+#include "../../src/remoteobjects/qremoteobjectnode.h"
--- /dev/null
+#include "../../src/remoteobjects/qremoteobjectpendingcall.h"
--- /dev/null
+#include "../../src/remoteobjects/qremoteobjectregistry.h"
--- /dev/null
+#include "../../src/remoteobjects/qremoteobjectreplica.h"
--- /dev/null
+#include "../../src/remoteobjects/qremoteobjectsettingsstore.h"
--- /dev/null
+#include "../../src/remoteobjects/qremoteobjectsource.h"
--- /dev/null
+#include "../../src/remoteobjects/qtremoteobjectglobal.h"
--- /dev/null
+/* This file was generated by syncqt. */
+#ifndef QT_QTREMOTEOBJECTS_VERSION_H
+#define QT_QTREMOTEOBJECTS_VERSION_H
+
+#define QTREMOTEOBJECTS_VERSION_STR "6.2.4"
+
+#define QTREMOTEOBJECTS_VERSION 0x060204
+
+#endif // QT_QTREMOTEOBJECTS_VERSION_H
--- /dev/null
+#include "../../../../../src/remoteobjectsqml/qremoteobjectsqml_p.h"
--- /dev/null
+#ifndef QT_QTREMOTEOBJECTSQML_MODULE_H
+#define QT_QTREMOTEOBJECTSQML_MODULE_H
+#include <QtRemoteObjectsQml/QtRemoteObjectsQmlDepends>
+#include "qtremoteobjectsqmlversion.h"
+#endif
--- /dev/null
+#include "qtremoteobjectsqmlversion.h"
--- /dev/null
+SYNCQT.HEADER_FILES =
+SYNCQT.GENERATED_HEADER_FILES = qtremoteobjectsqmlversion.h QtRemoteObjectsQmlVersion QtRemoteObjectsQml
+SYNCQT.PRIVATE_HEADER_FILES = qremoteobjectsqml_p.h
+SYNCQT.QPA_HEADER_FILES =
+SYNCQT.CLEAN_HEADER_FILES =
+SYNCQT.INJECTIONS =
--- /dev/null
+/* This file was generated by syncqt. */
+#ifndef QT_QTREMOTEOBJECTSQML_VERSION_H
+#define QT_QTREMOTEOBJECTSQML_VERSION_H
+
+#define QTREMOTEOBJECTSQML_VERSION_STR "6.2.4"
+
+#define QTREMOTEOBJECTSQML_VERSION 0x060204
+
+#endif // QT_QTREMOTEOBJECTSQML_VERSION_H
--- /dev/null
+#include "qregexparser.h"
--- /dev/null
+#ifndef QT_QTREPPARSER_MODULE_H
+#define QT_QTREPPARSER_MODULE_H
+#include <QtRepParser/QtRepParserDepends>
+#include "qregexparser.h"
+#include "qtrepparserversion.h"
+#endif
--- /dev/null
+#include "qtrepparserversion.h"
--- /dev/null
+SYNCQT.HEADER_FILES = qregexparser.h
+SYNCQT.GENERATED_HEADER_FILES = QRegexParser qtrepparserversion.h QtRepParserVersion QtRepParser
+SYNCQT.PRIVATE_HEADER_FILES =
+SYNCQT.QPA_HEADER_FILES =
+SYNCQT.CLEAN_HEADER_FILES = qregexparser.h
+SYNCQT.INJECTIONS =
--- /dev/null
+#include "../../src/repparser/qregexparser.h"
--- /dev/null
+/* This file was generated by syncqt. */
+#ifndef QT_QTREPPARSER_VERSION_H
+#define QT_QTREPPARSER_VERSION_H
+
+#define QTREPPARSER_VERSION_STR "6.2.4"
+
+#define QTREPPARSER_VERSION 0x060204
+
+#endif // QT_QTREPPARSER_VERSION_H
--- /dev/null
+TEMPLATE = aux
+
+prf.files = remoteobjects_repc.prf repcclient.pri repcserver.pri repcmerged.pri repccommon.pri repparser.prf
+prf.path = $$[QT_HOST_DATA]/mkspecs/features
+INSTALLS += prf
+
+# Ensure files are copied to qtbase mkspecs for non-prefixed builds
+!force_independent:if(!debug_and_release|!build_all|CONFIG(release, debug|release)) {
+ defineReplace(stripSrcDir) {
+ return($$relative_path($$1, $$_PRO_FILE_PWD_))
+ }
+ prffiles2build.input = prf.files
+ prffiles2build.output = $$[QT_HOST_DATA]/mkspecs/features/${QMAKE_FUNC_FILE_IN_stripSrcDir}
+ prffiles2build.commands = $$QMAKE_COPY ${QMAKE_FILE_IN} ${QMAKE_FILE_OUT}
+ prffiles2build.name = COPY ${QMAKE_FILE_IN}
+ prffiles2build.CONFIG = no_link target_predeps
+ QMAKE_EXTRA_COMPILERS += prffiles2build
+}
--- /dev/null
+include(repcclient.pri)
+include(repcserver.pri)
+include(repcmerged.pri)
+
+!isEmpty(QOBJECT_REP) {
+ qtPrepareLibExecTool(QMAKE_REPC, repc)
+
+ for (path, QT.remoteobjects.includes) {
+ REPC_INCLUDEPATH += -I $$shell_quote($$path)
+ }
+
+ qtPrepareLibExecTool(MOC_CREATE_JSON, moc)
+ moc_json.output = ${QMAKE_FILE_BASE}.json
+ moc_json.CONFIG = no_link moc_verify
+ moc_json.commands = $$MOC_CREATE_JSON -o ${QMAKE_FILE_BASE} ${QMAKE_FILE_NAME} --output-json
+ moc_json.depends = ${QMAKE_FILE_NAME}
+ moc_json.input = QOBJECT_REP
+ moc_json.variable_out = MOC_JSON
+
+ source2rep.input = MOC_JSON
+ source2rep.output = ${QMAKE_FILE_BASE}.rep
+ source2rep.commands = $$QMAKE_REPC $$REPC_INCLUDEPATH -o rep -i json ${QMAKE_FILE_NAME} ${QMAKE_FILE_OUT}
+ source2rep.depends = ${QMAKE_FILE_NAME} $$QT_TOOL.repc.binary
+ source2rep.CONFIG += target_predeps no_link
+ QMAKE_EXTRA_COMPILERS += moc_json source2rep
+}
--- /dev/null
+repc_type = replica
+repc_option = -o replica
+
+include(repccommon.pri)
--- /dev/null
+# Detect repc when QtRO is installed into non-Qt prefix
+cmd = $${QT.remoteobjects.bins}/repc
+contains(QMAKE_HOST.os, Windows) {
+ cmd = $$system_path($${cmd}.exe)
+}
+exists($$cmd): QT_TOOL.repc.binary = $$cmd
+
+# qtPrepareLibExecTool honors QT_TOOL.repc.binary if set
+qtPrepareLibExecTool(QMAKE_REPC, repc)
+
+REPC_INCLUDEPATHES = $$QT.remoteobjects.includes
+for (path, REPC_INCLUDEPATHES) {
+ REPC_INCLUDEPATH += -I $$path
+}
+
+isEmpty(QMAKE_MOD_REPC):QMAKE_MOD_REPC = rep_
+
+repc_TYPE = $$upper($$repc_type)
+
+load(moc)
+
+groups =
+for(entry, REPC_$$repc_TYPE) {
+ files = $$eval($${entry}.files)
+ isEmpty(files) {
+ files = $$entry
+ group = repc_$${repc_type}
+ } else {
+ group = $${entry}_repc_$${repc_type}
+ }
+ groups *= $$group
+
+ input_list = $$upper($$group)_LIST
+ json_list = $$upper($$group)_JSONLIST
+ for(subent, $$list($$unique(files))) {
+ if (contains(subent, .*\\.h$)|contains(subent, .*\\.hpp$)) {
+ $$json_list += $$subent
+ } else {
+ $$input_list += $$subent
+ }
+
+ # Add directory of *.rep file to include path
+ file_path = $$_PRO_FILE_PWD_/$$subent
+ INCLUDEPATH *= $$dirname(file_path)
+ }
+}
+
+for(group, groups) {
+ GROUP = $$upper($$group)
+ input_list = $${GROUP}_LIST
+ json_list = $${GROUP}_JSONLIST
+
+ qtPrepareLibExecTool(MOC_CREATE_JSON, moc)
+ $${group}_moc_json.output = ${QMAKE_FILE_BASE}.json
+ $${group}_moc_json.CONFIG = no_link moc_verify
+ $${group}_moc_json.commands = $$MOC_CREATE_JSON -o ${QMAKE_FILE_BASE} ${QMAKE_FILE_NAME} --output-json
+ $${group}_moc_json.depends = ${QMAKE_FILE_NAME}
+ $${group}_moc_json.input = $$json_list
+ $${group}_moc_json.variable_out = MOC_JSON
+
+ $${group}_header.output = $$QMAKE_MOD_REPC${QMAKE_FILE_BASE}_$${repc_type}.h
+ $${group}_header.commands = $$QMAKE_REPC $$repc_option $$REPC_INCLUDEPATH ${QMAKE_FILE_NAME} ${QMAKE_FILE_OUT}
+ $${group}_header.depends = ${QMAKE_FILE_NAME} $$QT_TOOL.repc.binary
+ $${group}_header.variable_out = $${GROUP}_HEADERS
+ $${group}_header.input = $$input_list MOC_JSON
+
+ $${group}_moc.commands = $$moc_header.commands $$REPC_INCLUDEPATH
+ $${group}_moc.output = $$moc_header.output
+ $${group}_moc.input = $${GROUP}_HEADERS
+ $${group}_moc.variable_out = GENERATED_SOURCES
+ !contains(TEMPLATE, vc.*): \
+ $${group}_moc.name = $$moc_header.name
+
+ QMAKE_EXTRA_COMPILERS += $${group}_moc_json $${group}_header $${group}_moc
+}
--- /dev/null
+repc_type = merged
+repc_option = -o merged
+
+include(repccommon.pri)
--- /dev/null
+repc_type = source
+repc_option = -o source
+
+include(repccommon.pri)
--- /dev/null
+CONFIG += qlalr
+INCLUDEPATH *= $$QT.repparser.includes
+
+for (include, INCLUDEPATH) {
+ exists($${include}/parser.g) {
+ msvc: QMAKE_CXXFLAGS += /wd4129
+ QLALRSOURCES += $${include}/parser.g
+ }
+}
--- /dev/null
+TEMPLATE = subdirs
+
+SUBDIRS += features
--- /dev/null
+
+add_subdirectory(repparser)
+if(QT_FEATURE_localserver)
+ add_subdirectory(remoteobjects)
+endif()
+if(TARGET Qt::Quick)
+ add_subdirectory(remoteobjectsqml)
+endif()
--- /dev/null
+
+#####################################################################
+## RemoteObjects Module:
+#####################################################################
+
+qt_internal_add_module(RemoteObjects
+ QMAKE_MODULE_CONFIG remoteobjects_repc
+ SOURCES
+ qconnection_local_backend.cpp qconnection_local_backend_p.h
+ qconnection_tcpip_backend.cpp qconnection_tcpip_backend_p.h
+ qconnectionfactories.cpp qconnectionfactories.h qconnectionfactories_p.h
+ qremoteobjectabstractitemmodeladapter.cpp qremoteobjectabstractitemmodeladapter_p.h
+ qremoteobjectabstractitemmodelreplica.cpp qremoteobjectabstractitemmodelreplica.h qremoteobjectabstractitemmodelreplica_p.h
+ qremoteobjectabstractitemmodeltypes_p.h
+ qremoteobjectcontainers.cpp qremoteobjectcontainers_p.h
+ qremoteobjectdynamicreplica.cpp qremoteobjectdynamicreplica.h
+ qremoteobjectnode.cpp qremoteobjectnode.h qremoteobjectnode_p.h
+ qremoteobjectpacket.cpp qremoteobjectpacket_p.h
+ qremoteobjectpendingcall.cpp qremoteobjectpendingcall.h qremoteobjectpendingcall_p.h
+ qremoteobjectregistry.cpp qremoteobjectregistry.h
+ qremoteobjectregistrysource.cpp qremoteobjectregistrysource_p.h
+ qremoteobjectreplica.cpp qremoteobjectreplica.h qremoteobjectreplica_p.h
+ qremoteobjectsettingsstore.cpp qremoteobjectsettingsstore.h
+ qremoteobjectsource.cpp qremoteobjectsource.h qremoteobjectsource_p.h
+ qremoteobjectsourceio.cpp qremoteobjectsourceio_p.h
+ qtremoteobjectglobal.cpp qtremoteobjectglobal.h
+ DEFINES
+ QT_BUILD_REMOTEOBJECTS_LIB
+ QT_NO_CAST_FROM_ASCII
+ QT_NO_CAST_FROM_BYTEARRAY
+ QT_NO_CAST_TO_ASCII
+ QT_NO_URL_CAST_FROM_STRING
+ INCLUDE_DIRECTORIES
+ .
+ LIBRARIES
+ Qt::CorePrivate
+ PUBLIC_LIBRARIES
+ Qt::Core
+ Qt::Network
+ PRIVATE_MODULE_INTERFACE
+ Qt::CorePrivate
+)
+
+#### Keys ignored in scope 1:.:.:remoteobjects.pro:<TRUE>:
+# MODULE = "remoteobjects"
+# MODULE_CONFIG = "remoteobjects_repc"
+# OTHER_FILES = "doc/qtremoteobjects.qdocconf" "doc/src/remoteobjects-cpp.qdoc" "doc/src/remoteobjects-index.qdoc" "doc/src/remoteobjects-overview.qdoc" "doc/src/remoteobjects-repc.qdoc"
+
+## Scopes:
+#####################################################################
+
+qt_internal_extend_target(RemoteObjects CONDITION QNX
+ SOURCES
+ qconnection_qnx_backend.cpp qconnection_qnx_backend_p.h
+ qconnection_qnx_global_p.h
+ qconnection_qnx_qiodevices.cpp qconnection_qnx_qiodevices.h qconnection_qnx_qiodevices_p.h
+ qconnection_qnx_server.cpp qconnection_qnx_server.h qconnection_qnx_server_p.h
+)
+
+qt_internal_extend_target(RemoteObjects CONDITION QNX AND QT_FEATURE_use_ham
+ PUBLIC_LIBRARIES
+ ham
+)
+qt_internal_add_docs(RemoteObjects
+ doc/qtremoteobjects.qdocconf
+)
+
+include(Qt6RemoteObjectsMacros.cmake)
--- /dev/null
+#
+# Copyright (C) 2015 Ford Motor Company
+# Contact: https://www.qt.io/licensing/
+#
+# This file is part of the QtRemoteObjects module of the Qt Toolkit.
+#
+# $QT_BEGIN_LICENSE:LGPL$
+# Commercial License Usage
+# Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+# and conditions see https://www.qt.io/terms-conditions. For further
+# information use the contact form at https://www.qt.io/contact-us.
+#
+# 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.LGPL3 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.
+#
+# GNU General Public License Usage
+# Alternatively, this file may be used under the terms of the GNU
+# General Public License version 2.0 or (at your option) the GNU General
+# Public license version 3 or any later version approved by the KDE Free
+# Qt Foundation. The licenses are as published by the Free Software
+# Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+# included in the packaging of this file. Please review the following
+# information to ensure the GNU General Public License requirements will
+# be met: https://www.gnu.org/licenses/gpl-2.0.html and
+# https://www.gnu.org/licenses/gpl-3.0.html.
+#
+# $QT_END_LICENSE$
+
+if (NOT TARGET Qt5::repc)
+ add_executable(Qt5::repc IMPORTED)
+
+!!IF isEmpty(CMAKE_BIN_DIR_IS_ABSOLUTE)
+ set(imported_location \"${_qt5RemoteObjects_install_prefix}/$${CMAKE_BIN_DIR}repc$$CMAKE_BIN_SUFFIX\")
+!!ELSE
+ set(imported_location \"$${CMAKE_BIN_DIR}repc$$CMAKE_BIN_SUFFIX\")
+!!ENDIF
+ _qt5_RemoteObjects_check_file_exists(${imported_location})
+
+ set_target_properties(Qt5::repc PROPERTIES
+ IMPORTED_LOCATION ${imported_location}
+ )
+ get_target_property(Qt5RemoteObjects_REPC_EXECUTABLE Qt5::repc LOCATION)
+endif()
+
+# Create versionless tool targets.
+foreach(__qt_tool repc)
+ if(NOT \"${QT_NO_CREATE_VERSIONLESS_TARGETS}\" AND NOT TARGET Qt::${__qt_tool}
+ AND TARGET Qt5::${__qt_tool})
+ add_executable(Qt::${__qt_tool} IMPORTED)
+ get_target_property(__qt_imported_location Qt5::${__qt_tool} IMPORTED_LOCATION)
+ set_target_properties(Qt::${__qt_tool}
+ PROPERTIES IMPORTED_LOCATION \"${__qt_imported_location}\")
+ endif()
+endforeach()
--- /dev/null
+#
+# Copyright (C) 2019 The Qt Company Ltd.
+# Contact: https://www.qt.io/licensing/
+#
+# This file is part of the QtRepc module of the Qt Toolkit.
+#
+# $QT_BEGIN_LICENSE:LGPL$
+# Commercial License Usage
+# Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+# and conditions see https://www.qt.io/terms-conditions. For further
+# information use the contact form at https://www.qt.io/contact-us.
+#
+# 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.LGPL3 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.
+#
+# GNU General Public License Usage
+# Alternatively, this file may be used under the terms of the GNU
+# General Public License version 2.0 or (at your option) the GNU General
+# Public license version 3 or any later version approved by the KDE Free
+# Qt Foundation. The licenses are as published by the Free Software
+# Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+# included in the packaging of this file. Please review the following
+# information to ensure the GNU General Public License requirements will
+# be met: https://www.gnu.org/licenses/gpl-2.0.html and
+# https://www.gnu.org/licenses/gpl-3.0.html.
+#
+# $QT_END_LICENSE$
+
+# With a macOS framework Qt build, moc needs to be passed -F<framework-path> arguments to resolve
+# framework style includes like #include <QtCore/qobject.h>
+# Extract the location of the Qt frameworks by querying the imported location of QtRemoteObjects
+# framework parent directory.
+function(_qt_internal_get_remote_objects_framework_path out_var)
+ set(value "")
+ if(APPLE AND QT_FEATURE_framework)
+ get_target_property(ro_path ${QT_CMAKE_EXPORT_NAMESPACE}::RemoteObjects IMPORTED_LOCATION)
+ string(REGEX REPLACE "(.*)/Qt[^/]+\\.framework.*" "\\1" ro_fw_path "${ro_path}")
+ if(ro_fw_path)
+ set(value "${ro_fw_path}")
+ endif()
+ endif()
+ set(${out_var} "${value}" PARENT_SCOPE)
+endfunction()
+
+function(_qt_internal_get_remote_objects_framework_path_moc_options out_var)
+ _qt_internal_get_remote_objects_framework_path(ro_fw_path)
+ if(ro_fw_path)
+ set(${out_var} "OPTIONS" "-F${ro_fw_path}" PARENT_SCOPE)
+ else()
+ set(${out_var} "" PARENT_SCOPE)
+ endif()
+endfunction()
+
+function(_qt_internal_add_repc_files type target)
+ set(options)
+ set(oneValueArgs)
+ set(multiValueArgs SOURCES)
+
+ cmake_parse_arguments(ARGS "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
+
+ set(outfiles)
+ if(QT_REPC_DEBUG_MODE)
+ set(debug "-d")
+ else()
+ set(debug "")
+ endif()
+ set(repc_incpath) ########### TODO
+
+ _qt_internal_get_remote_objects_framework_path_moc_options(extra_moc_options)
+ foreach(it ${ARGS_SOURCES})
+ get_filename_component(outfilename ${it} NAME_WE)
+ get_filename_component(extension ${it} EXT)
+ if ("${extension}" STREQUAL ".h" OR "${extension}" STREQUAL ".hpp")
+ # This calls moc on an existing header file to extract metatypes json information
+ # which is then passed to the tool to generate another header.
+ qt6_wrap_cpp(qtro_moc_files "${it}"
+ __QT_INTERNAL_OUTPUT_MOC_JSON_FILES json_list
+ TARGET "${target}"
+ ${extra_moc_options})
+
+ # Pass the generated metatypes .json file to the tool.
+ set(infile ${json_list})
+ set_source_files_properties(${qtro_moc_files} PROPERTIES HEADER_FILE_ONLY ON)
+ list(APPEND outfiles ${qtro_moc_files})
+ else()
+ # Pass the .rep file to the tool.
+ get_filename_component(infile ${it} ABSOLUTE)
+ endif()
+ set(outfile ${CMAKE_CURRENT_BINARY_DIR}/rep_${outfilename}_${type}.h)
+
+ add_custom_command(
+ OUTPUT ${outfile}
+ ${QT_TOOL_PATH_SETUP_COMMAND}
+ COMMAND
+ ${QT_CMAKE_EXPORT_NAMESPACE}::repc
+ ${debug} -o ${type} ${repc_incpath} ${infile} ${outfile}
+ MAIN_DEPENDENCY ${infile}
+ DEPENDS ${QT_CMAKE_EXPORT_NAMESPACE}::repc
+ VERBATIM
+ )
+ list(APPEND outfiles ${outfile})
+
+ # The generated header file needs to be manually moc'ed (without using AUTOMOC) and then
+ # added as source to compile into the target.
+ qt6_wrap_cpp(qtro_moc_files "${outfile}" TARGET "${target}" ${extra_moc_options})
+ set_source_files_properties("${outfile}" PROPERTIES
+ GENERATED TRUE
+ SKIP_AUTOGEN ON)
+ list(APPEND outfiles ${qtro_moc_files})
+ endforeach()
+ target_sources(${target} PRIVATE ${outfiles})
+endfunction()
+
+# Add .rep source files to a target to generate source header files
+function(qt6_add_repc_sources target)
+ list(POP_FRONT ARGV)
+ _qt_internal_add_repc_files(source ${target} SOURCES ${ARGV})
+endfunction()
+
+# Add .rep source files to a target to generate replica header files
+function(qt6_add_repc_replicas target)
+ list(POP_FRONT ARGV)
+ _qt_internal_add_repc_files(replica ${target} SOURCES ${ARGV})
+endfunction()
+
+# Add .rep source files to a target to generate combined (source and replica) header files
+function(qt6_add_repc_merged target)
+ list(POP_FRONT ARGV)
+ _qt_internal_add_repc_files(merged ${target} SOURCES ${ARGV})
+endfunction()
+
+# Create .rep interface file from QObject header
+function(qt6_reps_from_headers target)
+ list(POP_FRONT ARGV)
+ _qt_internal_get_remote_objects_framework_path_moc_options(extra_moc_options)
+
+ foreach(it ${ARGV})
+ get_filename_component(outfilename ${it} NAME_WE)
+ # This calls moc on an existing header file to extract metatypes json information
+ # which is then passed to the tool to generate a .rep file.
+ qt6_wrap_cpp(qtro_moc_files "${it}"
+ __QT_INTERNAL_OUTPUT_MOC_JSON_FILES json_list
+ TARGET "${target}"
+ ${extra_moc_options})
+ set(infile ${json_list})
+ set_source_files_properties(${qtro_moc_files} PROPERTIES HEADER_FILE_ONLY ON)
+ list(APPEND outfiles ${qtro_moc_files})
+ set(outfile ${CMAKE_CURRENT_BINARY_DIR}/${outfilename}.rep)
+ add_custom_command(OUTPUT ${outfile}
+ ${QT_TOOL_PATH_SETUP_COMMAND}
+ COMMAND ${QT_CMAKE_EXPORT_NAMESPACE}::repc
+ -o rep ${infile} ${outfile}
+ MAIN_DEPENDENCY ${infile}
+ VERBATIM)
+ list(APPEND outfiles ${outfile})
+ endforeach()
+ target_sources(${target} PRIVATE ${outfiles})
+endfunction()
+
+if(NOT QT_NO_CREATE_VERSIONLESS_FUNCTIONS)
+ function(qt_add_repc_sources)
+ if(QT_DEFAULT_MAJOR_VERSION EQUAL 6)
+ qt6_add_repc_sources(${ARGN})
+ else()
+ message(FATAL_ERROR "qt_add_repc_sources() is only available in Qt 6. "
+ "Please check the repc documentation for alternatives.")
+ endif()
+ endfunction()
+ function(qt_add_repc_replicas)
+ if(QT_DEFAULT_MAJOR_VERSION EQUAL 6)
+ qt6_add_repc_replicas(${ARGN})
+ else()
+ message(FATAL_ERROR "qt_add_repc_replicas() is only available in Qt 6. "
+ "Please check the repc documentation for alternatives.")
+ endif()
+ endfunction()
+ function(qt_add_repc_merged)
+ if(QT_DEFAULT_MAJOR_VERSION EQUAL 6)
+ qt6_add_repc_merged(${ARGN})
+ else()
+ message(FATAL_ERROR "qt_add_repc_merged() is only available in Qt 6. "
+ "Please check the repc documentation for alternatives.")
+ endif()
+ endfunction()
+ function(qt_reps_from_headers)
+ if(QT_DEFAULT_MAJOR_VERSION EQUAL 6)
+ qt6_reps_from_headers(${ARGN})
+ else()
+ message(FATAL_ERROR "qt_reps_from_headers() is only available in Qt 6. "
+ "Please check the repc documentation for alternatives.")
+ endif()
+ endfunction()
+endif()
--- /dev/null
+
+
+#### Inputs
+
+
+
+#### Libraries
+
+
+
+#### Tests
+
+
+
+#### Features
+
+qt_feature("use_ham" PUBLIC
+ LABEL "High Availability Manager (ham)"
+ PURPOSE "Use QNX's High Availability Manager (ham) library"
+ AUTODETECT OFF
+ CONDITION QNX
+)
+qt_feature_definition("use_ham" "QT_NO_USE_HAM" NEGATE VALUE "1")
+qt_configure_add_summary_section(NAME "Qt Remote Objects")
+qt_configure_add_summary_entry(ARGS "use_ham")
+qt_configure_end_summary_section() # end of "Qt Remote Objects" section
--- /dev/null
+Put all documentation images into this folder.
--- /dev/null
+include($QT_INSTALL_DOCS/global/qt-module-defaults.qdocconf)
+include($QT_INSTALL_DOCS/config/exampleurl-qtremoteobjects.qdocconf)
+
+project = QtRemoteObjects
+description = Qt Remote Objects Reference Documentation
+version = $QT_VERSION
+
+qhp.projects = QtRemoteObjects
+
+qhp.QtRemoteObjects.file = qtremoteobjects.qhp
+qhp.QtRemoteObjects.namespace = org.qt-project.qtremoteobjects.$QT_VERSION_TAG
+qhp.QtRemoteObjects.virtualFolder = remoteobjects
+qhp.QtRemoteObjects.indexTitle = Qt Remote Objects
+qhp.QtRemoteObjects.indexRoot =
+
+qhp.QtRemoteObjects.filterAttributes = qtremoteobjects $QT_VERSION qtrefdoc
+qhp.QtRemoteObjects.customFilters.Qt.name = QtRemoteObjects $QT_VERSION
+qhp.QtRemoteObjects.customFilters.Qt.filterAttributes = qtremoteobjects $QT_VERSION
+qhp.QtRemoteObjects.subprojects = overviews classes repc
+qhp.QtRemoteObjects.subprojects.overviews.title = Getting Started
+qhp.QtRemoteObjects.subprojects.overviews.indexTitle = Getting Started with Qt Remote Objects
+qhp.QtRemoteObjects.subprojects.overviews.selectors = fake:page,group,module
+qhp.QtRemoteObjects.subprojects.classes.title = C++ Classes
+qhp.QtRemoteObjects.subprojects.classes.indexTitle = Qt Remote Objects C++ Classes
+qhp.QtRemoteObjects.subprojects.classes.selectors = class fake:headerfile
+qhp.QtRemoteObjects.subprojects.classes.sortPages = true
+
+depends += qtcore \
+ qtnetwork \
+ qtdoc \
+ qtcmake \
+ qmake
+
+tagfile = ../../../doc/qtremoteobjects/qtremoteobjects.tags
+
+headerdirs += .. \
+ ../../remoteobjects
+
+sourcedirs += .. \
+ ../../remoteobjects
+
+exampledirs += ../../../examples/remoteobjects \
+ snippets/
+
+#add thumbnail images for the example docs that does not have an image.
+manifestmeta.thumbnail.names += "QtRemoteObjects/Model*" \
+ "QtRemoteObjects/QML*" \
+ "QtRemoteObjects/QtRemote*"
+
+
+examplesinstallpath = remoteobjects
+
+imagedirs += images
+
+navigation.landingpage = "Qt Remote Objects"
+navigation.cppclassespage = "Qt Remote Objects C++ Classes"
+navigation.qmltypespage = "Qt Remote Objects QML Types"
--- /dev/null
+Put all snipplets into this folder.
--- /dev/null
+cmake_minimum_required(VERSION 3.16)
+
+project(directconnectserver)
+
+set(CMAKE_AUTOMOC ON)
+set(CMAKE_AUTORCC ON)
+set(CMAKE_AUTOUIC ON)
+
+if(CMAKE_VERSION VERSION_LESS "3.7.0")
+ set(CMAKE_INCLUDE_CURRENT_DIR ON)
+endif()
+
+#! [remote_objects_cmake]
+find_package(Qt6 COMPONENTS RemoteObjects REQUIRED)
+#! [remote_objects_cmake]
+
+set(SOURCES
+ main.cpp
+ simpleswitch.cpp
+)
+
+#! [simpleSwitch_cmake_add_repc_source]
+qt6_add_repc_sources(directconnectserver
+ simpleswitch.rep
+)
+#! [simpleSwitch_cmake_add_repc_source]
+
+#! [simpleSwitch_cmake_add_repc_replica]
+qt6_add_repc_replicas(directconnectclient
+ simpleswitch.rep
+)
+#! [simpleSwitch_cmake_add_repc_replica]
+
+#! [simpleSwitch_cmake_add_repc_merged]
+qt6_add_repc_merged(directconnectexample
+ simpleswitch.rep
+)
+#! [simpleSwitch_cmake_add_repc_merged]
+
+add_executable(directconnectserver ${SOURCES})
+#! [remote_objects_cmake_link]
+target_link_libraries(directconnectserver PRIVATE Qt6::RemoteObjects)
+#! [remote_objects_cmake_link]
+
+#! [simpleSwitch_cmake_rep_from_header]
+qt6_reps_from_headers(directconnectexample
+ simpleswitch.h
+)
+#! [simpleSwitch_cmake_rep_from_header]
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QCoreApplication>
+#include "simpleswitch.h"
+
+int main(int argc, char *argv[])
+{
+ QCoreApplication a(argc, argv);
+
+ SimpleSwitch srcSwitch; // create simple switch
+
+ QRemoteObjectHost srcNode(QUrl(QStringLiteral("local:replica"))); // create host node without Registry
+ srcNode.enableRemoting(&srcSwitch); // enable remoting/Sharing
+
+ return a.exec();
+}
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "simpleswitch.h"
+
+// constructor
+SimpleSwitch::SimpleSwitch(QObject *parent) : SimpleSwitchSimpleSource(parent)
+{
+ stateChangeTimer = new QTimer(this); // Initialize timer
+ QObject::connect(stateChangeTimer, &SimpleSwitch::timeout, this, &SimpleSwitch::timeout_slot); // connect timeout() signal from stateChangeTimer to timeout_slot() of simpleSwitch
+ stateChangeTimer->start(2000); // Start timer and set timout to 2 seconds
+ qDebug() << "Source Node Started";
+}
+
+//destructor
+SimpleSwitch::~SimpleSwitch()
+{
+ stateChangeTimer->stop();
+}
+
+void SimpleSwitch::server_slot(bool clientState)
+{
+ qDebug() << "Replica state is " << clientState; // print switch state echoed back by client
+}
+
+void SimpleSwitch::timeout_slot(void)
+{
+ // slot called on timer timeout
+ if (currState()) // check if current state is true, currState() is defined in repc generated rep_simpleswitch_source.h
+ setCurrState(false); // set state to false
+ else
+ setCurrState(true); // set state to true
+ qDebug() << "Source State is "<<currState();
+
+}
+
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef SIMPLESWITCH_H
+#define SIMPLESWITCH_H
+
+#include "rep_simpleswitch_source.h"
+
+class SimpleSwitch : public SimpleSwitchSimpleSource
+{
+ Q_OBJECT
+public:
+ SimpleSwitch(QObject *parent = nullptr);
+ ~SimpleSwitch() override;
+ void server_slot(bool clientState) override;
+public Q_SLOTS:
+ void timeout_slot();
+private:
+ QTimer *stateChangeTimer;
+};
+
+#endif
--- /dev/null
+#include <QtCore>
+
+class SimpleSwitch
+{
+ PROP(bool currState=false);
+ SLOT(void server_slot(bool clientState));
+};
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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.LGPL3 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//! [qtremoteobject_include]
+#include <QtRemoteObjects>
+//! [qtremoteobject_include]
+
+//! [implementing_source]
+#include "rep_TimeModel_source.h"
+
+class MinuteTimer : public MinuteTimerSource
+{
+Q_OBJECT
+public:
+ MinuteTimer(QObject *parent = nullptr);
+ virtual ~MinuteTimer();
+
+public slots:
+ virtual void SetTimeZone(int zn) { //this is a pure virtual method in MinuteTimerSource
+ qDebug()<<"SetTimeZone"<<zn;
+ if (zn != zone) {
+ zone = zn;
+ }
+ };
+
+protected:
+ void timerEvent(QTimerEvent *);
+
+private:
+ QTime time;
+ QBasicTimer timer;
+ int zone;
+};
+//! [implementing_source]
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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.LGPL3 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//! [simpleSwitch_rep]
+class SimpleSwitch
+{
+ PROP(bool currState=false);
+ SLOT(server_slot(bool clientState));
+};
+//! [simpleSwitch_rep]
+
+//! [simpleSwitch_repsource_example1]
+REPC_SOURCE = simpleswitch.rep
+//! [simpleSwitch_repsource_example1]
+
+//! [simpleSwitch_remoteobjectsadd_example1]
+QT += remoteobjects
+//! [simpleSwitch_remoteobjectsadd_example1]
+
+//! [simpleSwitch_serverheader_example1]
+#ifndef SIMPLESWITCH_H
+#define SIMPLESWITCH_H
+
+#include "rep_simpleswitch_source.h"
+
+class SimpleSwitch : public SimpleSwitchSimpleSource
+{
+ Q_OBJECT
+public:
+ SimpleSwitch(QObject *parent = nullptr);
+ ~SimpleSwitch();
+ virtual void server_slot(bool clientState);
+public Q_SLOTS:
+ void timeout_slot();
+private:
+ QTimer *stateChangeTimer;
+};
+
+#endif
+//! [simpleSwitch_serverheader_example1]
+
+//! [simpleSwitch_serversource_example1]
+#include "simpleswitch.h"
+
+// constructor
+SimpleSwitch::SimpleSwitch(QObject *parent) : SimpleSwitchSimpleSource(parent)
+{
+ stateChangeTimer = new QTimer(this); // Initialize timer
+ QObject::connect(stateChangeTimer, &SimpleSwitch::timeout, this, &SimpleSwitch::timeout_slot); // connect timeout() signal from stateChangeTimer to timeout_slot() of simpleSwitch
+ stateChangeTimer->start(2000); // Start timer and set timout to 2 seconds
+ qDebug() << "Source Node Started";
+}
+
+//destructor
+SimpleSwitch::~SimpleSwitch()
+{
+ stateChangeTimer->stop();
+}
+
+void SimpleSwitch::server_slot(bool clientState)
+{
+ qDebug() << "Replica state is " << clientState; // print switch state echoed back by client
+}
+
+void SimpleSwitch::timeout_slot()
+{
+ // slot called on timer timeout
+ if (currState()) // check if current state is true, currState() is defined in repc generated rep_simpleswitch_source.h
+ setCurrState(false); // set state to false
+ else
+ setCurrState(true); // set state to true
+ qDebug() << "Source State is "<<currState();
+
+}
+//! [simpleSwitch_serversource_example1]
+
+//! [simpleSwitch_serverhostnode_example1]
+QRemoteObjectHost srcNode(QUrl(QStringLiteral("local:switch")));
+//! [simpleSwitch_serverhostnode_example1]
+
+//! [simpleSwitch_enableremoting_example1]
+SimpleSwitch srcSwitch; // create simple switch
+srcNode.enableRemoting(&srcSwitch); // enable remoting
+//! [simpleSwitch_enableremoting_example1]
+
+//! [simpleSwitch_servermaincpp_example1]
+#include <QCoreApplication>
+#include "simpleswitch.h"
+
+int main(int argc, char *argv[])
+{
+ QCoreApplication a(argc, argv);
+
+ SimpleSwitch srcSwitch; // create simple switch
+
+ QRemoteObjectHost srcNode(QUrl(QStringLiteral("local:switch"))); // create host node without Registry
+ srcNode.enableRemoting(&srcSwitch); // enable remoting/sharing
+
+ return a.exec();
+}
+//! [simpleSwitch_servermaincpp_example1]
+
+//! [simpleSwitch_clientrep_example1]
+REPC_REPLICA = simpleswitch.rep
+//! [simpleSwitch_clientrep_example1]
+
+//! [simpleSwitch_clientremotenode_example1]
+QRemoteObjectNode repNode; // create remote object node
+repNode.connectToNode(QUrl(QStringLiteral("local:switch"))); // connect with remote host node
+ //! [simpleSwitch_clientremotenode_example1]
+
+ //! [simpleSwitch_clientacquirereplica_example1]
+QSharedPointer<SimpleSwitchReplica> ptr;
+ptr.reset(repNode.acquire<SimpleSwitchReplica>()); // acquire replica of source from host node
+//! [simpleSwitch_clientacquirereplica_example1]
+
+//! [simpleSwitch_clientheader_example1]
+#ifndef _CLIENT_H
+#define _CLIENT_H
+
+#include <QObject>
+#include <QSharedPointer>
+
+#include "rep_simpleswitch_replica.h"
+
+class Client : public QObject
+{
+ Q_OBJECT
+public:
+ Client(QSharedPointer<SimpleSwitchReplica> ptr);
+ ~Client();
+ void initConnections();// Function to connect signals and slots of source and client
+
+Q_SIGNALS:
+ void echoSwitchState(bool switchState);// this signal is connected with server_slot(..) on the source object and echoes back switch state received from source
+
+public Q_SLOTS:
+ void recSwitchState_slot(); // slot to receive source state
+private:
+ bool clientSwitchState; // holds received server switch state
+ QSharedPointer<SimpleSwitchReplica> reptr;// holds reference to replica
+
+ };
+
+#endif
+//! [simpleSwitch_clientheader_example1]
+
+//! [simpleSwitch_clientcpp_example1]
+#include "client.h"
+
+// constructor
+Client::Client(QSharedPointer<SimpleSwitchReplica> ptr) :
+ QObject(nullptr),reptr(ptr)
+{
+ initConnections();
+ //We can connect to SimpleSwitchReplica Signals/Slots
+ //directly because our Replica was generated by repc.
+}
+
+//destructor
+Client::~Client()
+{
+}
+
+void Client::initConnections()
+{
+ // initialize connections between signals and slots
+
+ // connect source replica signal currStateChanged() with client's recSwitchState() slot to receive source's current state
+ QObject::connect(reptr.data(), &SimpleSwitchReplica::currStateChanged, this, &Client::recSwitchState_slot);
+ // connect client's echoSwitchState(..) signal with replica's server_slot(..) to echo back received state
+ QObject::connect(this, &Client::echoSwitchState, reptr.data(), &SimpleSwitchReplica::server_slot);
+}
+
+void Client::recSwitchState_slot(bool value)
+{
+ qDebug() << "Received source state "<< value << reptr.data()->currState();
+ clientSwitchState = reptr.data()->currState();
+ Q_EMIT echoSwitchState(clientSwitchState); // Emit signal to echo received state back to server
+}
+//! [simpleSwitch_clientcpp_example1]
+
+//! [simpleSwitch_clientmain_example1]
+#include <QCoreApplication>
+#include "client.h"
+
+int main(int argc, char *argv[])
+{
+ QCoreApplication a(argc, argv);
+
+
+ QSharedPointer<SimpleSwitchReplica> ptr; // shared pointer to hold source replica
+
+ QRemoteObjectNode repNode; // create remote object node
+ repNode.connectToNode(QUrl(QStringLiteral("local:switch"))); // connect with remote host node
+
+ ptr.reset(repNode.acquire<SimpleSwitchReplica>()); // acquire replica of source from host node
+
+ Client rswitch(ptr); // create client switch object and pass reference of replica to it
+
+ return a.exec();
+}
+//! [simpleSwitch_clientmain_example1]
+
+//! [simpleSwitch_dynamicclientnode_example2]
+QRemoteObjectNode repNode; // create remote object node
+repNode.connectToNode(QUrl(QStringLiteral("local:switch"))); // connect with remote host node
+//! [simpleSwitch_dynamicclientnode_example2]
+
+//! [simpleSwitch_dynamicclientacquirereplica_example2]
+QSharedPointer<QRemoteObjectDynamicReplica> ptr; // shared pointer to hold replica
+ptr.reset(repNode.acquire("SimpleSwitch")); // acquire replica of source from host node
+//! [simpleSwitch_dynamicclientacquirereplica_example2]
+
+//! [simpleSwitch_dynamicclientheader_example2]
+#ifndef _DYNAMICCLIENT_H
+#define _DYNAMICCLIENT_H
+
+#include <QObject>
+#include <QSharedPointer>
+
+#include <QRemoteObjectNode>
+#include <qremoteobjectdynamicreplica.h>
+
+class DynamicClient : public QObject
+{
+ Q_OBJECT
+public:
+ DynamicClient(QSharedPointer<QRemoteObjectDynamicReplica> ptr);
+ ~DynamicClient();
+
+Q_SIGNALS:
+ void echoSwitchState(bool switchState);// this signal is connected with server_slot(..) slot of source object and echoes back switch state received from source
+
+public Q_SLOTS:
+ void recSwitchState_slot(); // Slot to receive source state
+ void initConnection_slot(); //Slot to connect signals/slot on replica initialization
+
+private:
+ bool clientSwitchState; // holds received server switch state
+ QSharedPointer<QRemoteObjectDynamicReplica> reptr;// holds reference to replica
+ };
+
+#endif
+//! [simpleSwitch_dynamicclientheader_example2]
+
+//! [simpleSwitch_dynamicclientcpp_example2]
+#include "dynamicclient.h"
+
+// constructor
+DynamicClient::DynamicClient(QSharedPointer<QRemoteObjectDynamicReplica> ptr) :
+ QObject(nullptr), reptr(ptr)
+{
+
+ //connect signal for replica valid changed with signal slot initialization
+ QObject::connect(reptr.data(), &QRemoteObjectDynamicReplica::initialized, this,
+ &DynamicClient::initConnection_slot);
+}
+
+//destructor
+DynamicClient::~DynamicClient()
+{
+}
+
+// Function to initialize connections between slots and signals
+void DynamicClient::initConnection_slot()
+{
+
+ // connect source replica signal currStateChanged() with client's recSwitchState() slot to receive source's current state
+ QObject::connect(reptr.data(), SIGNAL(currStateChanged()), this, SLOT(recSwitchState_slot()));
+ // connect client's echoSwitchState(..) signal with replica's server_slot(..) to echo back received state
+ QObject::connect(this, SIGNAL(echoSwitchState(bool)),reptr.data(), SLOT(server_slot(bool)));
+}
+
+void DynamicClient::recSwitchState_slot()
+{
+ clientSwitchState = reptr->property("currState").toBool(); // use replica property to get currState from source
+ qDebug() << "Received source state " << clientSwitchState;
+ Q_EMIT echoSwitchState(clientSwitchState); // Emit signal to echo received state back to server
+}
+
+//! [simpleSwitch_dynamicclientcpp_example2]
+
+//! [simpleSwitch_dynamicclientmaincpp_example2]
+#include <QCoreApplication>
+
+#include "dynamicclient.h"
+
+int main(int argc, char *argv[])
+{
+ QCoreApplication a(argc, argv);
+
+ QSharedPointer<QRemoteObjectDynamicReplica> ptr; // shared pointer to hold replica
+
+ QRemoteObjectNode repNode;
+ repNode.connectToNode(QUrl(QStringLiteral("local:switch")));
+
+ ptr.reset(repNode.acquireDynamic("SimpleSwitch")); // acquire replica of source from host node
+
+ DynamicClient rswitch(ptr); // create client switch object and pass replica reference to it
+}
+//! [simpleSwitch_dynamicclientmaincpp_example2]
+
+//! [simpleSwitch_registrymaincpp_example3]
+#include <QCoreApplication>
+#include "simpleswitch.h"
+
+int main(int argc, char *argv[])
+{
+ QCoreApplication a(argc, argv);
+
+ SimpleSwitch srcSwitch; // create SimpleSwitch
+
+ QRemoteObjectRegistryHost regNode(QUrl(QStringLiteral("local:registry"))); // create node that hosts registry
+ QRemoteObjectHost srcNode(QUrl(QStringLiteral("local:switch")), QUrl(QStringLiteral("local:registry"))); // create node that will host source and connect to registry
+ //Note, you can add srcSwitch directly to regNode if desired.
+ //We use two Nodes here, as the regNode could easily be in a third process.
+
+ srcNode.enableRemoting(&srcSwitch); // enable remoting of source object
+
+ return a.exec();
+}
+//! [simpleSwitch_registrymaincpp_example3]
+
+//! [simpleSwitch_registrydynamicclientmaincpp_example3]
+ QRemoteObjectNode repNode(QUrl(QStringLiteral("local:registry")));
+//! [simpleSwitch_registrydynamicclientmaincpp_example3]
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+\page qtremoteobjects-cmake-qt-add-repc-replicas.html
+\ingroup cmake-macros-qtremoteobjects
+
+\title qt_add_repc_replicas
+\target qt6_add_repc_replicas
+
+\brief Creates C++ header files for replica types from the Qt Remote Objects .rep files.
+
+\cmakecommandsince 6.2
+
+\section1 Synopsis
+
+\badcode
+qt_add_repc_replicas(<TARGET> rep_files)
+
+qt6_add_repc_replicas(<TARGET> rep_files)
+\endcode
+
+\section1 Description
+
+Runs \l repc and generates \l {Qt Remote Objects Replica} header files based
+on the given \c rep_files. Adds the generated files to \c{<TARGET>}.
+
+\section1 Examples
+
+\snippet cmake-macros/CMakeLists.txt simpleSwitch_cmake_add_repc_replica
+
+The generated file(s) will be of the form \c {rep_<replica file name>_replica.h},
+in this case \c rep_simpleswitch_replica.h
+*/
+
+/*!
+\page qtremoteobjects-cmake-qt-add-repc-sources.html
+\ingroup cmake-macros-qtremoteobjects
+
+\title qt_add_repc_sources
+\target qt6_add_repc_sources
+
+\brief Creates C++ header files for source types from the Qt Remote Objects .rep files.
+
+\cmakecommandsince 6.2
+
+\section1 Synopsis
+
+\badcode
+qt_add_repc_sources(<TARGET> rep_files)
+
+qt6_add_repc_sources(<TARGET> rep_files)
+\endcode
+
+\section1 Description
+
+Runs \l repc and generates \l {Qt Remote Objects Source} header files based
+on the given \c rep_files. Adds the generated files to \c{<TARGET>}.
+
+\section1 Examples
+
+\snippet cmake-macros/CMakeLists.txt simpleSwitch_cmake_add_repc_source
+
+The generated file(s) will be of the form \c {rep_<replica file name>_source.h},
+in this case \c rep_simpleswitch_source.h
+*/
+
+/*!
+\page qtremoteobjects-cmake-qt-add-repc-merged.html
+\ingroup cmake-macros-qtremoteobjects
+
+\title qt_add_repc_merged
+\target qt6_add_repc_merged
+
+\brief Creates C++ header files for source and replica types from the Qt Remote Objects .rep files.
+
+\cmakecommandsince 6.2
+
+\section1 Synopsis
+
+\badcode
+qt_add_repc_merged(<TARGET> rep_files)
+
+qt6_add_repc_merged(<TARGET> rep_files)
+\endcode
+
+\section1 Description
+
+Runs \l repc and generates \l {Qt Remote Objects Replica} and \l {Qt Remote Objects Source}
+header files based on the given \c rep_files combined in a single header. Adds the
+generated files to \c{<TARGET>}.
+
+\section1 Examples
+
+\snippet cmake-macros/CMakeLists.txt simpleSwitch_cmake_add_repc_merged
+
+The generated file(s) will be of the form \c {rep_<replica file name>_merged.h},
+in this case \c rep_simpleswitch_merged.h
+
+\note Typically sources and replicas live in separate processes or devices, so
+this function is not commonly used.
+*/
+
+/*!
+\page qtremoteobjects-cmake-qt-rep-from-headers.html
+\ingroup cmake-macros-qtremoteobjects
+
+\title qt_reps_from_headers
+\target qt6_reps_from_headers
+
+\brief Creates .rep files from the QObject header files.
+
+\cmakecommandsince 6.2
+
+\section1 Synopsis
+
+\badcode
+qt_reps_from_headers(<TARGET> header_files)
+
+qt6_reps_from_headers(<TARGET> header_files)
+\endcode
+
+\section1 Description
+
+Generates corresponding \c .rep files from the existing QObject \c header_files.
+
+\section1 Examples
+
+\snippet cmake-macros/CMakeLists.txt simpleSwitch_cmake_rep_from_header
+
+This will generate an interface file called \c simpleswitch.rep in the build
+directory.
+*/
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \page remoteobjects-changes-qt6.html
+ \title Changes to Qt Remote Objects
+ \ingroup changes-qt-5-to-6
+ \brief Migrate Qt Remote Objects to Qt 6.
+
+ Qt 6 is a result of the conscious effort to make the framework more
+ efficient and easy to use.
+
+ We try to maintain binary and source compatibility for all the public
+ APIs in each release. But some changes were inevitable in an effort to
+ make Qt a better framework.
+
+ In this topic we summarize those changes in Qt Remote Objects, and provide
+ guidance to handle them.
+
+ \section1 API changes
+
+ \section2 Functions taking const-ref QString changing to QStringView
+
+ QRemoteObjectHostBase::proxy, QRemoteObjectHostBase::reverseProxy and
+ QRemoteObjectNode::instances now accept a QStringView instead
+ of \c{const QString &}. The largest difference caused by this is that it
+ no longer accepts implicit conversion from string literals
+ (i.e. \c{node.instances("abc");}). Instead, you could use a UTF-16
+ string literal (\c{node.instances(u"abc")}).
+
+ \section2 Changes to classes for custom transport backend support
+
+ The "semi-private" \c IoDeviceBase, \c ServerIoDevice, and \c ClientIoDevice
+ classes are now renamed to \c QtROIoDeviceBase, \c QtROServerIoDevice, and
+ \c QtROClientIoDevice respectively, to be consistent with naming in Qt.
+ They are also moved from the private \c qconnectionfactories_p.h header to
+ \c qconnectionfactories.h.
+
+ \note These classes are provided to give more flexibility for implementing
+ custom communication protocols for Qt Remote Objects, but there are no
+ source or binary compatibility guarantees for them. We recommend using the
+ QRemoteObjectNode::addClientSideConnection() and
+ QRemoteObjectHostBase::addHostSideConnection() methods, if you need
+ support for \l {External QIODevices} {external} communication channels.
+
+ \section1 CMake changes
+
+ The \c cmake instructions for calling \l repc and adding the generated
+ \c .rep files to a CMake project have slightly changed. Instead of the
+ \c qt5_generate_repc macro, you should now use \c qt6_add_repc_sources,
+ \c qt6_add_repc_replicas and \c qt6_add_repc_merged functions.
+ For example, the following code:
+
+ \code
+ set(SOURCES
+ main.cpp
+ simpleswitch.cpp
+ )
+
+ qt5_generate_repc(SOURCES simpleswitch.rep SOURCE)
+ add_executable(directconnectserver ${SOURCES})
+ \endcode
+
+ Should change to:
+
+ \code
+ set(SOURCES
+ main.cpp
+ simpleswitch.cpp
+ )
+ add_executable(directconnectserver ${SOURCES})
+ qt6_add_repc_sources(directconnectserver simpleswitch.rep)
+ \endcode
+
+ More detailed descriptions for these CMake functions can be found
+ \l {CMake functions} {here}.
+*/
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2019 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+\page qtremoteobjects-compatibility.html
+\title Qt Remote Objects Protocol Versioning
+
+Qt Remote Objects uses an internal protocol to pass data between processes
+and/or devices. The same protocol version needs to be used by all parties: if
+there is a mismatch, the connecting node will output a warning and the host
+node will not send any data.
+
+Currently released versions:
+
+\table
+\header
+ \li Protocol Version
+ \li Qt Version
+\row
+ \li <1.2
+ \li Used during QtRO's tech preview phase.
+\row
+ \li 1.2
+ \li 5.12.0
+\row
+ \li 1.3
+ \li 5.12.4
+\row
+ \li 2.0
+ \li 6.2.0
+\endtable
+*/
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+\module QtRemoteObjects
+\title Qt Remote Objects C++ Classes
+\brief Provides an easy to use mechanism for sharing a QObject's properties, signals, or slots, between processes.
+\ingroup modules
+\qtcmakepackage RemoteObjects
+\qtvariable remoteobjects
+
+ To link against the module using CMake, add the following lines to your \c cmake file:
+
+ \snippet cmake-macros/CMakeLists.txt remote_objects_cmake
+
+ \snippet cmake-macros/CMakeLists.txt remote_objects_cmake_link
+
+ To link against the module using \c qmake, add this line to your \c{.pro} file:
+
+ \snippet doc_src_simpleswitch.cpp simpleSwitch_remoteobjectsadd_example1
+
+ For more information, see \l{Getting Started with Qt Remote Objects}.
+*/
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+\page qtremoteobjects-custom-transport.html
+\title APIs for Implementing Custom Transport Backends
+\brief Gives an overview of abstract APIs for implementing custom transport
+backends for Qt Remote Objects.
+
+Qt Remote Objects provides several abstract interfaces for implementing custom
+transport backends. The concept behind these classes is that there needs to be
+a host node, which has an address that can be connected to. Then there is a
+client object, which can be publicly constructed, and can connect to the server.
+When the server gets a connection request, it creates the server side of the
+connection, which communicates directly with the client. There are thus three
+abstractions, one for the server (\c QConnectionAbstractServer), one for the
+client-side of the connection (\c QtROClientIoDevice), and the third for the
+server-side of the connection (\c QtROServerIoDevice). The latter two inherit
+from \c QtROIoDeviceBase.
+
+\section1 API Overview
+
+\list
+\li \c QtROIoDeviceBase
+\li \c QtROClientIoDevice
+\li \c QtROServerIoDevice
+\li \c QConnectionAbstractServer
+\endlist
+
+After implementing these interfaces, you can register your custom protocol
+using the qRegisterRemoteObjectsServer() and qRegisterRemoteObjectsClient()
+methods.
+
+\note These APIs are provided to give more flexibility for implementing custom
+communication protocols for Qt Remote Objects. There are no source or binary
+compatibility guarantees for them, meaning that the API is only guaranteed to work
+with the Qt version it was developed against. API changes will however only be made
+in minor releases. (6.1, 6.2, and so on.)
+
+*/
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2019 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+\page remoteobjects-example-dynamic-replica.html
+\title Example 2: Direct Connection with a Dynamic Replica
+\brief Describes how the Qt Remote Objects establishes a direct connection with a dynamic replica.
+\target qtro-example2
+
+Initially, a dynamic replica is created as a "bare" QObject - without
+properties, signals or slots. Then, during initialization, QtRO returns the
+API for the object, after the connection to the source is made. Thus, the API
+is added to the object at runtime.
+
+There are no changes to be made on the source side, as a dynamic \l Replica
+only impacts how the requestor node acquires the replica. So, we use the
+source-side code shown in \l {qtro-example1}{Example 1}.
+
+\list 1
+ \li Add replica generation to the project.
+
+ Because the replica is dynamically acquired, no \c .rep file is
+ required unlike in \l {qtro-example1}{Example 1}.
+
+ \li Create the remote node and connect it to the source host node.
+
+ The code for this step is unchanged from \l {qtro-example1}{Example 1}.
+ \snippet doc_src_simpleswitch.cpp simpleSwitch_dynamicclientnode_example2
+
+ \li Acquire a replica of the remote source object.
+
+ In \c main.cpp, we use a QSharedPointer to hold a replica of the
+ remote object, and then instantiate a replica requestor object:
+
+ \snippet doc_src_simpleswitch.cpp simpleSwitch_dynamicclientmaincpp_example2
+\endlist
+
+The complete declaration and definition of the requestor class,
+\c DynamicClient, is as follows:
+
+\c dynamicclient.h
+\snippet doc_src_simpleswitch.cpp simpleSwitch_dynamicclientheader_example2
+
+\c dynamicclient.cpp
+\snippet doc_src_simpleswitch.cpp simpleSwitch_dynamicclientcpp_example2
+
+When run together with the source-side example, the output is identical
+to \l {qtro-example1}{Example 1}.
+
+*/
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2019 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+
+\page remoteobjects-example-registry.html
+\title Example 3: Connections to Remote Nodes using a Registry
+\brief Describes how the Qt Remote Objects registry establishes connections between nodes.
+\target qtro-example3
+
+This example illustrates the use of a \l {Registry} to build the node topology.
+For simple networks, we use a QUrl to create a direct connection between two
+nodes. For complex networks, we use a registry, where you use a different QUrl
+to point both the host and replica nodes to the registry. For only two nodes,
+the benefits of using a registry are minimal. But, as the network grows, using
+a registry means that all nodes only need to connect to the registry via a single
+QUrl. In comparison, with direct connections, nodes would have to maintain a
+list of QUrls for every single node that they link to.
+
+\section2 Set up the Source
+
+The \c simpleswitch.h and \c simpleswitch.cpp sources from \l {qtro-example1}
+{Example} can be used without modification. The difference is in the way a host
+node is created and connected to the registry:
+
+\c main.cpp
+\snippet doc_src_simpleswitch.cpp simpleSwitch_registrymaincpp_example3
+
+\section2 Set up the Replica
+
+The requestor object used for this example is the dynamic replica client
+discussed in \l {qtro-example2}{Example 2}.
+
+The only modification is in \c main.cpp: a \l {Registry} node is created
+to acquire a \l {Replica}:
+
+\snippet doc_src_simpleswitch.cpp simpleSwitch_registrydynamicclientmaincpp_example3
+
+When run together with the source-side example, the output is identical
+to \l {qtro-example1}{Example 1}.
+
+*/
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2019 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+\page remoteobjects-example-static-source
+\title Example 1: Direct Connection using a Static Source
+\brief Describes how the Qt Remote Objects establishes a direct connection using a static source.
+\target qtro-example1
+
+In this example, the source object is a simple binary switch that toggles its
+state based on a timer. When the state changes, a signal is emitted by the
+source which QtRO propagates to all replicas. Since the replicas have the same
+properties, signals, and slots as were exposed from the source, any slots
+connected to the replica's signal will be called when the replica receives that
+signal. The client process then echoes back the received switch state to the
+source by emitting its own signal which is connected to a slot on the replica.
+
+\list 1
+\li \b {Create a source object}
+
+To create this \l Source object, first we create the definition file,
+\c simpleswitch.rep. This file describes the properties and methods for the
+object and is input to the Qt Remote Objects Compiler \l{repc}. This file only
+defines interfaces that are necessary to expose to the \l{Replica}{Replicas}.
+
+\c simpleswitch.rep
+\snippet doc_src_simpleswitch.cpp simpleSwitch_rep
+
+In \c simpleswitch.rep,
+\list
+ \li \c currState holds the current state of the switch.
+ \li \c server_slot() allows us to interact with the source - it will be
+ connected to the \c echoSwitchState(bool newstate) signal.
+\endlist
+
+For repc to process this file, add the following line to your \c cmake file:
+
+\snippet cmake-macros/CMakeLists.txt simpleSwitch_cmake_add_repc_source
+
+If you're using \c qmake:
+
+\snippet doc_src_simpleswitch.cpp simpleSwitch_repsource_example1
+
+These instructions are only relevant for the Qt Remote Object module,
+so you need to add it to your project as well. If you're using CMake,
+add:
+
+\snippet cmake-macros/CMakeLists.txt remote_objects_cmake
+
+\snippet cmake-macros/CMakeLists.txt remote_objects_cmake_link
+
+If you're using \c qmake:
+
+\snippet doc_src_simpleswitch.cpp simpleSwitch_remoteobjectsadd_example1
+
+repc creates the \c rep_SimpleSwitch_source.h header in the build directory
+that you specify. For more information, see \l{Source}.
+
+repc creates three helper classes for use with QtRO. For this example, we
+use the basic: \c SimpleSwitchSimpleSource. It's an abstract class, defined in
+\c rep_SimpleSwitch_source.h. We derive from it to define our SimpleSwitch
+implementation class as shown below:
+
+\c simpleswitch.h
+
+\snippet doc_src_simpleswitch.cpp simpleSwitch_serverheader_example1
+
+In \c simpleswitch.h,
+\list
+ \li \c stateChangeTimer is a QTimer that is used to toggle the state of our
+ SimpleSwitch.
+ \li \c timeout_slot() is connected to \c stateChangeTimer's timeout() signal.
+ \li \c server_slot() -- which is called automatically on the source whenever
+ any replica calls their version of the slot -- outputs the received value.
+ \li \c currStateChanged(bool), defined in the \l{repc}-generated
+ \c rep_SimpleSwitch_source.h, is emitted whenever \c currState toggles.
+ In this example, we ignore the signal on the source side, and handle it
+ later on the replica side.
+\endlist
+
+The definition of our \c SwitchState class is shown below:
+
+\c simpleswitch.cpp
+
+\snippet doc_src_simpleswitch.cpp simpleSwitch_serversource_example1
+
+\li \b {Create a registry}
+
+Because this example uses a direct connection between nodes, we can omit this
+step.
+
+\li \b {Create a host node}
+
+The host node is created as shown below:
+
+\snippet doc_src_simpleswitch.cpp simpleSwitch_serverhostnode_example1
+
+\li \b {Host source object and remoting}
+
+The following statements instantiate the \l {Source} object and pass it on to
+the host to enable "remoting", which is the process of making an object visible
+to the QtRO network:
+
+\snippet doc_src_simpleswitch.cpp simpleSwitch_enableremoting_example1
+
+The contents of \c main.cpp file that implements the steps described above are
+as follows:
+
+\c main.cpp
+
+\snippet doc_src_simpleswitch.cpp simpleSwitch_servermaincpp_example1
+
+Compile and run this source-side project. The output, without any replicas
+created, should look as shown below with the switch state toggling between
+\c true and \c false every two seconds.
+
+\image DirectConnectServerOutput.png "Example 1: Server Output"
+
+\endlist
+
+The subsequent steps are for creating the replica side of the network, which in
+this example gets the state of switch from the \l {Source} and echoes it back.
+
+\section2 Replica Code
+
+\list 1
+\li \b {Use repc to add a replica to your project}
+
+We use the same API definition file as we did on the source side,
+\c SimpleSwitch.rep, to create a \l {Replica} header file using the \l {repc}.
+If you're using \c cmake, include the following line in your client side
+\c cmake file, specifying a \c .rep file input:
+
+\snippet cmake-macros/CMakeLists.txt simpleSwitch_cmake_add_repc_replica
+
+If you're using \c qmake, add the following line to your client side \c .pro
+file:
+
+\snippet doc_src_simpleswitch.cpp simpleSwitch_clientrep_example1
+
+The \l {repc} tool generates a \c rep_SimpleSwitch_replica.h file in the build
+directory. For more information, see \l{Replica}.
+
+\li \b {Create a node to connect with the source's host node}
+
+The following code instantiates the second node on the network and connects it
+with the source host node:
+
+\snippet doc_src_simpleswitch.cpp simpleSwitch_clientremotenode_example1
+
+\li \b {Call the node's \l{QRemoteObjectNode::}{acquire()} to create a pointer
+ to a replica}
+
+First, we instantiate a replica:
+
+\snippet doc_src_simpleswitch.cpp simpleSwitch_clientacquirereplica_example1
+
+\note \l{QRemoteObjectNode::}{acquire()} returns a pointer to the replica, but
+doesn't manage its lifetime. This example shows the recommended process of
+wrapping the returned pointer in a QSharedPointer or QScopedPointer to ensure
+that the pointer is always deleted properly.
+
+\c main.cpp implements the steps described above and instantiates our object:
+
+\c main.cpp
+\snippet doc_src_simpleswitch.cpp simpleSwitch_clientmain_example1
+
+The complete declaration and definition for the \c Client class is as follows:
+
+\c client.h
+\snippet doc_src_simpleswitch.cpp simpleSwitch_clientheader_example1
+
+\c client.cpp
+\snippet doc_src_simpleswitch.cpp simpleSwitch_clientcpp_example1
+
+Compiling and running this example together with the source-side example
+generates the following output:
+
+\image DirectConnectClientServerOutput.png "Direct Connect Server Client Communication output"
+\endlist
+
+*/
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2018 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+\page qtremoteobjects-external-schemas.html
+\title Qt Remote Objects - External QIODevices
+\brief Describes how Qt Remote Objects supports custom QIODevice channels.
+
+\section1 External QIODevices
+
+Qt Remote Objects supports several communications channels out-of-the-box, such
+as the \l QTcpServer and \l QTcpSocket pair. Given the desired \l QUrl for tcp,
+or the desired name (for the \l QLocalServer and \l QLocalSocket pair), the
+code needed to listen and connect are boilerplate and handled internally by Qt.
+Qt Remote Objects supports other types of \l QIODevice as well, and the \l
+QRemoteObjectNode classes provide additional methods to support cases where
+custom code is needed.
+
+A contrived example with TCP/IP is shown below. A more realistic example would
+use an SSL connection, which would require configuration of certificates, etc.
+
+\code
+ // Create the server and listen outside of QtRO
+ QTcpServer tcpServer;
+ tcpServer.listen(QHostAddress(QStringLiteral("127.0.0.1")), 65213);
+
+ // Create the host node. We don't need a hostUrl unless we want to take
+ // advantage of external schemas (see next example).
+ QRemoteObjectHost srcNode;
+
+ // Make sure any connections are handed to QtRO
+ QObject::connect(&tcpServer, &QTcpServer::newConnection, &srcNode,
+ [&srcNode, &tcpServer]() {
+ srcNode.addHostSideConnection(tcpServer.nextPendingConnection());
+ });
+\endcode
+
+The Replica side code needs to manually connect to the Host
+\code
+ QRemoteObjectNode repNode;
+ QTcpSocket *socket = new QTcpSocket(&repNode);
+ QObject::connect(socket, &QTcpSocket::connected, &repNode,
+ [socket, &repNode]() {
+ repNode.addClientSideConnection(socket);
+ });
+ socket->connectToHost(QHostAddress(QStringLiteral("127.0.0.1")), 65213);
+\endcode
+
+\section1 External Schemas
+
+It is possible to create each side of the QIODevice and call \l
+{QRemoteObjectNode::addClientSideConnection(QIODevice *ioDevice)} and \l
+{QRemoteObjectHostBase::addHostSideConnection(QIODevice *ioDevice)} as shown
+above. This is fully supported, but requires the client know how to establish
+the connection or have a way to discover that information. This is exactly the
+problem the registry was designed to solve.
+
+Qt Remote Objects also allows "External Schemas" to be used with the registry,
+which helps with connection setup. On the \l QRemoteObjectHost side, the
+user must set the hostUrl with the desired schema.
+
+\code
+ // Use standard tcp url for the registry
+ const QUrl registryUrl = QUrl(QStringLiteral("tcp://127.0.0.1:65212"));
+ // Use "exttcp" for the "external" interface
+ const QUrl extUrl = QUrl(QStringLiteral("exttcp://127.0.0.1:65213"));
+
+ // Create the server and listen outside of QtRO
+ QTcpServer tcpServer;
+ tcpServer.listen(QHostAddress(extUrl.host()), extUrl.port());
+
+ // We need a registry for everyone to connect to
+ QRemoteObjectRegistryHost registry(registryUrl);
+
+ // Finally, we create our host node and register "exttcp" as our schema.
+ // We need the AllowExternalRegistration parameter to prevent the node from
+ // setting a hostUrlInvalid error.
+ QRemoteObjectHost srcNode(extUrl, registryUrl, QRemoteObjectHost::AllowExternalRegistration);
+ // From now on, when we call enableRemoting() from this node, the registry
+ // will be updated to show the Source object at extUrl.
+\endcode
+
+On the \l Replica side, the \l QRemoteObjectNode needs to register a callback
+to be used when the external schema is detected. The callback must be a
+\l {QRemoteObjectNode::}{RemoteObjectSchemaHandler}.
+
+\code
+ // Use standard tcp url for the registry
+ const QUrl registryUrl = QUrl(QStringLiteral("tcp://127.0.0.1:65212"));
+
+ // This time create the node connected to the registry
+ QRemoteObjectNode repNode(registryUrl);
+
+ // Create the RemoteObjectSchemaHandler callback
+ QRemoteObjectNode::RemoteObjectSchemaHandler setupTcp = [&repNode](QUrl url) {
+ QTcpSocket *socket = new QTcpSocket(&repNode);
+ connect(socket, &QTcpSocket::connected,
+ [socket, &repNode]() {
+ repNode.addClientSideConnection(socket);
+ });
+ connect(socket, &QSslSocket::errorOccurred,
+ [socket](QAbstractSocket::SocketError error) {
+ delete socket;
+ });
+ socket->connectToHost(url.host(), url.port());
+ };
+
+ // Once we call registerExternalSchema, the above method will be called
+ // whenever the registry sees an object we are interested in on "exttcp"
+ repNode.registerExternalSchema(QStringLiteral("exttcp"), setupTcp);
+\endcode
+*/
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+\page qtremoteobjects-gettingstarted.html
+\title Getting Started with Qt Remote Objects
+\brief Detailed information on how to use Qt Remote Objects.
+
+\section1 Introduction
+
+The Qt Remote Objects module provides an easy way to share Qt APIs between
+processes and devices. For this to work, we require a data channel between
+processes and devices. To establish this data channel, first, you need a
+QRemoteObjectNode.
+
+In QtRO, a node is an endpoint for communication. In a remote objects network,
+each participant, be it a process or a device, needs its own node. QtRO is a
+peer-to-peer network, with connected nodes being the links in the network.
+
+Nodes, by themselves, don’t provide much use. But their value comes when you
+add QObject classes to a node to share. Then, any peer node can request a copy
+or instance of the shared object from the \e{host node}, the node that shares
+it.
+
+Unlike when using normal class instances (with independent properties and
+signal emissions), QtRO automatically synchronizes changes to the shared object
+across all of its copies. With a few exceptions, these copies have the
+identical Qt API as the original object, and are meant to be used exactly as if
+the original object were available.
+
+In QtRO, the original object is called the \l{Source}. It's a fully-implemented
+C++ class, with the necessary business logic to provide the required
+functionality. Copies of this object are called \l{Replica}s. You don’t need
+to write any C++ code for a replica; you request an instance from a node
+instead. While you do need some code to use the replica, such as connecting
+signals to your own slots, you don’t need to implement the internal behavior –
+that's already done for you in the source.
+
+Because the source can be in a different process or even on a different device,
+there are factors in QtRO that you need to consider, which you typically
+wouldn't run into when developing without Inter-Process Communication (IPC).
+Specifically, what happens if the process or device isn't there? This is where
+the additions to the Replica API come in:
+
+\list
+ \li The \l{QRemoteObjectReplica::}{initialized()} signal is emitted once the
+ replica has received the \l{Source}{source} state from the QtRO
+ network.
+ \li Both the \l{QRemoteObjectReplica::}{isReplicaValid} property and the
+ \l{QRemoteObjectReplica::}{stateChanged()} signal alert you if the
+ connection is lost.
+\endlist
+
+Objects shared over QtRO use the links (conduits) between nodes for all
+communication. If you want to share a QObject, you must create a \e{host node}
+with a URL other nodes can connect to. You can also use the \l{Registry} to
+facilitate connections, but your nodes that share \l{Source}{sources} still need
+to be host nodes. Each shared object is given a name (a QString), used to
+identify it on the QtRO network.
+
+\section1 Implementation
+
+To illustrate the use of remote objects, on the source side, we need to:
+
+\list 1
+ \li Create the \l {Source} object that is replicated to other nodes, with or
+ without using \l repc, the Qt Remote Objects Compiler.
+ \li Optionally, create the \l{Registry}. Otherwise, use direct connections.
+ \li Create a host node so that the source object can be shared.
+ \li Call the node's \l{QRemoteObjectHostBase::}{enableRemoting()} function
+ to share the source object.
+\endlist
+
+On the replica side, we need to:
+
+\list 1
+ \li Optionally, use \l repc to generate a \l{Replica} header for your project.
+ \li Create the node that will connect with the \l{Source} host node.
+ \li Call the node's \l{QRemoteObjectNode::}{acquire()} function to create a
+ pointer to a replica.
+\endlist
+
+The following examples illustrate both \l{repc}-compiled static objects and dynamic
+source objects. Additionally, they also show direct connections as well as
+connections that use a \l{Registry} between nodes.
+
+\list
+ \li \l{Example 1: Direct Connection using a Static Source}
+ \li \l{Example 2: Direct Connection with a Dynamic Replica}
+ \li \l{Example 3: Connections to Remote Nodes using a Registry}
+\endlist
+
+*/
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+\page qtremoteobjects-index.html
+\title Qt Remote Objects
+\ingroup overviews
+\brief Provides APIs for inter-process communication.
+
+\target Qt Remote Objects
+\section1 Remote Object Concepts
+
+Qt Remote Objects (QtRO) is an Inter-Process Communication (IPC) module
+developed for Qt. This module extends Qt's existing functionalities to enable
+information exchange between processes or computers, easily.
+
+One of Qt's key features, to enable this information exchange, is the
+distinction between an object's API (defined by its properties, signals, and
+slots) and the implementation of that API. QtRO's purpose is to meet that
+expected API, even if the true QObject is in a different process. A slot
+called on a copy of an object (the \l {Replica} in QtRO) is forwarded to the
+true object (the \l {Source} in QtRO) for handling. Every Replica receives
+updates to the Source, either property changes or emitted signals.
+
+A \l {Replica} is a light-weight proxy for the \l {Source} object, but a
+Replica supports the same connections and behavior of QObjects, which makes it
+usable in the same way as any other QObject that Qt provides. Behind the
+scenes, QtRO handles everything that's necessary for the Replica to look like
+its Source.
+
+Note that Remote Objects behave differently from traditional Remote Procedure
+Call (RPC) implementations, for example:
+
+\list
+ \li In RPC, the client makes a request and waits for the response.
+ \li In RPC, the server doesn't push anything to the client unless it's in
+ response to a request.
+ \li Often, the design of RPC is such that different clients are independent
+ of each other: for instance, two clients can ask a mapping service for
+ directions and get different results.
+\endlist
+
+While it is possible to implement this RPC-style behavior in QtRO, as Sources
+without properties, and slots that have return values, QtRO hides the fact that
+the processing is really remote. You let a node give you the Replica instead of
+creating it yourself, possibly use the status signals
+(\l {QRemoteObjectReplica::} {isReplicaValid()}), but then interact with the
+object like you would with any other QObject-based type.
+
+\section1 Use Case: GPS
+
+Consider a sensor such as a Global Positioning System (GPS) receiver. In
+QtRO terms:
+
+\list
+ \li The \l{Source} would be the process that directly interacts with the
+ GPS hardware and derives your current location.
+ \li The location would be exposed as QObject properties; the periodic
+ updates to the location would update these properties and emit property
+ changed signals.
+ \li \l{Replica}{Replicas} would be created in other processes and would
+ always know your current location, but wouldn't need any of the logic
+ to compute the location from the sensor data.
+ \li Connecting to the location changed signal on the Replica would work as
+ expected: the signal emitted from the Source would trigger the signal
+ emission on every Replica.
+\endlist
+
+\section1 Use Case: Printer Access
+
+Consider a service that provides access to a printer. In QtRO terms:
+
+\list
+ \li The \l{Source} would be the process controlling the printer directly.
+ \li The ink levels and printer status would be monitored by QObject
+ properties. Updates to these properties would emit property changed
+ signals.
+ \li The key feature -- being able to print something -- needs to be passed
+ back to the printer. Incidentally, this aligns with the Qt slot mechanism,
+ which QtRO uses as the way for \l{Replica}{Replicas} to make calls on the
+ Source. In effect, properties and signals go from Source to Replicas;
+ slots go from Replica to Source.
+ \li When a print request is accepted, the printer status would change,
+ triggering a change in the status property. This would then be reported
+ to all Replicas.
+\endlist
+
+\include module-use.qdocinc using qt module
+\snippet cmake-macros/CMakeLists.txt remote_objects_cmake
+
+See also the \l {Build with CMake} overview.
+
+\include module-use.qdocinc building with qmake
+\snippet doc_src_simpleswitch.cpp simpleSwitch_remoteobjectsadd_example1
+
+\section1 Articles and Guides
+ \list
+ \li \l {Getting Started with Qt Remote Objects}
+ \li \l {Qt Remote Objects Nodes}{Nodes}
+ \li \l {Qt Remote Objects Source}{Sources}
+ \li \l {Qt Remote Objects Replica}{Replicas}
+ \li \l {Qt Remote Objects Registry}{Registry}
+ \li Using Custom Transports
+ \list
+ \li \l {Qt Remote Objects - External QIODevices}{External QIODevices}
+ \li \l {APIs for Implementing Custom Transport Backends}
+ {Implementing Custom Transport Backends}
+ \endlist
+ \li \l {Qt Remote Objects Compiler}{Compiler}
+ \li \l {Remote Object Interaction}
+ \li \l {Troubleshooting Qt Remote Objects}{Troubleshooting}
+ \li \l {Qt Remote Objects Protocol Versioning}{Protocol Versioning}
+ \endlist
+
+\section2 API Reference
+
+\list
+ \li \l {Qt Remote Objects C++ Classes}
+ \li \l {Qt Remote Objects QML Types}
+\endlist
+
+\section1 Licenses
+
+Qt Remote Objects is available under commercial licenses from \l{The Qt Company}.
+In addition, it is available under the
+\l{GNU Lesser General Public License, version 3}, or the
+\l{GNU General Public License, version 2}.
+See \l{Qt Licensing} for further details.
+
+*/
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2018 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+/*!
+\page qtremoteobjects-interaction.html
+\brief Describes how a source and replicas interact with one another.
+\section1 Remote Object Interaction
+
+The interaction between source and replicas is directional. Property changes
+and signal emission happen on the source, and are propagated to all replicas.
+If a property is writable, you can call the setter function on a replica, which
+is then forwarded to the source. Afterwards, if this call results in a new
+property value, that value is first changed at the source and then subsequently
+forwarded to all replicas. To the replica, it is then an asynchronous call,
+with latency before the change takes effect.
+
+While technically you can emit a signal on a replica, this is discouraged as it
+may have unexpected results. It will only trigger slots connected to the
+replica itself; not slots connected to the source or other replicas. Like
+property setters, slot invocations on a replica are forwarded to the source to
+run.
+
+Qt Remote Objects automatically implements the behavior described above. There
+is no need to write any replica implementation code. For dynamic replicas,
+this is handled automatically at runtime. For \l{repc} generated headers, this
+is handled at compile time.
+*/
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2018 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+/*!
+\page qtremoteobjects-node.html
+\title Qt Remote Objects Nodes
+\brief Describes how Qt Remote Objects pass data between nodes.
+
+In a QtRO network, information is passed between processes via
+QRemoteObjectNodes ("nodes"). This peer-to-peer functionality uses a small
+number of distinct packets passing the necessary data between nodes.
+
+Each process that participates in the network instantiates a Node-based type,
+such as QRemoteObjectNode, QRemoteObjectHost, or QRemoteObjectRegistryHost.
+The host types of Nodes provide additional functionality. Both
+QRemoteObjectHost and QRemoteObjectRegistryHost support the
+\l{QRemoteObjectHostBase::}{enableRemoting()} and the corresponding
+\l{QRemoteObjectHostBase::}{disableRemoting()} methods, which are the key
+methods to expose source objects to the network. To use the \l Registry
+functionality, you need to have a QRemoteObjectRegistryHost on the network.
+Then, all other nodes can pass the RegistryHost's URL to the Node's
+\c registryAddress constructor parameter, or pass the URL to the
+\l {QRemoteObjectNode::}{setRegistryUrl()} method.
+
+Since QtRO is a peer-to-peer network, to
+\l{QRemoteObjectNode::acquire()}{acquire()} a valid \l{Replica}, the replica's
+node needs to be connected to the node that hosts its \l{Source}. A host node is a
+node that allows other nodes to connect to it, which is accomplished by giving
+hosts unique addresses. This address is provided to the QRemoteObjectHost
+constructor or set by the setHostUrl method. The node from which a replica is
+requested must establish the connection to the host node, to initialize the
+replica and keep it up to date.
+
+\section1 Connecting Nodes using QtRO URLs
+
+Host Nodes use custom URLs to simplify connections. Currently, QtRO supports
+two types of connections:
+
+\list 1
+ \li A TCP connection using the standard TCP/IP protocol - supports
+ connections between devices as well as between processes on the same
+ device.
+ \li A local connection - supports connections between processes on the same
+ device. This type of connection can have less overhead, depending on
+ the underlying Operating System features.
+\endlist
+
+For local connections, you must use a unique name. For TCP connections, you
+must provide a unique address and port number combination.
+
+Currently, QtRO does not include a \l {http://www.zeroconf.org/} {zeroconf}
+facility. Therefore, all processes or devices must know beforehand, how to
+connect to each other. A \l {QRemoteObjectRegistry} can be used to simplify
+the connection process for a network with multiple Host Nodes.
+
+The table below summarizes the connection types available:
+
+ \table 90%
+ \header
+ \li URL
+ \li Notes
+ \row
+ \li {QUrl}("local:service")
+ \li Uses (internally) {QLocalServer}/{QLocalSocket} classes to
+ communicate between nodes.
+ \row
+ \li {QUrl}("tcp://192.168.1.1:9999")
+ \li Uses (internally) {QTcpServer}/{QTcpSocket} classes to
+ communicate between nodes.
+ \row
+ \li {QUrl}("qnx:service")
+ \li QNX OS only. Uses a custom (named) channel for native
+ communication between nodes.
+ \row
+ \li {QUrl}("localabstract:service")
+ \li Since 6.2. Linux/Android OSes only. Uses an abstract namespace
+ for Unix domain sockets. This allows QLocalSocket behavior to work on
+ non-writable devices.
+ \endtable
+
+Nodes have a few \l{QRemoteObjectHostBase::enableRemoting()}
+{enableRemoting()} methods that are used to share objects on the network.
+However, if the node is not a host node, an error is returned.
+
+Other processes or devices that want to interact with a shared object can
+use one of the \l{QRemoteObjectNode::acquire()} {node's acquire()} methods,
+to instantiate a replica.
+
+*/
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2018 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+\qmlmodule QtRemoteObjects 6.\QtMinorVersion
+\title Qt Remote Objects QML Types
+\ingroup qmlmodules
+\brief Provides QML types for remote objects support.
+
+The QML types for \l{Qt Remote Objects} provide the helper pieces needed to build a remote objects network.
+They are typically used in conjunction with custom-registered replica types that make up a specific
+network.
+
+As an example, consider the following .rep file:
+\code
+class MyType {
+ PROP(QString myProp="Hello World")
+};
+\endcode
+
+The generated replica can be registered as a QML type:
+\code
+qmlRegisterType<MyTypeReplica>("custom",1,0,"MyTypeReplica")
+\endcode
+
+And then used from QML in conjunction with the base type Node:
+\qml
+import QtQuick
+import QtRemoteObjects
+import custom 1.0
+
+Item {
+ MyTypeReplica {
+ id: myType
+ node: Node { registryUrl: "local:registry" }
+ }
+
+ Text { text: myType.myProp }
+
+ MouseArea {
+ anchors.fill: parent
+ onClicked: myType.pushMyProp("Updated Text")
+ }
+}
+\endqml
+
+Note that by default you cannot directly assign to a replica property, but rather use a \c push function.
+This is due to the potential problems that arise from the mix of declarative programming and asynchronous updates.
+Specifically, we want to avoid issues like the following:
+\badcode
+myType.myProp = "Updated Text"
+console.log(myType.myProp) // logs "Hello World", as the new text has not yet been round-tripped
+\endcode
+
+The QML types in this module can be imported into your application using the following import
+statement in your .qml file:
+\qml
+import QtRemoteObjects
+\endqml
+
+\section1 QML Types
+*/
+
+/*!
+\qmltype QtRemoteObjects
+\inqmlmodule QtRemoteObjects
+\since 5.14
+\brief The QtRemoteObjects global object provides useful functions for working with remote
+ types in QML.
+*/
+
+/*!
+ \qmlmethod Promise QtRemoteObjects::QtRemoteObjects::watch(QRemoteObjectPendingCall reply, int timeout = 30000)
+ Encapsulates the return value, represented by \a reply, from a replica in a JavaScript Promise.
+ A timeout can be set with \a timeout. The default timeout value is 30 seconds.
+
+ \qml
+ QtRemoteObjects.watch(replica.fetchDetails(identifier))
+ .then(function(value) { details = value },
+ function(error) { console.log("error fetching details:", error) })
+ \endqml
+*/
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2018 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+\page qtremoteobjects-registry.html
+\title Qt Remote Objects Registry
+\brief Describes how the Qt Remote Objects registry establishes connections
+ between nodes.
+\target Registry
+
+When you \l {QRemoteObjectNode::acquire()} a replica, the node URL is not passed
+as an argument. This means you do not need to specify the host node, but it does
+require you to have some other means of connecting to that host. Without the
+registry, it is necessary to manually call \l {QRemoteObjectNode::connectToNode()},
+from each node, to every host node that has \l {Source} objects it should
+replicate. This is fine for small or static networks, but does not scale.
+
+The registry provides a simpler way to establish these connections. Every node
+that wants to be part of the registry's network connects to the registry. The
+registry is itself a specialized source object, and thus is hosted by a node.
+Connecting to the registry is simply a matter of passing the registry's URL to
+the QRemoteObjectNode or QRemoteObjectHost constructor, or passing the URL to
+the setRegistryUrl method.
+
+The registry is tightly integrated with QtRO. Whenever a \l {Source} is added
+or removed, the name/URL is updated in the registry automatically. So once
+your node is connected to the registry, it is not necessary to connect to any
+other nodes manually. If you request an object on the network and you aren't
+connected to the hosting node, the registry will know what URL to connect to
+and will initiate the connection. Once connected (and the list of available
+objects is passed along, including the desired \l {Source}), the initialization
+process for the requested \l Replica will start automatically.
+*/
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \externalpage https://en.wikipedia.org/wiki/Domain-specific_language
+ \title Domain Specific Language (DSL)
+*/
+
+/*!
+\page qtremoteobjects-repc.html
+\title Qt Remote Objects Compiler
+\brief The Qt Remote Objects Compiler creates \l {Source} and \l {Replica} header files
+\ingroup overviews
+\keyword repc
+
+ \section1 REPC Overview
+
+ The \underline {Rep}lica \underline {C}ompiler (repc) generates QObject
+ header files based on an API definition file. The file (called a "rep"
+ file) uses a specific (text) syntax to describe the API. By convention,
+ these files are given a .rep file extension, short for Replica. When these
+ files are processed by repc, repc generates both \l {Source} and \l
+ {Replica} header files.
+
+ The Qt Remote Objects module also includes \l {CMake functions} and
+ \l {qmake variables} that can be added to your project file to automatically run
+ repc, and add the resulting files to the list of files processed by
+ \l{moc}{Meta Object Compiler} during the build process, making use of Qt
+ Remote Objects in your projects simple.
+
+ While Qt Remote Objects supports sharing any QObject over the network (using
+ enableRemoting on the Source side and acquireDynamic on the Replica side),
+ there are a couple of advantages to letting repc define your objects. First
+ of all, while \l {QRemoteObjectDynamicReplica} {DynamicReplicas} are
+ useful, they are more cumbersome to work with. The API is not known until
+ the object is initialized, and using the API from C++ requires string
+ lookups through QMetaObject's methods. Secondly, having the interface known
+ at compile time finds any issues at compile vs. at runtime. Thirdly, the rep
+ format supports default values, which can be handy if you are unable to
+ ensure the Source is available when the Replica is instantiated.
+
+ See the documentation \l {Source} {here} for information on using
+ the generated files in your code. Here we will focus on the repc format and
+ options.
+
+ \section1 The rep file format
+
+ The rep file format is a simple \l {Domain Specific Language (DSL)} for
+ describing an interface supported over Qt Remote Objects (QtRO). Since QtRO
+ is an object based system, these interfaces are defined by APIs available
+ through objects, that is, classes with properties, signals, and slots.
+
+ \section2 The class type
+
+ Each class defined in a rep file becomes a QObject in the generated header
+ files, with the described API generated for you.
+
+ To define a class use the \c class keyword, followed by the name you
+ want for your type, and then enclose your API in brackets like so
+ \code
+ class MyType
+ {
+ //PROP/CLASS/MODEL/SIGNAL/SLOT/ENUM declarations to define your API
+ };
+ \endcode
+
+ \section3 PROP
+
+ Q_PROPERTY elements are created by using the PROP keyword in the rep
+ file. The syntax is the \c PROP keyword followed by the definition enclosed
+ in parentheses, where the definition is the type, the name, and (optionally) a
+ default value or attributes.
+ \code
+ PROP(bool simpleBool) // boolean named simpleBool
+ PROP(bool defaultFalseBool=false) // boolean named defaultFalseBool, with false
+ // as the default value
+
+ PROP(int lifeUniverseEverything=42) // int value that defaults to 42
+ PROP(QByteArray myBinaryInfo) // Qt types are fine, may need #include
+ // additional headers in your rep file
+
+ PROP(QString name CONSTANT) // Property with the CONSTANT attribute
+ PROP(QString setable READWRITE) // Property with the READWRITE attribute
+ // note: Properties default to READPUSH
+ // (see description below)
+
+ PROP(SomeOtherType myCustomType) // Custom types work. Needs #include for the
+ // appropriate header for your type, make
+ // sure your type is known to the metabject
+ // system, and make sure it supports Queued
+ // Connections (see Q_DECLARE_METATYPE and
+ // qRegisterMetaType)
+ \endcode
+ More information about creating custom types can be found \l {Creating
+ Custom Qt Types} {here}.
+
+ By default, properties will have getters and a "push" slot defined, as well
+ as a notify signal emitted when the value is changed. Qt Remote Objects
+ requires the notify signal on the Source object to trigger sending updates
+ to the attached Replicas. In earlier versions of QtRO, properties defaulted
+ to being read/write, that is, having getters and setters. However, due to the
+ asynchronous nature of QtRO, this led to unintuitive behavior at times.
+ Setting the READWRITE attribute on the PROP will provide the old (getter
+ and setter) behavior.
+ \code
+ // In .rep file, old (setter) behavior
+ PROP(int myVal READWRITE) // Old behavior with setMyVal(int myVal) method
+
+ // In code... Assume myVal is initially set to 0 in Source
+ int originalValue = rep->myVal(); // Will be 0
+ rep->setMyVal(10); // Call setter, expecting a blocking/
+ // non-asynchronous return
+
+ if (rep->myVal() == 10) ... // Test will usually fail
+ \endcode
+
+ If it is necessary to block until the value is changed, something like the
+ following is necessary.
+ \code
+ // In .rep file, old (setter) behavior
+ PROP(int myVal READWRITE) // Old behavior with setMyVal(int myVal) method
+
+ // In code... Assume myVal is initially set to 0 in Source
+ bool originalValue = rep->myVal(); // Will be 0
+
+ // We can wait for the change using \l QSignalSpy
+ QSignalSpy spy(rep, SIGNAL(myValChanged(int)));
+
+ rep->setMyVal(10); // Call setter, expecting a blocking/
+ // non-asynchronous return
+
+ spy.wait(); // spy.wait() blocks until changed signal
+ // is received
+ if (rep->myVal() == 10) ... // Test will succeed assuming
+ // 1. Source object is connected
+ // 2. Nobody else (Source or other Replica)
+ // sets the myVal to something else (race
+ // condition)
+ // Rather than use QSignalSpy, the event-driven practice would be to connect the
+ // myValChanged notify signal to a slot that responds to the changes.
+ \endcode
+
+ QtRO now defaults to READPUSH, which provides an automatically generated
+ slot for requesting a property change.
+ \code
+ // In .rep file, defaults to READPUSH
+ PROP(bool myVal) // No setMyVal(int myVal) on Replica, has
+ // pushMyVal(int myVal) instead
+
+ // In code... Assume myVal is initially set to 0 in Source
+ bool originalValue = rep->myVal(); // Will be 0
+
+ // We can wait for the change using \l QSignalSpy
+ QSignalSpy spy(rep, SIGNAL(myValChanged(int)));
+
+ rep->pushMyVal(10); // Call push method, no expectation that change
+ // is applied upon method completion.
+
+ // Some way of waiting for change to be received by the Replica is still necessary,
+ // but hopefully not a surprise with the new pushMyVal() Slot.
+ spy.wait(); // spy.wait() blocks until changed signal
+ // is received
+ if (rep->myVal() == 10) ... // Test will succeed assuming
+ // 1. Source object is connected
+ // 2. Nobody else (Source or other Replica)
+ // set the myVal to something else (race
+ // condition)
+ \endcode
+
+ You can also use the \c CONSTANT, \c READONLY, \c PERSISTED, \c READWRITE,
+ \c READPUSH, or \c SOURCEONLYSETTER keywords in the PROP declaration, which
+ affects how the property is implemented. READPUSH is the default value if no value
+ used.
+
+ \code
+ PROP(int lifeUniverseEverything=42 CONSTANT)
+ PROP(QString name READONLY)
+ \endcode
+
+ Please note there are some subtleties here. A CONSTANT PROP has a
+ Q_PROPERTY declared as CONSTANT on the SOURCE side. However, replicas
+ cannot know the correct value until they are initialized, which means the
+ property value has to be allowed to change during initialization. For
+ READONLY, the source will have neither a setter nor a push slot, and the
+ replica side will not have a push slot generated. Adding the PERSISTED
+ trait to a PROP will have the PROP use the \l QRemoteObjectAbstractPersistedStore
+ instance set on a Node (if any) to save/restore PROP values.
+
+ Another nuanced value is SOURCEONLYSETTER, which provides another way of
+ specifying asymmetric behavior, where the \l Source (specifically the helper
+ class, \c SimpleSource) will have a public getter and setter for the
+ property, but it will be ReadOnly (with a notify signal) on the \l Replica
+ side. Thus the property can be fully controlled from the \l Source side,
+ but only observed from the \l Replica side. SOURCEONLYSETTER is the mode
+ used by repc for MODEL and CLASS instances, meaning the \l Source can
+ change the pointed to object, but the \l Replica can not provide a new
+ object, as no set<Prop> or push<Prop> method is generated. Note, this does
+ not impact the behavior of the pointed to type's properties, just the
+ ability to change the pointer itself.
+
+ \sa QRemoteObjectAbstractPersistedStore
+
+ \section3 CLASS
+
+ The CLASS keyword generates special Q_PROPERTY elements for objects derived from QObject.
+ These properties have the same semantics as SOURCEONLYSETTER. The syntax is the \c CLASS
+ keyword followed by the property name and then the type of subobject enclosed in parentheses.
+ \code
+ // In .rep file
+ class OtherClass
+ {
+ PROP(int value)
+ }
+
+ class MainClass
+ {
+ CLASS subObject(OtherClass)
+ }
+ \endcode
+
+ \section3 MODEL
+
+ The MODEL keyword generates special Q_PROPERTY elements for objects derived from QAbstractItemModel.
+ These properties have the same semantics as SOURCEONLYSETTER. The syntax is the \c MODEL
+ keyword followed by the property name and then parentheses enclosing the (comma-separated) roles
+ that should be exposed to the replica.
+ \code
+ // In .rep file
+ class CdClass
+ {
+ PROP(QString title READONLY)
+ MODEL tracks(title, artist, length)
+ }
+ \endcode
+
+ \section3 SIGNAL
+
+ \l [DOC QtCore] {Signals} {Signal} methods are created by using the SIGNAL keyword in the rep file.
+
+ Usage is to declare \c SIGNAL followed by the desired signature wrapped in
+ parentheses. The void return value should be skipped.
+
+ \code
+ SIGNAL(test())
+ SIGNAL(test(QString foo, int bar))
+ SIGNAL(test(QMap<QString,int> foo))
+ SIGNAL(test(const QString &foo))
+ SIGNAL(test(QString &foo))
+ \endcode
+
+ Just like in Qt \l {Qt::ConnectionType} {queued connections}, parameters in signals that are
+ references will be copied when being passed to replicas.
+
+ \section3 SLOT
+
+ \l [DOC QtCore] {Slots} {Slot} methods are created by using the SLOT keyword in the rep file.
+
+ Usage is to declare \c SLOT followed by the desired signature wrapped in
+ parentheses. The return value can be included in the declaration. If the
+ return value is skipped, void will be used in the generated files.
+
+ \code
+ SLOT(test())
+ SLOT(void test(QString foo, int bar))
+ SLOT(test(QMap<QString,int> foo))
+ SLOT(test(QMap<QString,int> foo, QMap<QString,int> bar))
+ SLOT(test(QMap<QList<QString>,int> foo))
+ SLOT(test(const QString &foo))
+ SLOT(test(QString &foo))
+ SLOT(test(const QMap<QList<QString>,int> &foo))
+ SLOT(test(const QString &foo, int bar))
+ \endcode
+
+ Just like in Qt \l {Qt::ConnectionType} {queued connections} and QtRO
+ SIGNALS, parameters in slots that are references will be copied when being
+ passed to Replicas.
+
+ \section3 ENUM
+
+ Enumerations (which use a combination of C++ enum and Qt's Q_ENUM in QtRO)
+ are described using the ENUM keyword.
+
+ \code
+ ENUM MyEnum {Foo}
+ ENUM MyEnum {Foo, Bar}
+ ENUM MyEnum {Foo, Bar = -1}
+ ENUM MyEnum {Foo=-1, Bar}
+ ENUM MyEnum {Foo=0xf, Bar}
+ ENUM MyEnum {Foo=1, Bar=3, Bas=5}
+ \endcode
+
+ Related topics: \l {The ENUM type}, \l {USE_ENUM keyword}
+
+ \section2 The POD type
+
+ Plain Old Data (POD) is a term to describe a simple data collection, along
+ the lines of a C++ struct. For example, if you have an API for a phonebook,
+ you may want to use the concept of an "address" in its interface (where
+ address might include street, city, state, country, and postal code). You
+ can use the POD keyword to define objects like this, which can then be used
+ by in PROP/SIGNAL/SLOT definitions in your class definitions.
+
+ Usage is to declare \c POD followed by the name for the generated type,
+ followed by type and name pairs separated by commas, where the type/name
+ pairs are wrapped in parentheses.
+
+ \code
+ POD Foo(int bar)
+ POD Foo(int bar, double bas)
+ POD Foo(QMap<QString,int> bar)
+ POD Foo(QList<QString> bar)
+ POD Foo(QMap<QString,int> bar, QMap<double,int> bas)
+ \endcode
+
+ A full example would look like this
+ \code
+ POD Foo(QList<QString> bar)
+ class MyType
+ {
+ SIGNAL(sendCustom(Foo foo));
+ };
+ \endcode
+
+ The code generated by repc creates a Q_GADGET class for each POD, with
+ corresponding Q_PROPERTY members for each type defined for the POD.
+
+ \section2 The ENUM type
+
+ It is often easier and cleaner to define an ENUM inside a class (see \l ENUM),
+ but if you need a standalone enum type, using the ENUM keyword outside of a
+ class definition can be helpful. This will generate a new class in your
+ header files that handles marshalling, etc.. The syntax is identical to \l
+ ENUM, with the exception that the declaration in this case is not contained
+ in a \c class declaration.
+
+ Related topics: \l {ENUM}, \l {USE_ENUM keyword}
+
+ \section2 USE_ENUM keyword
+
+ The USE_ENUM keyword was implemented before autogeneration via the ENUM
+ keyword was added. It is kept for backwards compatibility.
+
+ Related topics: \l {ENUM}, \l {The ENUM type}
+
+ \section2 Directives
+
+ The rep file defines an interface, but interfaces often require external
+ elements. In order to support this, repc will include any (single line)
+ directives at the top of the generated files. This allows you to, for
+ instance, use #include or #define directives that support the logic or
+ datatypes needed.
+
+ The repc tool currently ignores everything from the "#" symbol to the
+ end-of-line and adds that to the generated files. So multi-line
+ #if/#else/#endif statements and multi-line macros are not supported.
+
+ \section1 CMake functions
+
+ The CMake functions for generating source and replica types are listed below.
+
+ \annotatedlist cmake-macros-qtremoteobjects
+
+ \section1 qmake variables
+ \section2 REPC_REPLICA
+
+ Specifies the names of all rep files in the project that should be used to generate
+ replica header files.
+
+ For example:
+ \code
+ REPC_REPLICA = media.rep \
+ location.rep
+ \endcode
+
+ The generated file(s) will be of the form \c {rep_<replica file base>_replica.h}.
+
+ \section2 REPC_SOURCE
+
+ Specifies the names of all rep files in the project that should be used to generate
+ source header files.
+
+ For example:
+ \code
+ REPC_SOURCE = media.rep \
+ location.rep
+ \endcode
+
+ The generated file(s) will be of the form \c {rep_<replica file base>_source.h}.
+
+ \section2 REPC_MERGED
+
+ Specifies the names of all rep files in the project that should be used to generate
+ combined (source and replica) header files.
+
+ For example:
+ \code
+ REPC_MERGED = media.rep \
+ location.rep
+ \endcode
+
+ The generated file(s) will be of the form \c {rep_<replica file base>_merged.h}.
+
+ \note Typically sources and replicas live in separate processes or devices, so this variable
+ is not commonly used.
+
+ \section2 QOBJECT_REP
+
+ Specifies the names of existing QObject header files that should be used to generate corresponding
+ .rep files.
+*/
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2018 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+/*!
+\page qtremoteobjects-replica.html
+\title Qt Remote Objects Replica
+\brief Describes the concept of a replica and how it works as a surrogate object.
+\target Replica
+
+A QRemoteObjectReplica ("replica") is a surrogate object that has approximately
+the same API as the \l {Source} QObject it replicates. Additionally, there are
+a few properties and signals to make it possible to detect when the replica is
+initialized or if it loses its connection to the source object. There
+are a few other differences, notably, a constant property on the source cannot
+be constant on the replica. The value will not be known at the time when the
+replica is instantiated; it will only be known once the replica is initialized.
+For more information, see \l {Remote Object Interaction}.
+
+A compiled replica is a \l {QRemoteObjectReplica} based type, where the derived
+class definition is automatically generated by the \l {repc} compiler. When you
+use \l {CMake functions} or \l {qmake variables} for running the \l repc compiler,
+this makes the generation part of the build process. Although only a header is
+generated, it's a complete type. There is no public constructor, so you need to
+use the \l {QRemoteObjectNode::acquire} template function to create the Replica
+instance.
+
+A \l {QRemoteObjectDynamicReplica} can be generated at runtime. To do so, you
+call \l {QRemoteObjectNode::acquireDynamic()}, passing in the source name
+(a QString) as an argument. Dynamic replicas are a bit more verbose to use from
+C++, but they do not require compilation. Dynamic replicas do not support
+initial property values, or introspection until they have been initialized.
+
+An important difference between these two ways of creating replicas is the
+behavior before the replica is initialized. Since a dynamic replica only gets
+a metaObject after initialization, it has basically no API before
+initialization -- no properties, and no signals to connect slots to.
+
+Because metaObjects for compiled replicas are created at compile-time, their
+API is available when the replica is instantiated. You can even provide default
+values for properties in the template file, which are used until the replica is
+initialized with current values from the source.
+
+\section1 Replica Initialization
+
+A host node will share the list of sources that it hosts with every other node
+that connects to it. This host sends updates when sources are added to or
+removed from the list. In this way, a connected node will always know what
+sources it can attach itself to. Changes to a specific source are only
+propagated to nodes that have a replica of that source. Consequently, this
+avoids any unnecessary network traffic.
+
+When a node acquires a replica for a known source, it sends a request for that
+source to the host node. Upon receiving this request, the host creates a reply
+packet with the current values for all properties of that source. If the
+requested replica is \l{QRemoteObjectDynamicReplica}{dynamic}, the reply packet
+includes the API definition for the source. From then on, the replica's node
+will be included in the list of connections that receive changes to that
+source.
+
+If a replica is instantiated but its node is not connected to the node that
+hosts the requested source -- or that object lives in a host node process, but
+sharing/remoting has not been enabled for the QObject -- the Replica will still
+be created, but remain uninitialized.
+
+If, at a later time, the replica's node gets notified that the requested source
+is available from a connected node, at that point it will request the source
+and start the initialization process.
+
+If the connection to a host node is lost, the replica will transition to the
+invalid state. It will attempt to reconnect and will re-initialize if the
+connection is restored; this makes sure all properties are current.
+
+\section1 Replica Ownership
+
+The acquire methods return a pointer to the replica QObject instantiated by the
+node. The node has no way of knowing the replica's intended lifetime.
+Consequently, when the replica is not longer needed, it is the calling
+program's responsibility to delete it.
+
+You can instantiate multiple copies of the same replica. All replicas of the
+same source from a single node will share a private data member which handles
+the network communication. This means multiple instances of a replica do not
+introduce additional network traffic, although there will be some additional
+processing overhead. Failing to delete replicas will prevent the reference
+count on this private object from reaching 0, and cause unnecessary network
+communication until the calling process exits. For this reason, it is
+recommended to use \l {QScopedPointer} or \l {QSharedPointer} to help track
+the lifetime of replicas.
+
+*/
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2018 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+/*!
+\page qtremoteobjects-source.html
+\title Qt Remote Objects Source
+\brief Describes the concept of a source and how to use the source header that the repc generates.
+\target Source
+
+A QRemoteObjectSource ("source") is the QObject that is responsible for
+implementing the exposed API.
+
+At a high level, you can choose to use a QObject type directly as a source; or
+you can define the desired API in a \c{.rep} template for use with the
+\l {repc} compiler.
+
+If you already have a fully defined QObject, you can use it as a source by
+passing it to \l {QRemoteObjectHostBase::enableRemoting()}. This way, other
+processes or devices can then create
+\l{QRemoteObjectDynamicReplica}{dynamics replicas} of the object to interact
+with.
+
+For more information, see \l{Remote Object Interaction}.
+
+Letting repc generate a source header file for your project, using the
+\l {REPC_SOURCE} variable, provides three different options to implement the
+required API.
+
+Suppose your class name is Foo, you then have the following options:
+
+\list
+ \li \l {TypeSimpleSource} {FooSimpleSource} inheritance
+ \li \l {TypeSource} {FooSource} inheritance
+ \li \l {TypeAPI} {FooSourceAPI} usage with your own QObject
+\endlist
+
+For more details on how to create a \c{.rep} file, see \l{The rep file format}.
+
+\target TypeSimpleSource
+There is a <Type>SimpleSource class defined in the header, which provides the
+basic getter/setter methods for each property and implements data members of
+the correct property type in the header. "<Type>" here represents the class
+name from the \c{.rep} file, so if your class is of type "MyType" in the
+\c{.rep} file, then the generated header file will have a MyTypeSimpleSource
+class declared. This is a quick way to get started using the API. To use this
+class, you need to write a class that inherits from it and implement any slots
+defined, which are marked as pure virtual in the generated header file.
+You need to add the necessary logic to manage the exposed properties and emit
+signals, to your class as well.
+
+\target TypeSource
+If you need to hide your implementation details, use the second class declared
+in the header file, the <Type>Source class. This class' definition does not
+provide data members, and also makes the getter/setter functions pure virtual.
+While you may need to write more code, using this class gives you more
+flexibility in your implementation.
+
+\target TypeAPI
+The third class generated in the header is <Type>SourceAPI. This is a templated
+class, for use specifically by the templated version of
+\l {QRemoteObjectHostBase::enableRemoting()}, which allows you to use any
+QObject that supports the required API as the source. Use this class to hide or
+convert properties or signal/slot parameters. If your implementation
+does not provide the correct API, there will be compile-time warnings.
+
+\note Replicas and sources both derive from QObject; but their QObject API is
+\b never exposed. For instance, while a replica has a \l{QObject::}{destroyed}
+signal, the source's \l{QObject::}{destroyed} signal is not propagated. The
+source and each of its replica are unique QObjects with their own connections
+and lifetimes. Instead, the API that is exposed is defined by the \c{.rep}
+template used by repc. In the case of raw QObjects, all API elements are defined
+in the inheritance chain from a specific ancestor. The QObject's parent is always
+used, unless you define \c{Q_CLASSINFO("RemoteObject Type")} in an ancestor. If
+you use \c{Q_CLASSINFO("RemoteObject Type")}, that class's API is the lowest
+level of API used.
+
+\section1 Identifying Sources
+
+Because a host node can share more than one source, each source requires a name.
+All repc-generated headers include a way for the node to determine the class name:
+Q_CLASSINFO for replica, simplesource, or source types; or a static \c name()
+function for the SourceAPI type. If you pass your own QObject type to
+\l {QRemoteObjectHostBase::enableRemoting()}, the name is determined using the
+following logic:
+\list
+ \li A name can optionally be passed to \l {QRemoteObjectHostBase::enableRemoting()}.
+ If provided, that name is used.
+ \li If the object or any of its ancestors has Q_CLASSINFO of type
+ "RemoteObject Type" defined, that type name is used.
+ \li If the QObject's objectName is set, then it is used.
+ \li If none of the above are available, the call to
+ \l {QRemoteObjectHostBase::enableRemoting()} fails, returning false.
+\endlist
+*/
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2018 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+/*!
+\page qtremoteobjects-troubleshooting.html
+\title Troubleshooting Qt Remote Objects
+\section1 Troubleshooting
+
+QtRO includes a number of internal logging categories that can be used for further debugging:
+
+\code
+qt.remoteobjects
+qt.remoteobjects.io
+qt.remoteobjects.models
+\endcode
+
+*/
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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.LGPL3 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qconnection_local_backend_p.h"
+
+QT_BEGIN_NAMESPACE
+
+LocalClientIo::LocalClientIo(QObject *parent)
+ : QtROClientIoDevice(parent)
+ , m_socket(new QLocalSocket(this))
+{
+ connect(m_socket, &QLocalSocket::readyRead, this, &QtROClientIoDevice::readyRead);
+ connect(m_socket, &QLocalSocket::errorOccurred, this, &LocalClientIo::onError);
+ connect(m_socket, &QLocalSocket::stateChanged, this, &LocalClientIo::onStateChanged);
+}
+
+LocalClientIo::~LocalClientIo()
+{
+ close();
+}
+
+QIODevice *LocalClientIo::connection() const
+{
+ return m_socket;
+}
+
+void LocalClientIo::doClose()
+{
+ if (m_socket->isOpen()) {
+ connect(m_socket, &QLocalSocket::disconnected, this, &QObject::deleteLater);
+ m_socket->disconnectFromServer();
+ } else {
+ this->deleteLater();
+ }
+}
+
+void LocalClientIo::doDisconnectFromServer()
+{
+ m_socket->disconnectFromServer();
+}
+
+void LocalClientIo::connectToServer()
+{
+#ifdef Q_OS_ANDROID
+ if (!m_socket->socketOptions().testFlag(QLocalSocket::AbstractNamespaceOption))
+ qWarning() << "It is recommended to use 'localabstract' over 'local' on Android.";
+#endif
+ if (!isOpen())
+ m_socket->connectToServer(url().path());
+}
+
+bool LocalClientIo::isOpen() const
+{
+ return !isClosing() && (m_socket->state() == QLocalSocket::ConnectedState
+ || m_socket->state() == QLocalSocket::ConnectingState);
+}
+
+void LocalClientIo::onError(QLocalSocket::LocalSocketError error)
+{
+ qCDebug(QT_REMOTEOBJECT) << "onError" << error << m_socket->serverName();
+
+ switch (error) {
+ case QLocalSocket::ServerNotFoundError:
+ case QLocalSocket::UnknownSocketError:
+ case QLocalSocket::PeerClosedError:
+ //Host not there, wait and try again
+ emit shouldReconnect(this);
+ break;
+ case QLocalSocket::ConnectionError:
+ case QLocalSocket::ConnectionRefusedError:
+ //... TODO error reporting
+#ifdef Q_OS_UNIX
+ emit shouldReconnect(this);
+#endif
+ break;
+ default:
+ break;
+ }
+}
+
+void LocalClientIo::onStateChanged(QLocalSocket::LocalSocketState state)
+{
+ if (state == QLocalSocket::ClosingState && !isClosing()) {
+ m_socket->abort();
+ emit shouldReconnect(this);
+ }
+ if (state == QLocalSocket::ConnectedState)
+ initializeDataStream();
+}
+
+LocalServerIo::LocalServerIo(QLocalSocket *conn, QObject *parent)
+ : QtROServerIoDevice(parent), m_connection(conn)
+{
+ m_connection->setParent(this);
+ connect(conn, &QIODevice::readyRead, this, &QtROServerIoDevice::readyRead);
+ connect(conn, &QLocalSocket::disconnected, this, &QtROServerIoDevice::disconnected);
+}
+
+QIODevice *LocalServerIo::connection() const
+{
+ return m_connection;
+}
+
+void LocalServerIo::doClose()
+{
+ m_connection->disconnectFromServer();
+}
+
+LocalServerImpl::LocalServerImpl(QObject *parent)
+ : QConnectionAbstractServer(parent)
+{
+ connect(&m_server, &QLocalServer::newConnection, this, &QConnectionAbstractServer::newConnection);
+}
+
+LocalServerImpl::~LocalServerImpl()
+{
+ m_server.close();
+}
+
+QtROServerIoDevice *LocalServerImpl::configureNewConnection()
+{
+ if (!m_server.isListening())
+ return nullptr;
+
+ return new LocalServerIo(m_server.nextPendingConnection(), this);
+}
+
+bool LocalServerImpl::hasPendingConnections() const
+{
+ return m_server.hasPendingConnections();
+}
+
+QUrl LocalServerImpl::address() const
+{
+ QUrl result;
+ result.setPath(m_server.serverName());
+ result.setScheme(QRemoteObjectStringLiterals::local());
+
+ return result;
+}
+
+bool LocalServerImpl::listen(const QUrl &address)
+{
+#ifdef Q_OS_ANDROID
+ if (!m_server.socketOptions().testFlag(QLocalServer::AbstractNamespaceOption))
+ qWarning() << "It is recommended to use 'localabstract' over 'local' on Android.";
+#endif
+#ifdef Q_OS_UNIX
+ bool res = m_server.listen(address.path());
+ if (!res) {
+ QLocalServer::removeServer(address.path());
+ res = m_server.listen(address.path());
+ }
+ return res;
+#else
+ return m_server.listen(address.path());
+#endif
+}
+
+QAbstractSocket::SocketError LocalServerImpl::serverError() const
+{
+ return m_server.serverError();
+}
+
+void LocalServerImpl::close()
+{
+ m_server.close();
+}
+
+#ifdef Q_OS_LINUX
+
+AbstractLocalClientIo::AbstractLocalClientIo(QObject *parent)
+ : LocalClientIo(parent)
+{
+ m_socket->setSocketOptions(QLocalSocket::AbstractNamespaceOption);
+}
+
+AbstractLocalServerImpl::AbstractLocalServerImpl(QObject *parent)
+ : LocalServerImpl(parent)
+{
+ m_server.setSocketOptions(QLocalServer::AbstractNamespaceOption);
+}
+
+QUrl AbstractLocalServerImpl::address() const
+{
+ QUrl result;
+ result.setPath(m_server.serverName());
+ result.setScheme(QRemoteObjectStringLiterals::localabstract());
+
+ return result;
+}
+
+#endif // Q_OS_LINUX
+
+QT_END_NAMESPACE
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017-2015 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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.LGPL3 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QCONNECTIONCLIENTFACTORY_P_H
+#define QCONNECTIONCLIENTFACTORY_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qconnectionfactories_p.h"
+
+#include <QtNetwork/qlocalserver.h>
+#include <QtNetwork/qlocalsocket.h>
+
+QT_BEGIN_NAMESPACE
+
+class LocalClientIo : public QtROClientIoDevice
+{
+ Q_OBJECT
+
+public:
+ explicit LocalClientIo(QObject *parent = nullptr);
+ ~LocalClientIo() override;
+
+ QIODevice *connection() const override;
+ void connectToServer() override;
+ bool isOpen() const override;
+
+public Q_SLOTS:
+ void onError(QLocalSocket::LocalSocketError error);
+ void onStateChanged(QLocalSocket::LocalSocketState state);
+
+protected:
+ void doClose() override;
+ void doDisconnectFromServer() override;
+ QLocalSocket* m_socket;
+};
+
+#ifdef Q_OS_LINUX
+
+class AbstractLocalClientIo final : public LocalClientIo
+{
+ Q_OBJECT
+
+public:
+ explicit AbstractLocalClientIo(QObject *parent = nullptr);
+};
+
+#endif // Q_OS_LINUX
+
+class LocalServerIo final : public QtROServerIoDevice
+{
+ Q_OBJECT
+public:
+ explicit LocalServerIo(QLocalSocket *conn, QObject *parent = nullptr);
+
+ QIODevice *connection() const override;
+protected:
+ void doClose() override;
+
+private:
+ QLocalSocket *m_connection;
+};
+
+class LocalServerImpl : public QConnectionAbstractServer
+{
+ Q_OBJECT
+ Q_DISABLE_COPY(LocalServerImpl)
+
+public:
+ explicit LocalServerImpl(QObject *parent);
+ ~LocalServerImpl() override;
+
+ bool hasPendingConnections() const override;
+ QtROServerIoDevice *configureNewConnection() override;
+ QUrl address() const override;
+ bool listen(const QUrl &address) override;
+ QAbstractSocket::SocketError serverError() const override;
+ void close() override;
+
+protected:
+ QLocalServer m_server;
+};
+
+#ifdef Q_OS_LINUX
+
+class AbstractLocalServerImpl final : public LocalServerImpl
+{
+ Q_OBJECT
+
+public:
+ explicit AbstractLocalServerImpl(QObject *parent);
+ QUrl address() const override;
+};
+
+#endif // Q_OS_LINUX
+
+QT_END_NAMESPACE
+
+#endif
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017-2016 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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.LGPL3 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qconnection_qnx_backend_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QnxClientIo::QnxClientIo(QObject *parent)
+ : QtROClientIoDevice(parent)
+ , m_socket(new QQnxNativeIo(this))
+{
+ connect(m_socket, &QQnxNativeIo::readyRead, this, &QtROClientIoDevice::readyRead);
+ connect(m_socket,
+ static_cast<void(QQnxNativeIo::*)(QAbstractSocket::SocketError)>(&QQnxNativeIo::error),
+ this,
+ &QnxClientIo::onError);
+ connect(m_socket, &QQnxNativeIo::stateChanged, this, &QnxClientIo::onStateChanged);
+}
+
+QnxClientIo::~QnxClientIo()
+{
+ close();
+}
+
+QIODevice *QnxClientIo::connection() const
+{
+ return m_socket;
+}
+
+void QnxClientIo::doClose()
+{
+ if (m_socket->isOpen()) {
+ connect(m_socket, &QQnxNativeIo::disconnected, this, &QObject::deleteLater);
+ m_socket->disconnectFromServer();
+ } else {
+ deleteLater();
+ }
+}
+
+void QnxClientIo::doDisconnectFromServer()
+{
+ m_socket->disconnectFromServer();
+}
+
+void QnxClientIo::connectToServer()
+{
+ if (!isOpen())
+ m_socket->connectToServer(url().path());
+}
+
+bool QnxClientIo::isOpen() const
+{
+ return !isClosing() && (m_socket->state() == QAbstractSocket::ConnectedState
+ || m_socket->state() == QAbstractSocket::ConnectingState);
+}
+
+void QnxClientIo::onError(QAbstractSocket::SocketError error)
+{
+ qCDebug(QT_REMOTEOBJECT) << "onError" << error << m_socket->serverName();
+
+ switch (error) {
+ case QAbstractSocket::RemoteHostClosedError:
+ m_socket->close();
+ qCWarning(QT_REMOTEOBJECT) << "RemoteHostClosedError";
+ case QAbstractSocket::HostNotFoundError: //Host not there, wait and try again
+ case QAbstractSocket::AddressInUseError:
+ case QAbstractSocket::ConnectionRefusedError:
+ //... TODO error reporting
+ emit shouldReconnect(this);
+ break;
+ default:
+ break;
+ }
+}
+
+void QnxClientIo::onStateChanged(QAbstractSocket::SocketState state)
+{
+ if (state == QAbstractSocket::ClosingState && !isClosing()) {
+ m_socket->abort();
+ emit shouldReconnect(this);
+ } else if (state == QAbstractSocket::ConnectedState)
+ initializeDataStream();
+}
+
+QnxServerIo::QnxServerIo(QSharedPointer<QIOQnxSource> conn, QObject *parent)
+ : QtROServerIoDevice(parent), m_connection(conn)
+{
+ connect(conn.data(), &QIODevice::readyRead, this, &QtROServerIoDevice::readyRead);
+ connect(conn.data(), &QIOQnxSource::disconnected, this, &QtROServerIoDevice::disconnected);
+}
+
+QIODevice *QnxServerIo::connection() const
+{
+ return m_connection.data();
+}
+
+void QnxServerIo::doClose()
+{
+ m_connection->close();
+}
+
+QnxServerImpl::QnxServerImpl(QObject *parent)
+ : QConnectionAbstractServer(parent)
+{
+ connect(&m_server,
+ &QQnxNativeServer::newConnection,
+ this,
+ &QConnectionAbstractServer::newConnection);
+}
+
+QnxServerImpl::~QnxServerImpl()
+{
+ m_server.close();
+}
+
+QtROServerIoDevice *QnxServerImpl::configureNewConnection()
+{
+ if (!m_server.isListening())
+ return nullptr;
+
+ return new QnxServerIo(m_server.nextPendingConnection(), this);
+}
+
+bool QnxServerImpl::hasPendingConnections() const
+{
+ return m_server.hasPendingConnections();
+}
+
+QUrl QnxServerImpl::address() const
+{
+ QUrl result;
+ result.setPath(m_server.serverName());
+ result.setScheme(QStringLiteral("qnx"));
+
+ return result;
+}
+
+bool QnxServerImpl::listen(const QUrl &address)
+{
+ return m_server.listen(address.path());
+}
+
+QAbstractSocket::SocketError QnxServerImpl::serverError() const
+{
+ //TODO implement on QQnxNativeServer and here
+ //return m_server.serverError();
+ return QAbstractSocket::AddressInUseError;
+}
+
+void QnxServerImpl::close()
+{
+ close();
+}
+
+QT_END_NAMESPACE
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017-2016 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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.LGPL3 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QCONNECTIONQNXBACKEND_P_H
+#define QCONNECTIONQNXBACKEND_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qconnectionfactories_p.h"
+#include "qconnection_qnx_qiodevices.h"
+#include "qconnection_qnx_server.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ QtRO provides QtROClientIoDevice, QtROServerIoDevice and QConnectionAbstractServer
+ as abstract interfaces to allow different backends to be used by QtRO. The
+ concept behind these classes is that there needs to be a Host node, which
+ has an address that can be connected to. Then there is a client object,
+ which can be publicly constructed, and can connect to the server. When the
+ server gets a connection request, it creates the server side of the
+ connection, which communicates directly with the client. There are thus
+ three abstractions, one for the server, one for the client-side of the
+ connection, and the third for the server-side of the connection. The later
+ two need to inherit from QIODevice.
+
+ Creating a backend for something that is already implemented in Qt is a
+ matter of creating the three needed abstractions. In the case of creating a
+ QNX backend using QNX's Native Messaging, the backend needs to create the
+ Server (which has an address for accepting connections), the client
+ QIODevice, and the server side QIODevice. Since Native Messaging is one
+ way, and recommends using pulses to support two-way communication, the
+ logic for the client-side and server-side QIODevice are very different.
+ Thus, three additional backend classes are needed as well.
+
+ QnxClientIo implements the QtRO QtROClientIoDevice wrapper around the QNX
+ specific QQnxNativeIo QIODevice (the client-side QIODevice).
+
+ QnxServerIo implements the QtRO QtROServerIoDevice wrapper around the QNX
+ specific QIOQnxSource QIODevice (the server-side QIODevice).
+
+ QnxServerImpl implements the QtRO QConnectionAbstractServer wrapper around
+ the QNX specific QQnxNativeServer, which is the server object listening for
+ connections.
+
+ Not sure if it is of interest to the Qt community, but it seems like
+ QQnxNativeIo, QIOQnxSource and QQnxNativeServer could used as an optimized
+ QLocalServer/QLocalSocket QPA for QNX.
+*/
+
+class QnxClientIo final : public QtROClientIoDevice
+{
+ Q_OBJECT
+
+public:
+ explicit QnxClientIo(QObject *parent = nullptr);
+ ~QnxClientIo() override;
+
+ QIODevice *connection() const override;
+ void connectToServer() override;
+ bool isOpen() const override;
+
+public Q_SLOTS:
+ void onError(QAbstractSocket::SocketError error);
+ void onStateChanged(QAbstractSocket::SocketState state);
+
+protected:
+ void doClose() override;
+ void doDisconnectFromServer() override;
+private:
+ QQnxNativeIo *m_socket;
+};
+
+class QnxServerIo final : public QtROServerIoDevice
+{
+public:
+ explicit QnxServerIo(QSharedPointer<QIOQnxSource> conn, QObject *parent = nullptr);
+
+ QIODevice *connection() const override;
+protected:
+ void doClose() override;
+
+private:
+ //TODO Source or Replica
+ QSharedPointer<QIOQnxSource> m_connection;
+};
+
+class QnxServerImpl final : public QConnectionAbstractServer
+{
+ Q_OBJECT
+
+public:
+ explicit QnxServerImpl(QObject *parent);
+ ~QnxServerImpl() override;
+
+ bool hasPendingConnections() const override;
+ QtROServerIoDevice *configureNewConnection() override;
+ QUrl address() const override;
+ bool listen(const QUrl &address) override;
+ QAbstractSocket::SocketError serverError() const override;
+ void close() override;
+
+private:
+ QQnxNativeServer m_server;
+};
+
+QT_END_NAMESPACE
+
+#endif // QCONNECTIONQNXBACKEND_P_H
+
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017-2016 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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.LGPL3 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QNXIPCPRIVATE_GLOBAL_H
+#define QNXIPCPRIVATE_GLOBAL_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <sys/neutrino.h>
+#include <sys/dispatch.h>
+#include <sys/siginfo.h>
+#include <unistd.h> // provides SETIOV
+#include <sys/netmgr.h> //FOR ND_LOCAL_NODE
+#include <errno.h>
+#include <QtCore/qthread.h>
+#ifdef USE_HAM
+# include <ha/ham.h>
+#endif
+
+#define WARNING(cmd) qCWarning(QT_REMOTEOBJECT) << "Warning " #cmd << strerror(errno) \
+ << Q_FUNC_INFO << __FILE__ << __LINE__;
+
+#define WARN_ON_ERROR(cmd, ...) if (cmd(__VA_ARGS__) == -1) qCWarning(QT_REMOTEOBJECT) \
+ << "Error " #cmd << strerror(errno) << Q_FUNC_INFO << __FILE__ << __LINE__;
+
+#define WARN_AND_RETURN_ON_ERROR(cmd, retval, ...) if (cmd(__VA_ARGS__) == -1) \
+ { qCWarning(QT_REMOTEOBJECT) << "Error " #cmd << strerror(errno) \
+ << Q_FUNC_INFO << __FILE__ << __LINE__; return (retval); }
+
+#define FATAL_ON_ERROR(cmd, ...) if (cmd(__VA_ARGS__) == -1) qFatal("Error %s: %s %s %s %d", \
+ #cmd, strerror(errno), Q_FUNC_INFO, __FILE__, __LINE__);
+
+QT_BEGIN_NAMESPACE
+
+const int MAX_RETRIES = 3;
+
+enum MsgType : uint16_t { REPLICA_INIT = _IO_MAX+100,
+ REPLICA_TX_RECV,
+ SOURCE_TX_RESP,
+ SOURCE_TX_RESP_REPEAT,
+ };
+enum PulseType : uint8_t { SOURCE_TX_RQ = _PULSE_CODE_MINAVAIL+42,
+ REPLICA_WRITE,
+ TERMINATE,
+ NODE_DEATH
+ };
+union recv_msgs
+{
+ struct _pulse pulse;
+ uint16_t type;
+};
+
+template <typename T>
+class Thread : public QThread
+{
+public:
+ Thread(T *obj, const QString &name = QString()) : QThread(), m_obj(obj)
+ {
+ if (!name.isEmpty())
+ setObjectName(name);
+ }
+ void run() override
+ {
+ m_obj->thread_func();
+ }
+private:
+ T *m_obj;
+};
+
+QT_END_NAMESPACE
+
+#endif // QNXIPCPRIVATE_GLOBAL_H
+
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017-2016 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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.LGPL3 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qconnection_qnx_global_p.h"
+#include "qconnection_qnx_qiodevices.h"
+#include "qconnection_qnx_server.h"
+#include "qconnection_qnx_qiodevices_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QQnxNativeIoPrivate::QQnxNativeIoPrivate()
+ : QIODevicePrivate()
+ , serverId(-1)
+ , channelId(-1)
+ , connectionId(-1)
+ , state(QAbstractSocket::UnconnectedState)
+ , obuffer(new QRingBuffer)
+ , thread(this, QStringLiteral("NativeIo"))
+{
+ //This lets us set msgType before any MsgSend
+ //and have the value sent as the header/type.
+ SETIOV(tx_iov + 0, &msgType, sizeof(msgType));
+ SIGEV_NONE_INIT(&tx_pulse);
+}
+
+QQnxNativeIoPrivate::~QQnxNativeIoPrivate()
+{
+ teardownConnection();
+}
+
+bool QQnxNativeIoPrivate::establishConnection()
+{
+ //On the client side, we need to create the channel/connection
+ //to listen for the server's send pulse.
+ if (channelId == -1) {
+ const int channel = ChannelCreate(0);
+ if (channel == -1) {
+ WARNING(ChannelCreate)
+ return false;
+ }
+ channelId = channel;
+ }
+
+ const int connection = ConnectAttach(ND_LOCAL_NODE, 0, channelId, _NTO_SIDE_CHANNEL, 0);
+ if (connection == -1) {
+ WARNING(ConnectAttach)
+ teardownConnection();
+ return false;
+ }
+ connectionId = connection;
+
+ SIGEV_PULSE_INIT(&tx_pulse, connection, SIGEV_PULSE_PRIO_INHERIT, SOURCE_TX_RQ, 0);
+ SIGEV_MAKE_UPDATEABLE(&tx_pulse);
+ qCDebug(QT_REMOTEOBJECT) << "in establish" << tx_pulse.sigev_code << SOURCE_TX_RQ;
+
+ if (MsgRegisterEvent(&tx_pulse, connectionId) == -1) {
+ qCWarning(QT_REMOTEOBJECT) << "Unable to register event for server" << serverName;
+ teardownConnection();
+ return false;
+ }
+
+ const int id = name_open(qPrintable(serverName), 0);
+ if (id == -1) {
+ qCWarning(QT_REMOTEOBJECT) << "Unable to connect to server" << serverName;
+ teardownConnection();
+ return false;
+ }
+ serverId = id;
+
+ thread.start();
+
+ Q_Q(QQnxNativeIo);
+ qCDebug(QT_REMOTEOBJECT) << "Before INIT: ServerId" << id << "name" << serverName << q;
+ SETIOV(tx_iov + 1, &tx_pulse, sizeof(tx_pulse));
+ SETIOV(tx_iov + 2, &channelId, sizeof(channelId));
+
+ //Send our registration message to the server
+ msgType = MsgType::REPLICA_INIT;
+ //We send tx_pulse along. When the server want to
+ //transmit data, it sends the pulse back to us.
+ //When we see that (in receive_thread) we send a
+ //message and get the server's tx data in the reply.
+ //
+ //We transmit the channelId as well - it is only used
+ //if HAM is enabled, but this will prevent a possible
+ //mismatch between code compiled with vs. without HAM
+ //(which could happen if we ever use QCONN between
+ //devices)
+ if (MsgSendv(serverId, tx_iov, 3, nullptr, 0) == -1) {
+ WARNING(MsgSendv)
+ teardownConnection();
+ return false;
+ }
+
+ state = QAbstractSocket::ConnectedState;
+ emit q->stateChanged(state);
+
+ return true;
+}
+
+void QQnxNativeIoPrivate::teardownConnection()
+{
+ Q_Q(QQnxNativeIo);
+ state = QAbstractSocket::ClosingState;
+ emit q->stateChanged(state);
+
+ stopThread();
+
+ state = QAbstractSocket::UnconnectedState;
+ emit q->stateChanged(state);
+}
+
+void QQnxNativeIoPrivate::stopThread()
+{
+ if (thread.isRunning()) {
+ for (int count = 0; count < MAX_RETRIES; ++count) {
+ if (MsgSendPulse(connectionId, -1, TERMINATE, 0) == -1) {
+ if (errno == EAGAIN) {
+ usleep(5000 + (rand() % 10) * 10000); //5 to 95 msec
+ qCWarning(QT_REMOTEOBJECT) << "Retrying terminate pulse";
+ continue;
+ }
+ qFatal("MsgSendPulse failed on terminate pulse. Error = %s", strerror(errno));
+ }
+ thread.wait();
+ return;
+ }
+ if (errno == EAGAIN)
+ qFatal("MsgSendPulse failed on terminate pulse (max retries)");
+ }
+}
+
+// method (run in a thread) to watch for connections and handle receiving data
+void QQnxNativeIoPrivate::thread_func()
+{
+ Q_Q(QQnxNativeIo);
+
+ _pulse pulse;
+
+ qCDebug(QT_REMOTEOBJECT) << "Client thread_func running";
+
+ bool running = true;
+ int nTxRequestToIgnore = 0;
+ while (running) {
+ int rcvid = MsgReceivePulse(channelId, &pulse, sizeof(pulse), nullptr);
+ if (rcvid == -1)
+ continue;
+
+ qCDebug(QT_REMOTEOBJECT) << "MsgReceivePulse unblocked, code =" << pulse.code;
+
+ switch (pulse.code) {
+ case SOURCE_TX_RQ: //The Source object wants to send us data
+ {
+ const int len = pulse.value.sival_int;
+ qCDebug(QT_REMOTEOBJECT, "TX request with len = %d, tx ignore = %d", len, nTxRequestToIgnore);
+ if (nTxRequestToIgnore) {
+ --nTxRequestToIgnore;
+ break;
+ }
+
+ int bytesLeft;
+
+ msgType = MsgType::SOURCE_TX_RESP;
+ ibLock.lockForWrite();
+ iov_t reply_vector[2];
+ SETIOV(reply_vector, &bytesLeft, sizeof(bytesLeft));
+ SETIOV(reply_vector+1, buffer.reserve(len), len);
+ const int res = MsgSendv(serverId, tx_iov, 1, reply_vector, 2);
+
+ if (res == -1) {
+ buffer.chop(len);
+ ibLock.unlock();
+ WARNING(MsgSendv);
+ break;
+ }
+ ibLock.unlock();
+
+ qCDebug(QT_REMOTEOBJECT) << "Reply said bytesLeft =" << bytesLeft;
+
+ if (bytesLeft) {
+ msgType = MsgType::SOURCE_TX_RESP_REPEAT;
+ ibLock.lockForWrite();
+ SETIOV(reply_vector, &nTxRequestToIgnore, sizeof(nTxRequestToIgnore));
+ SETIOV(reply_vector+1, buffer.reserve(bytesLeft), bytesLeft);
+ const int res = MsgSendv(serverId, tx_iov, 1, reply_vector, 2);
+ if (res == -1) {
+ buffer.chop(bytesLeft);
+ ibLock.unlock();
+ WARNING(MsgSendv);
+ break;
+ }
+ ibLock.unlock();
+ qCDebug(QT_REMOTEOBJECT) << "Reply2 said nTxRequestToIgnore =" << nTxRequestToIgnore;
+ }
+
+ QMetaObject::invokeMethod(q, "readyRead", Qt::QueuedConnection);
+ }
+ break;
+ case REPLICA_WRITE: //Our node has data to send
+ {
+ const int len = pulse.value.sival_int;
+ obLock.lockForWrite(); //NAR (Not-An-Error)
+ const QByteArray payload = obuffer->read();
+ obLock.unlock();
+ Q_ASSERT(len == payload.length());
+
+ msgType = MsgType::REPLICA_TX_RECV;
+ SETIOV(tx_iov + 1, payload.constData(), len);
+ if (MsgSendvs(serverId, tx_iov, 2, nullptr, 0) == -1) {
+ WARNING(MsgSendvs);
+ obLock.lockForWrite();
+ if (obuffer->isEmpty()) {
+ obuffer->append(payload);
+ } else {
+ //Since QRingBuffer just holds a QList of
+ //QByteArray, copying the QByteArrays to
+ //another container is cheap.
+ QRingBuffer *newBuffer = new QRingBuffer;
+ newBuffer->append(payload);
+ while (!obuffer->isEmpty())
+ newBuffer->append(obuffer->read());
+ obuffer.reset(newBuffer);
+ }
+ obLock.unlock();
+ WARNING(MsgSendvs);
+ }
+ }
+ break;
+ case TERMINATE:
+ running = false;
+ continue;
+ case NODE_DEATH:
+ qCWarning(QT_REMOTEOBJECT) << "Host node died";
+ running = false;
+ emit q->error(QAbstractSocket::RemoteHostClosedError);
+ continue;
+ default:
+ /* some other unexpected message */
+ qCWarning(QT_REMOTEOBJECT) << "unexpected pulse type:" << pulse.type << __FILE__ << __LINE__;
+ WARN_ON_ERROR(MsgError, rcvid, ENOSYS)
+ break;
+ }
+ }
+
+ if (serverId >= 0) {
+ WARN_ON_ERROR(name_close, serverId)
+ serverId = -1;
+ }
+
+ if (tx_pulse.sigev_notify & SIGEV_FLAG_HANDLE) {
+ WARN_ON_ERROR(MsgUnregisterEvent, &tx_pulse);
+ SIGEV_NONE_INIT(&tx_pulse);
+ }
+
+ if (connectionId >= 0) {
+ WARN_ON_ERROR(ConnectDetach, connectionId)
+ connectionId = -1;
+ }
+
+ if (channelId >= 0) {
+ WARN_ON_ERROR(ChannelDestroy, channelId)
+ channelId = -1;
+ }
+
+ qCDebug(QT_REMOTEOBJECT) << "Client thread_func stopped";
+}
+
+QQnxNativeIo::QQnxNativeIo(QObject *parent)
+ : QIODevice(*new QQnxNativeIoPrivate, parent)
+{
+}
+
+QQnxNativeIo::~QQnxNativeIo()
+{
+ close();
+}
+
+bool QQnxNativeIo::connectToServer(QIODevice::OpenMode openMode)
+{
+ Q_D(QQnxNativeIo);
+ Q_UNUSED(openMode)
+
+ if (state() == QAbstractSocket::ConnectedState ||
+ state() == QAbstractSocket::ConnectingState) {
+ setErrorString(QStringLiteral("Already connected"));
+ emit error(QAbstractSocket::OperationError);
+ return false;
+ }
+
+ const int omMask = QIODevice::Append | QIODevice::Truncate | QIODevice::Text;
+ if (openMode & omMask)
+ qCWarning(QT_REMOTEOBJECT, "Tried to open using unsupported open mode flags.");
+
+ d->errorString.clear();
+ d->state = QAbstractSocket::ConnectingState;
+ emit stateChanged(d->state);
+
+ if (d->serverName.isEmpty()) {
+ setErrorString(QStringLiteral("serverName not set"));
+ emit error(QAbstractSocket::HostNotFoundError);
+ return false;
+ }
+
+ QIODevice::open(openMode & (~omMask));
+
+ if (!d->establishConnection()) {
+ QIODevice::close();
+ qCWarning(QT_REMOTEOBJECT, "Failed to connect to server");
+ emit error(QAbstractSocket::UnknownSocketError);
+ return false;
+ }
+
+ emit stateChanged(d->state);
+
+ return true;
+}
+
+bool QQnxNativeIo::connectToServer(const QString &name, QIODevice::OpenMode openMode)
+{
+ setServerName(name);
+ return connectToServer(openMode);
+}
+
+void QQnxNativeIo::disconnectFromServer()
+{
+ close();
+}
+
+void QQnxNativeIo::setServerName(const QString &name)
+{
+ Q_D(QQnxNativeIo);
+
+ if (d->state != QAbstractSocket::UnconnectedState) {
+ qCWarning(QT_REMOTEOBJECT) << "QQnxNativeIo::setServerName() called while not unconnected";
+ return;
+ }
+
+ d->serverName = name;
+}
+
+QString QQnxNativeIo::serverName() const
+{
+ Q_D(const QQnxNativeIo);
+ return d->serverName;
+}
+
+void QQnxNativeIo::abort()
+{
+ Q_D(QQnxNativeIo);
+
+ d->stopThread();
+ //Don't need mutex since thread is stopped
+ d->obuffer->clear();
+ d->buffer.clear();
+
+ d->state = QAbstractSocket::UnconnectedState;
+ emit stateChanged(d->state);
+ QIODevice::close();
+}
+
+bool QQnxNativeIo::isSequential() const
+{
+ return true;
+}
+
+qint64 QQnxNativeIo::bytesAvailable() const
+{
+ Q_D(const QQnxNativeIo);
+
+ d->ibLock.lockForRead();
+ qint64 size = d->buffer.size();
+ d->ibLock.unlock();
+
+ return size;
+}
+
+qint64 QQnxNativeIo::bytesToWrite() const
+{
+ Q_D(const QQnxNativeIo);
+
+ d->obLock.lockForRead();
+ qint64 size = d->obuffer->size();
+ d->obLock.unlock();
+
+ return size;
+}
+
+bool QQnxNativeIo::open(QIODevice::OpenMode openMode)
+{
+ const int omMask = QIODevice::Append | QIODevice::Truncate | QIODevice::Text;
+ if (openMode & omMask)
+ qCWarning(QT_REMOTEOBJECT, "Tried to open using unsupported open mode flags.");
+
+ return connectToServer(openMode & (~omMask));
+}
+
+void QQnxNativeIo::close()
+{
+ Q_D(QQnxNativeIo);
+
+ if (!isOpen())
+ return;
+
+ d->teardownConnection();
+
+ d->obuffer->clear();
+ d->buffer.clear();
+ QIODevice::close();
+}
+
+QAbstractSocket::SocketState QQnxNativeIo::state() const
+{
+ Q_D(const QQnxNativeIo);
+ return d->state;
+}
+
+bool QQnxNativeIo::waitForBytesWritten(int msecs)
+{
+ //TODO - This method isn't used by Qt Remote Objects, but would
+ //need to be implemented before this class could be used as a
+ //generic QIODevice.
+ Q_UNUSED(msecs)
+ Q_ASSERT(false);
+ return false;
+}
+
+bool QQnxNativeIo::waitForReadyRead(int msecs)
+{
+ //TODO - This method isn't used by Qt Remote Objects, but would
+ //need to be implemented before this class could be used as a
+ //generic QIODevice.
+ Q_UNUSED(msecs)
+ Q_ASSERT(false);
+ return false;
+}
+
+qint64 QQnxNativeIo::readData(char *data, qint64 size)
+{
+ Q_D(QQnxNativeIo);
+ qint64 read;
+
+ if (!isReadable())
+ return 0;
+
+ d->ibLock.lockForWrite(); //NAR (Not-An-Error)
+ read = d->buffer.read(data, size);
+ d->ibLock.unlock();
+
+ return read;
+}
+
+qint64 QQnxNativeIo::writeData(const char *data, qint64 size)
+{
+ Q_D(QQnxNativeIo);
+
+ if (!isWritable())
+ return 0;
+
+ if (size < 0 || size > INT_MAX) {
+ qCWarning(QT_REMOTEOBJECT) << "Invalid size (" << size << ") passed to QtRO QNX backend writeData().";
+ return -1;
+ }
+
+ int isize = static_cast<int>(size);
+
+ d->obLock.lockForWrite();
+ d->obuffer->append(QByteArray(data, isize));
+ d->obLock.unlock();
+
+ WARN_AND_RETURN_ON_ERROR(MsgSendPulse, -1, d->connectionId, -1, PulseType::REPLICA_WRITE, isize)
+
+ return size;
+}
+
+/* QIOQnxSource ***************************************************************/
+
+QIOQnxSourcePrivate::QIOQnxSourcePrivate(int _rcvid)
+ : QIODevicePrivate()
+ , rcvid(_rcvid)
+ , state(QAbstractSocket::ConnectedState)
+{
+}
+
+QIOQnxSource::QIOQnxSource(int rcvid, QObject *parent)
+ : QIODevice(*new QIOQnxSourcePrivate(rcvid), parent)
+{
+ setOpenMode(QIODevice::ReadWrite);
+}
+
+QIOQnxSource::~QIOQnxSource()
+{
+ close();
+}
+
+bool QIOQnxSource::isSequential() const
+{
+ return true;
+}
+
+qint64 QIOQnxSource::bytesAvailable() const
+{
+ Q_D(const QIOQnxSource);
+
+ d->ibLock.lockForRead();
+ qint64 size = d->buffer.size();
+ d->ibLock.unlock();
+
+ return size;
+}
+
+qint64 QIOQnxSource::bytesToWrite() const
+{
+ Q_D(const QIOQnxSource);
+
+ d->obLock.lockForRead();
+ qint64 size = d->obuffer.size();
+ d->obLock.unlock();
+
+ return size;
+}
+
+bool QIOQnxSource::open(QIODevice::OpenMode openMode)
+{
+ Q_UNUSED(openMode)
+ return false;
+}
+
+void QIOQnxSource::onDisconnected()
+{
+ close();
+ emit disconnected();
+}
+
+void QIOQnxSource::close()
+{
+ Q_D(QIOQnxSource);
+
+ if (!isOpen())
+ return;
+
+ d->state = QAbstractSocket::ClosingState;
+ emit stateChanged(d->state);
+
+ d->state = QAbstractSocket::UnconnectedState;
+ emit stateChanged(d->state);
+
+ d->obuffer.clear();
+ d->buffer.clear();
+ QIODevice::close();
+}
+
+QAbstractSocket::SocketState QIOQnxSource::state() const
+{
+ Q_D(const QIOQnxSource);
+ return d->state;
+}
+
+bool QIOQnxSource::waitForBytesWritten(int msecs)
+{
+ //TODO - This method isn't used by Qt Remote Objects, but would
+ //need to be implemented before this class could be used as a
+ //generic QIODevice.
+ Q_UNUSED(msecs)
+ Q_ASSERT(false);
+ return false;
+}
+
+bool QIOQnxSource::waitForReadyRead(int msecs)
+{
+ //TODO - This method isn't used by Qt Remote Objects, but would
+ //need to be implemented before this class could be used as a
+ //generic QIODevice.
+ Q_UNUSED(msecs)
+ Q_ASSERT(false);
+ return false;
+}
+
+qint64 QIOQnxSource::readData(char *data, qint64 size)
+{
+ Q_D(QIOQnxSource);
+ qint64 read;
+
+ if (!isReadable())
+ return 0;
+
+ d->ibLock.lockForWrite(); //NAR (Not-An-Error)
+ read = d->buffer.read(data, size);
+ d->ibLock.unlock();
+
+ return read;
+}
+
+qint64 QIOQnxSource::writeData(const char *data, qint64 size)
+{
+ Q_D(QIOQnxSource);
+
+ if (!isWritable())
+ return 0;
+
+ if (size < 0 || size > INT_MAX) {
+ qCWarning(QT_REMOTEOBJECT) << "Invalid size (" << size << ") passed to QtRO QNX backend writeData().";
+ return -1;
+ }
+
+ int isize = static_cast<int>(size);
+
+ d->obLock.lockForWrite();
+ d->obuffer.append(QByteArray(data, isize));
+ d->obLock.unlock();
+
+ if (!d->m_serverClosing.loadRelaxed()) {
+ d->m_event.sigev_value.sival_int = isize;
+ WARN_ON_ERROR(MsgDeliverEvent, d->rcvid, &(d->m_event))
+ }
+
+ return size;
+}
+
+QT_END_NAMESPACE
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017-2016 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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.LGPL3 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQNXNATIVEIO_H
+#define QQNXNATIVEIO_H
+
+#include <QtNetwork/qabstractsocket.h>
+#include <QtRemoteObjects/qtremoteobjectglobal.h>
+
+QT_BEGIN_NAMESPACE
+
+/*
+ * The implementation of the Source and Replica
+ * side QIODevice look like they will be fairly
+ * different, including different APIs. So
+ * creating a 2nd derived type for the source.
+ *
+ * TODO: revisit if these can be combined into a
+ * single type.
+ *
+ * With two types, QQnxNativeIo will need to get
+ * Source or Replica added. Not sure what intuitive
+ * names are yet. So for now, QQnxNativeIo is the
+ * Replica side, QIOQnxSourcePrivate is the Source
+ * side. Revisit the name as this matures.
+ *
+*/
+class QQnxNativeIoPrivate;
+class QIOQnxSourcePrivate;
+
+class Q_REMOTEOBJECTS_EXPORT QQnxNativeIo : public QIODevice
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QQnxNativeIo)
+
+public:
+ explicit QQnxNativeIo(QObject *parent = nullptr);
+ ~QQnxNativeIo() override;
+
+ bool connectToServer(OpenMode openMode = ReadWrite);
+ bool connectToServer(const QString &name, OpenMode openMode = ReadWrite);
+ void disconnectFromServer();
+
+ void setServerName(const QString &name);
+ QString serverName() const;
+
+ void abort();
+ bool isSequential() const override;
+ qint64 bytesAvailable() const override;
+ qint64 bytesToWrite() const override;
+ bool open(OpenMode openMode = ReadWrite) override;
+ void close() override;
+ QAbstractSocket::SocketError error() const;
+ bool flush();
+ bool isValid() const;
+
+ QAbstractSocket::SocketState state() const;
+ bool waitForBytesWritten(int msecs = 30000) override;
+ bool waitForConnected(int msecs = 30000);
+ bool waitForDisconnected(int msecs = 30000);
+ bool waitForReadyRead(int msecs = 30000) override;
+
+Q_SIGNALS:
+ void connected();
+ void disconnected();
+ void error(QAbstractSocket::SocketError socketError);
+ void stateChanged(QAbstractSocket::SocketState socketState);
+
+protected:
+ qint64 readData(char*, qint64) override;
+ qint64 writeData(const char*, qint64) override;
+
+private:
+ Q_DISABLE_COPY(QQnxNativeIo)
+};
+Q_DECLARE_TYPEINFO(QQnxNativeIo, Q_RELOCATABLE_TYPE);
+
+class Q_REMOTEOBJECTS_EXPORT QIOQnxSource : public QIODevice
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QIOQnxSource)
+
+public:
+ explicit QIOQnxSource(int rcvid, QObject *parent = nullptr);
+ ~QIOQnxSource() override;
+
+ bool isSequential() const override;
+ qint64 bytesAvailable() const override;
+ qint64 bytesToWrite() const override;
+ void close() override;
+ QAbstractSocket::SocketError error() const;
+ bool isValid() const;
+
+ QAbstractSocket::SocketState state() const;
+ bool waitForBytesWritten(int msecs = 30000) override;
+ bool waitForConnected(int msecs = 30000);
+ bool waitForDisconnected(int msecs = 30000);
+ bool waitForReadyRead(int msecs = 30000) override;
+
+Q_SIGNALS:
+ void disconnected();
+ void error(QAbstractSocket::SocketError socketError);
+ void stateChanged(QAbstractSocket::SocketState socketState);
+
+protected:
+ qint64 readData(char*, qint64) override;
+ qint64 writeData(const char*, qint64) override;
+ bool open(OpenMode openMode) override;
+
+private Q_SLOTS:
+ void onDisconnected();
+
+private:
+ Q_DISABLE_COPY(QIOQnxSource)
+ friend class QQnxNativeServerPrivate;
+ friend class QnxServerIo;
+};
+Q_DECLARE_TYPEINFO(QIOQnxSource, Q_RELOCATABLE_TYPE);
+
+QT_END_NAMESPACE
+
+#endif // QQNXNATIVEIO_H
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017-2016 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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.LGPL3 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQNXNATIVEIO_P_H
+#define QQNXNATIVEIO_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qconnection_qnx_qiodevices.h"
+#include "qconnection_qnx_global_p.h"
+
+#include <QtCore/qreadwritelock.h>
+#include <QtCore/qscopedpointer.h>
+
+#include "private/qiodevice_p.h"
+#include "private/qringbuffer_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QQnxNativeIoPrivate : public QIODevicePrivate
+{
+ Q_DECLARE_PUBLIC(QQnxNativeIo)
+
+ mutable QReadWriteLock ibLock;
+ mutable QReadWriteLock obLock;
+
+public:
+ QQnxNativeIoPrivate();
+ ~QQnxNativeIoPrivate();
+ void thread_func();
+ bool establishConnection();
+ void teardownConnection();
+ void stopThread();
+ QString serverName;
+ int serverId, channelId, connectionId;
+ sigevent tx_pulse;
+ QAbstractSocket::SocketState state;
+ QScopedPointer<QRingBuffer> obuffer;
+ MsgType msgType;
+ iov_t tx_iov[3], rx_iov[2];
+ Thread<QQnxNativeIoPrivate> thread;
+};
+
+class QIOQnxSourcePrivate : public QIODevicePrivate
+{
+ Q_DECLARE_PUBLIC(QIOQnxSource)
+
+ friend class QQnxNativeServerPrivate;
+
+ mutable QReadWriteLock ibLock;
+ mutable QReadWriteLock obLock;
+
+public:
+ QIOQnxSourcePrivate(int _rcvid);
+ int rcvid;
+ QAbstractSocket::SocketState state;
+ MsgType msgType;
+ sigevent m_event;
+ QRingBuffer obuffer;
+ QAtomicInt m_serverClosing;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQNXNATIVEIO_P_H
+
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017-2016 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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.LGPL3 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qconnection_qnx_global_p.h"
+#include "qconnection_qnx_qiodevices_p.h"
+#include "qconnection_qnx_server_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QQnxNativeServer::QQnxNativeServer(QObject *parent)
+ : QObject(*new QQnxNativeServerPrivate, parent)
+{
+}
+
+QQnxNativeServer::~QQnxNativeServer()
+{
+}
+
+void QQnxNativeServer::close()
+{
+ Q_D(QQnxNativeServer);
+ d->teardownServer();
+}
+
+bool QQnxNativeServer::hasPendingConnections() const
+{
+ Q_D(const QQnxNativeServer);
+ d->mutex.lock();
+ const int len = d->pending.length();
+ d->mutex.unlock();
+ return len > 0;
+}
+
+bool QQnxNativeServer::isListening() const
+{
+ Q_D(const QQnxNativeServer);
+ return !(d->serverName.isEmpty());
+}
+
+bool QQnxNativeServer::listen(const QString &name)
+{
+ Q_D(QQnxNativeServer);
+ if (isListening()) {
+ qCWarning(QT_REMOTEOBJECT) << "QQnxNativeServer::listen() called when already listening";
+ return false;
+ }
+
+ if (name.isEmpty()) {
+ d->error = QAbstractSocket::HostNotFoundError;
+ QString function = QLatin1String("QQnxNativeServer::listen");
+ d->errorString = tr("%1: Name error").arg(function);
+ return false;
+ }
+
+ if (!d->listen(name)) {
+ d->serverName.clear();
+ return false;
+ }
+
+ d->serverName = name;
+ return true;
+}
+
+QSharedPointer<QIOQnxSource> QQnxNativeServer::nextPendingConnection()
+{
+ Q_D(QQnxNativeServer);
+ d->mutex.lock();
+ Q_ASSERT(d->pending.length() > 0);
+ auto io = d->pending.takeFirst();
+ d->mutex.unlock();
+ return io;
+}
+
+QString QQnxNativeServer::serverName() const
+{
+ Q_D(const QQnxNativeServer);
+ return d->serverName;
+}
+
+bool QQnxNativeServer::waitForNewConnection(int msec, bool *timedOut)
+{
+ //TODO - This method isn't used by Qt Remote Objects, but would
+ //need to be implemented before this class could be used as a
+ //connection server (like QTcpServer or QLocalServer).
+ Q_UNUSED(msec)
+ Q_UNUSED(timedOut)
+ Q_ASSERT(false);
+ return false;
+}
+
+void QQnxNativeServer::onSourceClosed()
+{
+ Q_D(QQnxNativeServer);
+ QIOQnxSource *conn = qobject_cast<QIOQnxSource *>(sender());
+ Q_ASSERT(conn);
+
+ d->cleanupIOSource(conn);
+}
+
+QQnxNativeServerPrivate::QQnxNativeServerPrivate()
+ : error(QAbstractSocket::UnknownSocketError)
+ , thread(this, QStringLiteral("NativeServer"))
+{
+}
+
+QQnxNativeServerPrivate::~QQnxNativeServerPrivate()
+{
+ if (thread.isRunning())
+ teardownServer();
+}
+
+// method (run in a thread) to watch for connections and handle receiving data
+void QQnxNativeServerPrivate::thread_func()
+{
+ struct _msg_info msg_info;
+ recv_msgs recv_buf;
+ QList<iov_t> resp_repeat_iov(5);
+
+ qCDebug(QT_REMOTEOBJECT) << "Server thread_func running";
+
+ while (running.loadRelaxed()) {
+ // wait for messages and pulses
+ int rcvid = MsgReceive(attachStruct->chid, &recv_buf, sizeof(_pulse), &msg_info);
+ qCDebug(QT_REMOTEOBJECT) << "MsgReceive unblocked. Rcvid" << rcvid << " Scoid" << msg_info.scoid;
+ if (rcvid == -1) {
+ if (errno != ESRCH) // ESRCH means the channel closed
+ WARNING(MsgReceive)
+ break;
+ }
+
+ if (0 == rcvid) {
+ qCDebug(QT_REMOTEOBJECT) << "Pulse" << recv_buf.pulse.code;
+ /* we received a pulse
+ */
+ switch (recv_buf.pulse.code) {
+ case _PULSE_CODE_DISCONNECT:
+ {
+ /* a client has disconnected. Verify that it is
+ * our client, and if so, clean up our saved state
+ */
+ const int scoid = recv_buf.pulse.scoid;
+ const QSet<int> coids = connections.take(scoid);
+ for (int coid : coids)
+ {
+ const uint64_t uid = static_cast<uint64_t>(scoid) << 32 | static_cast<uint32_t>(coid);
+ QSharedPointer<QIOQnxSource> io;
+ mutex.lock();
+ if (sources.contains(uid))
+ io = sources.take(uid);
+ mutex.unlock();
+#ifdef USE_HAM
+ ham_action_t *action = hamActions.take(uid);
+ ham_action_remove(action, 0);
+ ham_action_handle_free(action);
+#endif
+
+ if (!io.isNull()) {
+ io->d_func()->m_serverClosing.ref();
+ QMetaObject::invokeMethod(io.data(),"onDisconnected",Qt::QueuedConnection);
+ }
+ }
+
+ /* always do the ConnectDetach() */
+ //Don't care about return value
+ ConnectDetach(recv_buf.pulse.scoid);
+ qCDebug(QT_REMOTEOBJECT) << "disconnect from client" << recv_buf.pulse.scoid;
+ }
+ break;
+ case _PULSE_CODE_COIDDEATH:
+ {
+ /* a connection has gone away. Verify that it is
+ * our client, and if so, clean up our saved state
+ */
+ const int coid = recv_buf.pulse.value.sival_int;
+
+ if (ConnectServerInfo(0, coid, nullptr) != coid) {
+ const int scoid = recv_buf.pulse.scoid;
+ if (connections.value(scoid).contains(coid))
+ connections[scoid].remove(coid);
+ QSharedPointer<QIOQnxSource> io;
+ const uint64_t uid = static_cast<uint64_t>(scoid) << 32 | static_cast<uint32_t>(coid);
+ mutex.lock();
+ if (sources.contains(uid))
+ io = sources.take(uid);
+ mutex.unlock();
+#ifdef USE_HAM
+ ham_action_t *action = hamActions.take(uid);
+ ham_action_remove(action, 0);
+ ham_action_handle_free(action);
+#endif
+
+ if (!io.isNull()) {
+ io->d_func()->m_serverClosing.ref();
+ QMetaObject::invokeMethod(io.data(),"onDisconnected",Qt::QueuedConnection);
+ }
+ qCDebug(QT_REMOTEOBJECT) << "Connection dropped" << coid;
+ }
+ break;
+ }
+ break;
+ case _PULSE_CODE_UNBLOCK:
+ if (running.loadRelaxed()) {
+ // did we forget to Reply to our client?
+ qCWarning(QT_REMOTEOBJECT) << "got an unblock pulse, did you forget to reply to your client?";
+ WARN_ON_ERROR(MsgError, recv_buf.pulse.value.sival_int, EINTR)
+ }
+ break;
+ default:
+ qCWarning(QT_REMOTEOBJECT) << "unexpected pulse code: " << recv_buf.pulse.code << __FILE__ << __LINE__;
+ break;
+ }
+ continue;
+ }
+
+ /* not an error, not a pulse, therefore a message */
+ switch (recv_buf.type)
+ {
+ qCDebug(QT_REMOTEOBJECT) << "Msg Received" << recv_buf.type;
+
+ case _IO_CONNECT:
+ /* _IO_CONNECT because someone did a name_open() to us and we are
+ * in the network case (gns running). We must EOK it. */
+ if (connections.contains(msg_info.scoid)
+ && connections.value(msg_info.scoid).contains(msg_info.coid))
+ {
+ qCWarning(QT_REMOTEOBJECT) << "Already connected rcvid seen" << connections << rcvid;
+ FATAL_ON_ERROR(MsgError, rcvid, EADDRINUSE)
+ } else {
+ if (!connections.contains(msg_info.scoid))
+ connections.insert(msg_info.scoid, QSet<int>());
+ connections[msg_info.scoid] << msg_info.coid;
+ qCDebug(QT_REMOTEOBJECT) << "New connection (qns)" << msg_info.coid << msg_info.scoid;
+ const uint64_t uid = static_cast<uint64_t>(msg_info.scoid) << 32 | static_cast<uint32_t>(msg_info.coid);
+ createSource(rcvid, uid, msg_info.pid); // Reads more and then calls MsgReply
+ }
+ break;
+
+ case MsgType::REPLICA_INIT:
+ qCDebug(QT_REMOTEOBJECT) << "MsgType::INIT received" << rcvid << msg_info.scoid << msg_info.tid << msg_info.chid << msg_info.coid;
+ //Check if this is a new connection (not gns)
+ if (connections.contains(msg_info.scoid)
+ && connections.value(msg_info.scoid).contains(msg_info.coid))
+ {
+ qCWarning(QT_REMOTEOBJECT) << "Already connected rcvid seen" << connections << rcvid;
+ FATAL_ON_ERROR(MsgError, rcvid, EADDRINUSE)
+ } else {
+ if (!connections.contains(msg_info.scoid))
+ connections.insert(msg_info.scoid, QSet<int>());
+ connections[msg_info.scoid] << msg_info.coid;
+ qCDebug(QT_REMOTEOBJECT) << "New connection (non-gns)" << rcvid << msg_info.coid << msg_info.scoid;
+ const uint64_t uid = static_cast<uint64_t>(msg_info.scoid) << 32 | static_cast<uint32_t>(msg_info.coid);
+ createSource(rcvid, uid, msg_info.pid); // Reads more and then calls MsgReply
+ }
+
+ break;
+ case MsgType::SOURCE_TX_RESP:
+ {
+ WARN_ON_ERROR(MsgInfo, rcvid, &msg_info);
+ const uint64_t uid = static_cast<uint64_t>(msg_info.scoid) << 32 | static_cast<uint32_t>(msg_info.coid);
+ mutex.lock();
+ Q_ASSERT(sources.contains(uid));
+ auto io = sources.value(uid);
+ mutex.unlock();
+
+ io->d_func()->obLock.lockForWrite(); //NAR (Not-An-Error)
+ const QByteArray data = io->d_func()->obuffer.read();
+ const int bytesLeft = io->d_func()->obuffer.size();
+ io->d_func()->obLock.unlock();
+
+ qCDebug(QT_REMOTEOBJECT) << "server received SOURCE_TX_RESP with length" << msg_info.dstmsglen << "/" << data.length() << "Available:" << bytesLeft;
+ Q_ASSERT(data.length() == static_cast<int>(msg_info.dstmsglen - sizeof(bytesLeft)));
+
+ iov_t reply_vector[2];
+ SETIOV(reply_vector, &bytesLeft, sizeof(bytesLeft));
+ SETIOV(reply_vector+1, data.data(), data.length());
+
+ FATAL_ON_ERROR(MsgReplyv, rcvid, EOK, reply_vector, 2)
+ }
+ break;
+ case MsgType::SOURCE_TX_RESP_REPEAT:
+ {
+ WARN_ON_ERROR(MsgInfo, rcvid, &msg_info);
+ const uint64_t uid = static_cast<uint64_t>(msg_info.scoid) << 32 | static_cast<uint32_t>(msg_info.coid);
+ mutex.lock();
+ Q_ASSERT(sources.contains(uid));
+ auto io = sources.value(uid);
+ mutex.unlock();
+
+ int len_taken = 0;
+ const int to_send = msg_info.dstmsglen - sizeof(int); //Exclude the buffer count
+ QByteArrayList qba_array;
+ io->d_func()->obLock.lockForWrite(); //NAR (Not-An-Error)
+ qCDebug(QT_REMOTEOBJECT) << "server received SOURCE_TX_RESP_REPEAT with length" << msg_info.dstmsglen << "Available:" << io->d_func()->obuffer.size();
+ while (len_taken != to_send)
+ {
+ QByteArray data = io->d_func()->obuffer.read();
+ qba_array << data;
+ len_taken += data.length();
+ if (data.length() == 0) { // We somehow reached the end
+ qCWarning(QT_REMOTEOBJECT) << "Reached the end of the buffer before getting the requested amount of data." << Q_FUNC_INFO << __FILE__ << __LINE__;
+ break;
+ }
+ }
+ qCDebug(QT_REMOTEOBJECT) << "grabbing more data" << len_taken << to_send << qba_array.length();
+ io->d_func()->obLock.unlock();
+
+ Q_ASSERT(len_taken == to_send);
+ const int buffers_taken = qba_array.length();
+
+ resp_repeat_iov.resize(buffers_taken+1);
+ SETIOV(&resp_repeat_iov[0], &buffers_taken, sizeof(buffers_taken));
+ for (int i = 1; i <= buffers_taken; ++i)
+ SETIOV(&resp_repeat_iov[i], qba_array.at(i-1).constData(), qba_array.at(i-1).length());
+ FATAL_ON_ERROR(MsgReplyv, rcvid, EOK, resp_repeat_iov.data(), buffers_taken+1)
+ }
+ break;
+ case MsgType::REPLICA_TX_RECV:
+ {
+ FATAL_ON_ERROR(MsgInfo,rcvid, &msg_info)
+ const uint64_t uid = static_cast<uint64_t>(msg_info.scoid) << 32 | static_cast<uint32_t>(msg_info.coid);
+ mutex.lock();
+ Q_ASSERT(sources.contains(uid));
+ auto io = sources.value(uid);
+ mutex.unlock();
+
+ //Long-lock, use buffer+memcpy if we run into trouble
+ io->d_func()->ibLock.lockForWrite();
+ qint32 toRead = msg_info.msglen-sizeof(MsgType);
+ char *payload = io->d_func()->buffer.reserve(toRead);
+
+ const int res = MsgRead(rcvid, payload, toRead, sizeof(MsgType));
+ if (-1 == res) {
+ io->d_func()->buffer.chop(toRead);
+ io->d_func()->ibLock.unlock();
+ qFatal("MsgRead");
+ }
+ Q_ASSERT(res == toRead);
+
+ if (res < toRead)
+ io->d_func()->buffer.chop(toRead - res);
+ io->d_func()->ibLock.unlock();
+
+ FATAL_ON_ERROR(MsgReply, rcvid, EOK, nullptr, 0)
+
+ qCDebug(QT_REMOTEOBJECT) << "server received REPLICA_TX_RECV" << payload << toRead;
+
+ emit io->readyRead();
+ }
+ break;
+ default:
+ /* some other unexpected message */
+ qCWarning(QT_REMOTEOBJECT) << "unexpected message type" << recv_buf.type << __FILE__ << __LINE__;
+ WARN_ON_ERROR(MsgError, rcvid, ENOSYS)
+ break;
+ }
+ }
+ mutex.lock();
+ for (auto io: sources)
+ io->d_func()->m_serverClosing.ref();
+ mutex.unlock();
+ name_detach(attachStruct, 0);
+ attachStruct = nullptr;
+ qCDebug(QT_REMOTEOBJECT) << "Server thread_func stopped";
+}
+
+bool QQnxNativeServerPrivate::listen(const QString &name)
+{
+ attachStruct = name_attach(nullptr, qPrintable(name), 0);
+ if (attachStruct == nullptr) {
+ qCDebug(QT_REMOTEOBJECT, "name_attach call failed");
+ return false;
+ }
+ terminateCoid = ConnectAttach(ND_LOCAL_NODE, 0, attachStruct->chid, _NTO_SIDE_CHANNEL, 0);
+ if (terminateCoid == -1) {
+ qCDebug(QT_REMOTEOBJECT, "ConnectAttach failed");
+ return false;
+ }
+
+ running.ref();
+ thread.start();
+
+ return true;
+}
+
+void QQnxNativeServerPrivate::cleanupIOSource(QIOQnxSource *conn)
+{
+ QSharedPointer<QIOQnxSource> io;
+ mutex.lock();
+ for (auto i = sources.begin(), end = sources.end(); i != end; ++i) {
+ if (i.value().data() == conn) {
+ io = std::move(i.value());
+ sources.erase(i);
+ break;
+ }
+ }
+ mutex.unlock();
+ if (!io.isNull()) {
+ io->d_func()->m_serverClosing.ref();
+ io->close();
+ }
+}
+
+void QQnxNativeServerPrivate::teardownServer()
+{
+ if (attachStruct == nullptr)
+ return;
+
+ running.deref();
+ MsgSendPulse(terminateCoid, SIGEV_PULSE_PRIO_INHERIT, _PULSE_CODE_UNBLOCK, 0);
+ ConnectDetach(terminateCoid);
+ thread.wait();
+
+ //Existing QIOQnxSources will be deleted along with object
+ //threads gone, don't need to use mutex
+ sources.clear();
+#ifdef USE_HAM
+ if (hamAvailable)
+ closeHamResources();
+#endif
+}
+
+void QQnxNativeServerPrivate::createSource(int rcvid, uint64_t uid, pid_t toPid)
+{
+ Q_Q(QQnxNativeServer);
+#ifndef USE_HAM
+ Q_UNUSED(toPid)
+#endif
+ auto io = QSharedPointer<QIOQnxSource>(new QIOQnxSource(rcvid));
+ io->moveToThread(q->thread());
+ QObject::connect(io.data(), &QIOQnxSource::aboutToClose,
+ q, &QQnxNativeServer::onSourceClosed);
+
+ QIOQnxSourcePrivate *iop = io->d_func();
+ FATAL_ON_ERROR(MsgRead, rcvid, &(iop->m_event), sizeof(sigevent), sizeof(MsgType))
+ int sentChannelId;
+ FATAL_ON_ERROR(MsgRead, rcvid, &sentChannelId, sizeof(int), sizeof(MsgType)+sizeof(sigevent))
+ FATAL_ON_ERROR(MsgReply, rcvid, EOK, nullptr, 0)
+
+ mutex.lock();
+ sources.insert(uid, io);
+ pending.append(io);
+ mutex.unlock();
+
+ //push an event into the main threads eventloop to emit newConnection.
+ QMetaObject::invokeMethod(q,"newConnection",Qt::QueuedConnection);
+#ifdef USE_HAM
+ if (!hamInitialized) {
+ hamInitialized = true;
+ hamAvailable = initializeHam();
+ }
+ if (hamAvailable)
+ configureHamDeath(sentChannelId, toPid, uid);
+#endif
+}
+
+#ifdef USE_HAM
+bool QQnxNativeServerPrivate::initializeHam()
+{
+ if (access("/proc/ham",F_OK) != 0) {
+ WARNING(access(/proc/ham))
+ return false;
+ }
+ ham_connect(0);
+ pid_t pid = getpid();
+ hamEntityHandle = ham_attach(qPrintable(serverName), ND_LOCAL_NODE, pid, NULL, 0);
+ if (!hamEntityHandle) {
+ WARNING(ham_attach)
+ ham_disconnect(0);
+ return false;
+ }
+ hamConditionHandle = ham_condition(hamEntityHandle, CONDDEATH, "death", 0);
+ if (!hamConditionHandle) {
+ WARNING(ham_condition)
+ ham_detach(hamEntityHandle, 0);
+ ham_entity_handle_free(hamEntityHandle);
+ ham_disconnect(0);
+ return false;
+ }
+ qCDebug(QT_REMOTEOBJECT, "HAM initialized for %s (pid = %d)", qPrintable(serverName), pid);
+ return true;
+}
+
+void QQnxNativeServerPrivate::configureHamDeath(int sentChannelId, pid_t toPid, uint64_t uid)
+{
+ char identifier[25];
+ snprintf(identifier, 25, "%d_%d", toPid, sentChannelId);
+ ham_action_t *a = ham_action_notify_pulse(hamConditionHandle, identifier,
+ ND_LOCAL_NODE, toPid,
+ sentChannelId, NODE_DEATH, 0, 0);
+ if (!a)
+ WARNING(ham_action_notify_pulse)
+ else
+ hamActions.insert(uid, a);
+}
+
+void QQnxNativeServerPrivate::closeHamResources()
+{
+ ham_entity_handle_free(hamEntityHandle);
+ ham_condition_handle_free(hamConditionHandle);
+ ham_disconnect(0);
+}
+#endif
+
+QT_END_NAMESPACE
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017-2016 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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.LGPL3 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQNXNATIVESERVER_H
+#define QQNXNATIVESERVER_H
+
+#include <QtNetwork/qabstractsocket.h>
+#include <QtRemoteObjects/qtremoteobjectglobal.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQnxNativeServerPrivate;
+class QQnxNativeIo;
+class QIOQnxSource;
+
+class Q_REMOTEOBJECTS_EXPORT QQnxNativeServer : public QObject
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QQnxNativeServer)
+
+Q_SIGNALS:
+ void newConnection();
+
+public:
+ explicit QQnxNativeServer(QObject *parent = nullptr);
+ ~QQnxNativeServer();
+
+ void close();
+ bool hasPendingConnections() const;
+ bool isListening() const;
+ bool listen(const QString &name);
+ QSharedPointer<QIOQnxSource> nextPendingConnection();
+ QString serverName() const;
+ bool waitForNewConnection(int msec = 0, bool *timedOut = nullptr);
+
+private Q_SLOTS:
+ void onSourceClosed();
+
+private:
+ Q_DISABLE_COPY(QQnxNativeServer)
+ friend class QIOQnxSource;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQNXNATIVESERVER_H
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017-2016 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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.LGPL3 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQNXNATIVESERVER_P_H
+#define QQNXNATIVESERVER_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "private/qobject_p.h"
+#include "qconnection_qnx_server.h"
+#include "qconnection_qnx_global_p.h"
+
+#include <QtCore/qatomic.h>
+#include <QtCore/qmutex.h>
+#include <QtCore/qsharedpointer.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQnxNativeServerPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QQnxNativeServer)
+
+public:
+ QQnxNativeServerPrivate();
+
+ ~QQnxNativeServerPrivate();
+
+ void thread_func();
+
+ void cleanupIOSource(QIOQnxSource *conn);
+ void teardownServer();
+ void createSource(int rcvid, uint64_t uid, pid_t toPid);
+#ifdef USE_HAM
+ bool initializeHam();
+ void configureHamDeath(int sentChannelId, pid_t toPid, uint64_t uid);
+ void closeHamResources();
+#endif
+
+ bool listen(const QString &name);
+ QString errorString;
+ QAbstractSocket::SocketError error;
+ QString serverName;
+ name_attach_t *attachStruct;
+ QHash<int, QSet<int> > connections;
+ QHash<uint64_t, QSharedPointer<QIOQnxSource>> sources;
+ QList<QSharedPointer<QIOQnxSource>> pending;
+ QAtomicInt running;
+ Thread<QQnxNativeServerPrivate> thread;
+ mutable QMutex mutex;
+ int terminateCoid;
+#ifdef USE_HAM
+ ham_entity_t *hamEntityHandle;
+ ham_condition_t *hamConditionHandle;
+ QHash<uint64_t, ham_action_t*> hamActions;
+ bool hamAvailable = false;
+ bool hamInitialized = false;
+#endif
+};
+
+QT_END_NAMESPACE
+
+#endif // QQNXNATIVESERVER_P_H
+
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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.LGPL3 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qconnection_tcpip_backend_p.h"
+
+#include <QtNetwork/qhostinfo.h>
+
+QT_BEGIN_NAMESPACE
+
+TcpClientIo::TcpClientIo(QObject *parent)
+ : QtROClientIoDevice(parent)
+ , m_socket(new QTcpSocket(this))
+{
+ connect(m_socket, &QTcpSocket::readyRead, this, &QtROClientIoDevice::readyRead);
+ connect(m_socket, &QAbstractSocket::errorOccurred, this, &TcpClientIo::onError);
+ connect(m_socket, &QTcpSocket::stateChanged, this, &TcpClientIo::onStateChanged);
+}
+
+TcpClientIo::~TcpClientIo()
+{
+ close();
+}
+
+QIODevice *TcpClientIo::connection() const
+{
+ return m_socket;
+}
+
+void TcpClientIo::doClose()
+{
+ if (m_socket->isOpen()) {
+ connect(m_socket, &QTcpSocket::disconnected, this, &QObject::deleteLater);
+ m_socket->disconnectFromHost();
+ } else {
+ this->deleteLater();
+ }
+}
+
+void TcpClientIo::doDisconnectFromServer()
+{
+ m_socket->disconnectFromHost();
+}
+
+void TcpClientIo::connectToServer()
+{
+ if (isOpen())
+ return;
+ QHostAddress address(url().host());
+ if (address.isNull()) {
+ const QList<QHostAddress> addresses = QHostInfo::fromName(url().host()).addresses();
+ Q_ASSERT_X(addresses.size() >= 1, Q_FUNC_INFO, url().toString().toLatin1().data());
+ address = addresses.first();
+ }
+
+ m_socket->connectToHost(address, quint16(url().port()));
+}
+
+bool TcpClientIo::isOpen() const
+{
+ return (!isClosing() && (m_socket->state() == QAbstractSocket::ConnectedState
+ || m_socket->state() == QAbstractSocket::ConnectingState));
+}
+
+void TcpClientIo::onError(QAbstractSocket::SocketError error)
+{
+ qCDebug(QT_REMOTEOBJECT) << "onError" << error;
+
+ switch (error) {
+ case QAbstractSocket::HostNotFoundError: //Host not there, wait and try again
+ case QAbstractSocket::ConnectionRefusedError:
+ case QAbstractSocket::NetworkError:
+ emit shouldReconnect(this);
+ break;
+ case QAbstractSocket::AddressInUseError:
+ //... TODO error reporting
+ break;
+ default:
+ break;
+ }
+}
+
+void TcpClientIo::onStateChanged(QAbstractSocket::SocketState state)
+{
+ if (state == QAbstractSocket::ClosingState && !isClosing()) {
+ m_socket->abort();
+ emit shouldReconnect(this);
+ }
+ if (state == QAbstractSocket::ConnectedState)
+ initializeDataStream();
+}
+
+
+TcpServerIo::TcpServerIo(QTcpSocket *conn, QObject *parent)
+ : QtROServerIoDevice(parent), m_connection(conn)
+{
+ m_connection->setParent(this);
+ connect(conn, &QIODevice::readyRead, this, &QtROServerIoDevice::readyRead);
+ connect(conn, &QAbstractSocket::disconnected, this, &QtROServerIoDevice::disconnected);
+}
+
+QIODevice *TcpServerIo::connection() const
+{
+ return m_connection;
+}
+
+void TcpServerIo::doClose()
+{
+ m_connection->disconnectFromHost();
+}
+
+
+
+TcpServerImpl::TcpServerImpl(QObject *parent)
+ : QConnectionAbstractServer(parent)
+{
+ connect(&m_server, &QTcpServer::newConnection, this, &QConnectionAbstractServer::newConnection);
+}
+
+TcpServerImpl::~TcpServerImpl()
+{
+ close();
+}
+
+QtROServerIoDevice *TcpServerImpl::configureNewConnection()
+{
+ if (!m_server.isListening())
+ return nullptr;
+
+ return new TcpServerIo(m_server.nextPendingConnection(), this);
+}
+
+bool TcpServerImpl::hasPendingConnections() const
+{
+ return m_server.hasPendingConnections();
+}
+
+QUrl TcpServerImpl::address() const
+{
+ return m_originalUrl;
+}
+
+bool TcpServerImpl::listen(const QUrl &address)
+{
+ QHostAddress host(address.host());
+ if (host.isNull()) {
+ if (address.host().isEmpty()) {
+ host = QHostAddress::Any;
+ } else {
+ qCWarning(QT_REMOTEOBJECT) << address.host() << " is not an IP address, trying to resolve it";
+ QHostInfo info = QHostInfo::fromName(address.host());
+ if (info.addresses().isEmpty())
+ host = QHostAddress::Any;
+ else
+ host = info.addresses().constFirst();
+ }
+ }
+
+ bool ret = m_server.listen(host, quint16(address.port()));
+ if (ret) {
+ m_originalUrl.setScheme(QLatin1String("tcp"));
+ m_originalUrl.setHost(m_server.serverAddress().toString());
+ m_originalUrl.setPort(m_server.serverPort());
+ }
+ return ret;
+}
+
+QAbstractSocket::SocketError TcpServerImpl::serverError() const
+{
+ return m_server.serverError();
+}
+
+void TcpServerImpl::close()
+{
+ m_server.close();
+}
+
+QT_END_NAMESPACE
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017-2015 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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.LGPL3 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QCONNECTIONTCPIPBACKEND_P_H
+#define QCONNECTIONTCPIPBACKEND_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qconnectionfactories_p.h"
+
+#include <QtNetwork/qtcpserver.h>
+#include <QtNetwork/qtcpsocket.h>
+
+QT_BEGIN_NAMESPACE
+
+class TcpClientIo final : public QtROClientIoDevice
+{
+ Q_OBJECT
+
+public:
+ explicit TcpClientIo(QObject *parent = nullptr);
+ ~TcpClientIo() override;
+
+ QIODevice *connection() const override;
+ void connectToServer() override;
+ bool isOpen() const override;
+
+public Q_SLOTS:
+ void onError(QAbstractSocket::SocketError error);
+ void onStateChanged(QAbstractSocket::SocketState state);
+
+protected:
+ void doClose() override;
+ void doDisconnectFromServer() override;
+
+private:
+ QTcpSocket *m_socket;
+};
+
+class TcpServerIo final : public QtROServerIoDevice
+{
+ Q_OBJECT
+public:
+ explicit TcpServerIo(QTcpSocket *conn, QObject *parent = nullptr);
+
+ QIODevice *connection() const override;
+protected:
+ void doClose() override;
+
+private:
+ QTcpSocket *m_connection;
+};
+
+class TcpServerImpl final : public QConnectionAbstractServer
+{
+ Q_OBJECT
+ Q_DISABLE_COPY(TcpServerImpl)
+
+public:
+ explicit TcpServerImpl(QObject *parent);
+ ~TcpServerImpl() override;
+
+ bool hasPendingConnections() const override;
+ QtROServerIoDevice *configureNewConnection() override;
+ QUrl address() const override;
+ bool listen(const QUrl &address) override;
+ QAbstractSocket::SocketError serverError() const override;
+ void close() override;
+
+private:
+ QTcpServer m_server;
+ QUrl m_originalUrl; // necessary because of a QHostAddress bug
+};
+
+QT_END_NAMESPACE
+#endif // QCONNECTIONTCPIPBACKEND_P_H
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017-2015 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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.LGPL3 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qconnectionfactories_p.h"
+#include "qremoteobjectpacket_p.h"
+
+// BEGIN: Backends
+#if defined(Q_OS_QNX)
+#include "qconnection_qnx_backend_p.h"
+#endif
+#include "qconnection_local_backend_p.h"
+#include "qconnection_tcpip_backend_p.h"
+// END: Backends
+
+QT_BEGIN_NAMESPACE
+
+using namespace QtRemoteObjects;
+
+class QtROFactoryLoader
+{
+public:
+ QtROClientFactory clientFactory;
+ QtROServerFactory serverFactory;
+};
+
+Q_GLOBAL_STATIC(QtROFactoryLoader, loader)
+
+inline bool fromDataStream(QDataStream &in, QRemoteObjectPacketTypeEnum &type, QString &name)
+{
+ quint16 _type;
+ in >> _type;
+ type = Invalid;
+ switch (_type) {
+ case Handshake: type = Handshake; break;
+ case InitPacket: type = InitPacket; break;
+ case InitDynamicPacket: type = InitDynamicPacket; break;
+ case AddObject: type = AddObject; break;
+ case RemoveObject: type = RemoveObject; break;
+ case InvokePacket: type = InvokePacket; break;
+ case InvokeReplyPacket: type = InvokeReplyPacket; break;
+ case PropertyChangePacket: type = PropertyChangePacket; break;
+ case ObjectList: type = ObjectList; break;
+ case Ping: type = Ping; break;
+ case Pong: type = Pong; break;
+ default:
+ qCWarning(QT_REMOTEOBJECT_IO) << "Invalid packet received" << _type;
+ }
+ if (type == Invalid)
+ return false;
+ if (type == ObjectList)
+ return true;
+ in >> name;
+ qCDebug(QT_REMOTEOBJECT_IO) << "Packet received of type" << type << "for object" << name;
+ return true;
+}
+
+/*!
+ All communication between nodes happens through some form of QIODevice with
+ an associated QDataStream to handle marshalling of Qt types. QtROIoDeviceBase
+ is an abstract base class that provides a consistent interface to QtRO, yet
+ can be extended to support different types of QIODevice.
+ */
+QtROIoDeviceBase::QtROIoDeviceBase(QObject *parent) : QObject(*new QtROIoDeviceBasePrivate, parent) { }
+
+QtROIoDeviceBase::QtROIoDeviceBase(QtROIoDeviceBasePrivate &dptr, QObject *parent) : QObject(dptr, parent) { }
+
+QtROIoDeviceBase::~QtROIoDeviceBase()
+{
+}
+
+bool QtROIoDeviceBase::read(QRemoteObjectPacketTypeEnum &type, QString &name)
+{
+ Q_D(QtROIoDeviceBase);
+ qCDebug(QT_REMOTEOBJECT_IO) << deviceType() << "read()" << d->m_curReadSize << bytesAvailable();
+
+ if (d->m_curReadSize == 0) {
+ if (bytesAvailable() < static_cast<int>(sizeof(quint32)))
+ return false;
+
+ d->m_dataStream >> d->m_curReadSize;
+ }
+
+ qCDebug(QT_REMOTEOBJECT_IO) << deviceType() << "read()-looking for map" << d->m_curReadSize
+ << bytesAvailable();
+
+ if (bytesAvailable() < d->m_curReadSize)
+ return false;
+
+ d->m_curReadSize = 0;
+ return fromDataStream(d->m_dataStream, type, name);
+}
+
+void QtROIoDeviceBase::write(const QByteArray &data)
+{
+ Q_D(QtROIoDeviceBase);
+ if (connection()->isOpen() && !d->m_isClosing)
+ connection()->write(data);
+}
+
+void QtROIoDeviceBase::write(const QByteArray &data, qint64 size)
+{
+ Q_D(QtROIoDeviceBase);
+ if (connection()->isOpen() && !d->m_isClosing)
+ connection()->write(data.data(), size);
+}
+
+bool QtROIoDeviceBase::isOpen() const
+{
+ return !isClosing();
+}
+
+void QtROIoDeviceBase::close()
+{
+ Q_D(QtROIoDeviceBase);
+ d->m_isClosing = true;
+ doClose();
+}
+
+qint64 QtROIoDeviceBase::bytesAvailable() const
+{
+ return connection()->bytesAvailable();
+}
+
+void QtROIoDeviceBase::initializeDataStream()
+{
+ Q_D(QtROIoDeviceBase);
+ d->m_dataStream.setDevice(connection());
+ d->m_dataStream.resetStatus();
+}
+
+bool QtROIoDeviceBase::isClosing() const
+{
+ Q_D(const QtROIoDeviceBase);
+ return d->m_isClosing;
+}
+
+void QtROIoDeviceBase::addSource(const QString &name)
+{
+ Q_D(QtROIoDeviceBase);
+ d->m_remoteObjects.insert(name);
+}
+
+void QtROIoDeviceBase::removeSource(const QString &name)
+{
+ Q_D(QtROIoDeviceBase);
+ d->m_remoteObjects.remove(name);
+}
+
+QSet<QString> QtROIoDeviceBase::remoteObjects() const
+{
+ Q_D(const QtROIoDeviceBase);
+ return d->m_remoteObjects;
+}
+
+QtROClientIoDevice::QtROClientIoDevice(QObject *parent) : QtROIoDeviceBase(*new QtROClientIoDevicePrivate, parent)
+{
+}
+
+QtROClientIoDevice::~QtROClientIoDevice()
+{
+ if (!isClosing())
+ close();
+}
+
+void QtROClientIoDevice::disconnectFromServer()
+{
+ doDisconnectFromServer();
+ emit shouldReconnect(this);
+}
+
+QUrl QtROClientIoDevice::url() const
+{
+ Q_D(const QtROClientIoDevice);
+ return d->m_url;
+}
+
+QString QtROClientIoDevice::deviceType() const
+{
+ return QStringLiteral("QtROClientIoDevice");
+}
+
+void QtROClientIoDevice::setUrl(const QUrl &url)
+{
+ Q_D(QtROClientIoDevice);
+ d->m_url = url;
+}
+
+/*!
+ The Qt servers create QIODevice derived classes from handleConnection. The
+ problem is that they behave differently, so this class adds some
+ consistency.
+ */
+QtROServerIoDevice::QtROServerIoDevice(QObject *parent) : QtROIoDeviceBase(parent)
+{
+}
+
+QString QtROServerIoDevice::deviceType() const
+{
+ return QStringLiteral("QtROServerIoDevice");
+}
+
+QConnectionAbstractServer::QConnectionAbstractServer(QObject *parent)
+ : QObject(parent)
+{
+}
+
+QConnectionAbstractServer::~QConnectionAbstractServer()
+{
+}
+
+QtROServerIoDevice *QConnectionAbstractServer::nextPendingConnection()
+{
+ QtROServerIoDevice *iodevice = configureNewConnection();
+ iodevice->initializeDataStream();
+ return iodevice;
+}
+
+QtROExternalIoDevice::QtROExternalIoDevice(QIODevice *device, QObject *parent)
+ : QtROIoDeviceBase(*new QtROExternalIoDevicePrivate(device), parent)
+{
+ Q_D(QtROExternalIoDevice);
+ initializeDataStream();
+ connect(device, &QIODevice::aboutToClose, this, [d]() { d->m_isClosing = true; });
+ connect(device, &QIODevice::readyRead, this, &QtROExternalIoDevice::readyRead);
+ auto meta = device->metaObject();
+ if (-1 != meta->indexOfSignal(SIGNAL(disconnected())))
+ connect(device, SIGNAL(disconnected()), this, SIGNAL(disconnected()));
+}
+
+QIODevice *QtROExternalIoDevice::connection() const
+{
+ Q_D(const QtROExternalIoDevice);
+ return d->m_device;
+}
+
+bool QtROExternalIoDevice::isOpen() const
+{
+ Q_D(const QtROExternalIoDevice);
+ if (!d->m_device)
+ return false;
+ return d->m_device->isOpen() && QtROIoDeviceBase::isOpen();
+}
+
+void QtROExternalIoDevice::doClose()
+{
+ Q_D(QtROExternalIoDevice);
+ if (isOpen())
+ d->m_device->close();
+}
+
+QString QtROExternalIoDevice::deviceType() const
+{
+ return QStringLiteral("QtROExternalIoDevice");
+}
+
+/*!
+ \class QtROServerFactory
+ \inmodule QtRemoteObjects
+ \brief A class that holds information about server backends available on the Qt Remote Objects network.
+*/
+QtROServerFactory::QtROServerFactory()
+{
+#ifdef Q_OS_QNX
+ registerType<QnxServerImpl>(QStringLiteral("qnx"));
+#endif
+#ifdef Q_OS_LINUX
+ registerType<AbstractLocalServerImpl>(QStringLiteral("localabstract"));
+#endif
+ registerType<LocalServerImpl>(QStringLiteral("local"));
+ registerType<TcpServerImpl>(QStringLiteral("tcp"));
+}
+
+QtROServerFactory *QtROServerFactory::instance()
+{
+ return &loader->serverFactory;
+}
+
+/*!
+ \class QtROClientFactory
+ \inmodule QtRemoteObjects
+ \brief A class that holds information about client backends available on the Qt Remote Objects network.
+*/
+QtROClientFactory::QtROClientFactory()
+{
+#ifdef Q_OS_QNX
+ registerType<QnxClientIo>(QStringLiteral("qnx"));
+#endif
+#ifdef Q_OS_LINUX
+ registerType<AbstractLocalClientIo>(QStringLiteral("localabstract"));
+#endif
+ registerType<LocalClientIo>(QStringLiteral("local"));
+ registerType<TcpClientIo>(QStringLiteral("tcp"));
+}
+
+QtROClientFactory *QtROClientFactory::instance()
+{
+ return &loader->clientFactory;
+}
+
+/*!
+ \fn void qRegisterRemoteObjectsClient(const QString &id)
+ \relates QtROClientFactory
+
+ Registers the Remote Objects client \a id for the type \c{T}.
+
+ If you need a custom transport protocol for Qt Remote Objects, you need to
+ register the client & server implementation here.
+
+ \note This function requires that \c{T} is a fully defined type at the point
+ where the function is called.
+
+ This example registers the class \c{CustomClientIo} as \c{"myprotocol"}:
+
+ \code
+ qRegisterRemoteObjectsClient<CustomClientIo>(QStringLiteral("myprotocol"));
+ \endcode
+
+ With this in place, you can now instantiate nodes using this new custom protocol:
+
+ \code
+ QRemoteObjectNode client(QUrl(QStringLiteral("myprotocol:registry")));
+ \endcode
+
+ \sa {qRegisterRemoteObjectsServer}
+*/
+
+/*!
+ \fn void qRegisterRemoteObjectsServer(const QString &id)
+ \relates QtROServerFactory
+
+ Registers the Remote Objects server \a id for the type \c{T}.
+
+ If you need a custom transport protocol for Qt Remote Objects, you need to
+ register the client & server implementation here.
+
+ \note This function requires that \c{T} is a fully defined type at the point
+ where the function is called.
+
+ This example registers the class \c{CustomServerImpl} as \c{"myprotocol"}:
+
+ \code
+ qRegisterRemoteObjectsServer<CustomServerImpl>(QStringLiteral("myprotocol"));
+ \endcode
+
+ With this in place, you can now instantiate nodes using this new custom protocol:
+
+ \code
+ QRemoteObjectNode client(QUrl(QStringLiteral("myprotocol:registry")));
+ \endcode
+
+ \sa {qRegisterRemoteObjectsServer}
+*/
+
+QtROIoDeviceBasePrivate::QtROIoDeviceBasePrivate() : QObjectPrivate()
+{
+ m_dataStream.setVersion(dataStreamVersion);
+ m_dataStream.setByteOrder(QDataStream::LittleEndian);
+}
+
+QT_END_NAMESPACE
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2021 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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.LGPL3 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QCONNECTIONFACTORIES_H
+#define QCONNECTIONFACTORIES_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is part of the QtRO internal API and is not meant to be used
+// in applications. It contains "internal" components, which are exported
+// to allow new QIODevice channels to be added to extend QtRO. Usage of these
+// APIs may make your code source and binary incompatible with future versions
+// of Qt.
+//
+
+#include <QtNetwork/qabstractsocket.h>
+
+#include <QtRemoteObjects/qtremoteobjectglobal.h>
+
+
+QT_BEGIN_NAMESPACE
+
+class QtROIoDeviceBasePrivate;
+class QtROClientIoDevicePrivate;
+class QtROExternalIoDevicePrivate;
+
+class Q_REMOTEOBJECTS_EXPORT QtROIoDeviceBase : public QObject
+{
+ Q_OBJECT
+ Q_DISABLE_COPY(QtROIoDeviceBase)
+
+public:
+ explicit QtROIoDeviceBase(QObject *parent = nullptr);
+ ~QtROIoDeviceBase() override;
+
+ bool read(QtRemoteObjects::QRemoteObjectPacketTypeEnum &, QString &);
+
+ virtual void write(const QByteArray &data);
+ virtual void write(const QByteArray &data, qint64);
+ virtual bool isOpen() const;
+ virtual void close();
+ virtual qint64 bytesAvailable() const;
+ virtual QIODevice *connection() const = 0;
+ void initializeDataStream();
+ bool isClosing() const;
+ void addSource(const QString &);
+ void removeSource(const QString &);
+ QSet<QString> remoteObjects() const;
+
+Q_SIGNALS:
+ void readyRead();
+ void disconnected();
+
+protected:
+ explicit QtROIoDeviceBase(QtROIoDeviceBasePrivate &, QObject *parent);
+ virtual QString deviceType() const = 0;
+ virtual void doClose() = 0;
+
+private:
+ Q_DECLARE_PRIVATE(QtROIoDeviceBase)
+ friend class QRemoteObjectNodePrivate;
+ friend class QConnectedReplicaImplementation;
+ friend class QRemoteObjectSourceIo;
+};
+
+class Q_REMOTEOBJECTS_EXPORT QtROServerIoDevice : public QtROIoDeviceBase
+{
+ Q_OBJECT
+ Q_DISABLE_COPY(QtROServerIoDevice)
+
+public:
+ explicit QtROServerIoDevice(QObject *parent = nullptr);
+
+protected:
+ QString deviceType() const override;
+};
+
+class Q_REMOTEOBJECTS_EXPORT QConnectionAbstractServer : public QObject
+{
+ Q_OBJECT
+ Q_DISABLE_COPY(QConnectionAbstractServer)
+
+public:
+ explicit QConnectionAbstractServer(QObject *parent = nullptr);
+ ~QConnectionAbstractServer() override;
+
+ virtual bool hasPendingConnections() const = 0;
+ QtROServerIoDevice* nextPendingConnection();
+ virtual QUrl address() const = 0;
+ virtual bool listen(const QUrl &address) = 0;
+ virtual QAbstractSocket::SocketError serverError() const = 0;
+ virtual void close() = 0;
+
+protected:
+ virtual QtROServerIoDevice* configureNewConnection() = 0;
+
+Q_SIGNALS:
+ void newConnection();
+};
+
+class Q_REMOTEOBJECTS_EXPORT QtROClientIoDevice : public QtROIoDeviceBase
+{
+ Q_OBJECT
+ Q_DISABLE_COPY(QtROClientIoDevice)
+
+public:
+ explicit QtROClientIoDevice(QObject *parent = nullptr);
+ ~QtROClientIoDevice() override;
+
+ void disconnectFromServer();
+ virtual void connectToServer() = 0;
+
+ QUrl url() const;
+
+Q_SIGNALS:
+ void shouldReconnect(QtROClientIoDevice*);
+
+protected:
+ virtual void doDisconnectFromServer() = 0;
+ QString deviceType() const override;
+ void setUrl(const QUrl &url);
+
+private:
+ Q_DECLARE_PRIVATE(QtROClientIoDevice)
+ friend class QtROClientFactory;
+};
+
+class QtROServerFactory
+{
+public:
+ Q_REMOTEOBJECTS_EXPORT static QtROServerFactory *instance();
+
+ QConnectionAbstractServer *create(const QUrl &url, QObject *parent = nullptr)
+ {
+ auto creatorFunc = m_creatorFuncs.value(url.scheme());
+ return creatorFunc ? (*creatorFunc)(parent) : nullptr;
+ }
+
+ template<typename T>
+ void registerType(const QString &id)
+ {
+ m_creatorFuncs[id] = [](QObject *parent) -> QConnectionAbstractServer * {
+ return new T(parent);
+ };
+ }
+
+ bool isValid(const QUrl &url)
+ {
+ return m_creatorFuncs.contains(url.scheme());
+ }
+
+private:
+ friend class QtROFactoryLoader;
+ QtROServerFactory();
+
+ using CreatorFunc = QConnectionAbstractServer * (*)(QObject *);
+ QHash<QString, CreatorFunc> m_creatorFuncs;
+};
+
+class QtROClientFactory
+{
+public:
+ Q_REMOTEOBJECTS_EXPORT static QtROClientFactory *instance();
+
+ /// creates an object from a string
+ QtROClientIoDevice *create(const QUrl &url, QObject *parent = nullptr)
+ {
+ auto creatorFunc = m_creatorFuncs.value(url.scheme());
+ if (!creatorFunc)
+ return nullptr;
+
+ QtROClientIoDevice *res = (*creatorFunc)(parent);
+ if (res)
+ res->setUrl(url);
+ return res;
+ }
+
+ template<typename T>
+ void registerType(const QString &id)
+ {
+ m_creatorFuncs[id] = [](QObject *parent) -> QtROClientIoDevice * {
+ return new T(parent);
+ };
+ }
+
+ bool isValid(const QUrl &url)
+ {
+ return m_creatorFuncs.contains(url.scheme());
+ }
+
+private:
+ friend class QtROFactoryLoader;
+ QtROClientFactory();
+
+ using CreatorFunc = QtROClientIoDevice * (*)(QObject *);
+ QHash<QString, CreatorFunc> m_creatorFuncs;
+};
+
+template <typename T>
+inline void qRegisterRemoteObjectsClient(const QString &id)
+{
+ QtROClientFactory::instance()->registerType<T>(id);
+}
+
+template <typename T>
+inline void qRegisterRemoteObjectsServer(const QString &id)
+{
+ QtROServerFactory::instance()->registerType<T>(id);
+}
+
+QT_END_NAMESPACE
+
+#endif // QCONNECTIONFACTORIES_H
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017-2015 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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.LGPL3 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QCONNECTIONFACTORIES_P_H
+#define QCONNECTIONFACTORIES_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qdatastream.h>
+#include <QtCore/qiodevice.h>
+#include <QtCore/qpointer.h>
+#include <QtCore/private/qobject_p.h>
+
+#include <QtRemoteObjects/qtremoteobjectglobal.h>
+#include <QtRemoteObjects/qconnectionfactories.h>
+#include "qremoteobjectpacket_p.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace QtRemoteObjects {
+
+static const int dataStreamVersion = QDataStream::Qt_6_2;
+static const QLatin1String protocolVersion("QtRO 2.0");
+
+}
+
+class QtROExternalIoDevice : public QtROIoDeviceBase
+{
+ Q_OBJECT
+
+public:
+ explicit QtROExternalIoDevice(QIODevice *device, QObject *parent=nullptr);
+ QIODevice *connection() const override;
+ bool isOpen() const override;
+
+protected:
+ void doClose() override;
+ QString deviceType() const override;
+private:
+ Q_DECLARE_PRIVATE(QtROExternalIoDevice)
+};
+
+class QtROIoDeviceBasePrivate : public QObjectPrivate
+{
+public:
+ QtROIoDeviceBasePrivate();
+
+ // TODO Remove stream()
+ QDataStream &stream() { return m_dataStream; }
+
+ bool m_isClosing = false;
+ quint32 m_curReadSize = 0;
+ QDataStream m_dataStream;
+ QSet<QString> m_remoteObjects;
+ QRemoteObjectPackets::CodecBase *m_codec { nullptr };
+ Q_DECLARE_PUBLIC(QtROIoDeviceBase)
+};
+
+class QtROClientIoDevicePrivate : public QtROIoDeviceBasePrivate
+{
+public:
+ QtROClientIoDevicePrivate() : QtROIoDeviceBasePrivate() { }
+ QUrl m_url;
+ Q_DECLARE_PUBLIC(QtROClientIoDevice)
+};
+
+class QtROExternalIoDevicePrivate : public QtROIoDeviceBasePrivate
+{
+public:
+ QtROExternalIoDevicePrivate(QIODevice *device) : QtROIoDeviceBasePrivate(), m_device(device) { }
+ QPointer<QIODevice> m_device;
+ Q_DECLARE_PUBLIC(QtROExternalIoDevice)
+};
+
+QT_END_NAMESPACE
+
+#endif
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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.LGPL3 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qremoteobjectabstractitemmodeladapter_p.h"
+
+#include <QtCore/qitemselectionmodel.h>
+
+inline QList<QModelRoleData> createModelRoleData(const QList<int> &roles)
+{
+ QList<QModelRoleData> roleData;
+ roleData.reserve(roles.size());
+ for (int role : roles)
+ roleData.emplace_back(role);
+ return roleData;
+}
+
+// consider evaluating performance difference with item data
+inline QVariantList collectData(const QModelIndex &index, const QAbstractItemModel *model,
+ QModelRoleDataSpan roleDataSpan)
+{
+ model->multiData(index, roleDataSpan);
+
+ QVariantList result;
+ result.reserve(roleDataSpan.size());
+ for (auto &roleData : roleDataSpan)
+ result.push_back(std::move(roleData.data()));
+
+ return result;
+}
+
+inline QList<int> filterRoles(const QList<int> &roles, const QList<int> &availableRoles)
+{
+ if (roles.isEmpty())
+ return availableRoles;
+
+ QList<int> neededRoles;
+ for (int inRole : roles) {
+ for (int availableRole : availableRoles)
+ if (inRole == availableRole) {
+ neededRoles << inRole;
+ continue;
+ }
+ }
+ return neededRoles;
+}
+
+QAbstractItemModelSourceAdapter::QAbstractItemModelSourceAdapter(QAbstractItemModel *obj, QItemSelectionModel *sel, const QList<int> &roles)
+ : QObject(obj),
+ m_model(obj),
+ m_availableRoles(roles)
+{
+ QAbstractItemModelSourceAdapter::registerTypes();
+ m_selectionModel = sel;
+ connect(m_model, &QAbstractItemModel::dataChanged, this, &QAbstractItemModelSourceAdapter::sourceDataChanged);
+ connect(m_model, &QAbstractItemModel::rowsInserted, this, &QAbstractItemModelSourceAdapter::sourceRowsInserted);
+ connect(m_model, &QAbstractItemModel::columnsInserted, this, &QAbstractItemModelSourceAdapter::sourceColumnsInserted);
+ connect(m_model, &QAbstractItemModel::rowsRemoved, this, &QAbstractItemModelSourceAdapter::sourceRowsRemoved);
+ connect(m_model, &QAbstractItemModel::rowsMoved, this, &QAbstractItemModelSourceAdapter::sourceRowsMoved);
+ connect(m_model, &QAbstractItemModel::layoutChanged, this, &QAbstractItemModelSourceAdapter::sourceLayoutChanged);
+ if (m_selectionModel)
+ connect(m_selectionModel, &QItemSelectionModel::currentChanged, this, &QAbstractItemModelSourceAdapter::sourceCurrentChanged);
+}
+
+void QAbstractItemModelSourceAdapter::registerTypes()
+{
+ static bool alreadyRegistered = false;
+ if (alreadyRegistered)
+ return;
+
+ alreadyRegistered = true;
+ qRegisterMetaType<QAbstractItemModel*>();
+ qRegisterMetaType<Qt::Orientation>();
+ qRegisterMetaType<QList<Qt::Orientation>>();
+ qRegisterMetaType<QtPrivate::ModelIndex>();
+ qRegisterMetaType<QtPrivate::IndexList>();
+ qRegisterMetaType<QtPrivate::DataEntries>();
+ qRegisterMetaType<QtPrivate::MetaAndDataEntries>();
+ qRegisterMetaType<QItemSelectionModel::SelectionFlags>();
+ qRegisterMetaType<QSize>();
+ qRegisterMetaType<QIntHash>();
+}
+
+QItemSelectionModel* QAbstractItemModelSourceAdapter::selectionModel() const
+{
+ return m_selectionModel;
+}
+
+QSize QAbstractItemModelSourceAdapter::replicaSizeRequest(QtPrivate::IndexList parentList)
+{
+ QModelIndex parent = toQModelIndex(parentList, m_model);
+ const int rowCount = m_model->rowCount(parent);
+ const int columnCount = m_model->columnCount(parent);
+ const QSize size(columnCount, rowCount);
+ qCDebug(QT_REMOTEOBJECT_MODELS) << "parent" << parentList << "size=" << size;
+ return size;
+}
+
+void QAbstractItemModelSourceAdapter::replicaSetData(const QtPrivate::IndexList &index, const QVariant &value, int role)
+{
+ const QModelIndex modelIndex = toQModelIndex(index, m_model);
+ Q_ASSERT(modelIndex.isValid());
+ const bool result = m_model->setData(modelIndex, value, role);
+ Q_ASSERT(result);
+ Q_UNUSED(result)
+}
+
+QtPrivate::DataEntries QAbstractItemModelSourceAdapter::replicaRowRequest(QtPrivate::IndexList start, QtPrivate::IndexList end, QList<int> roles)
+{
+ qCDebug(QT_REMOTEOBJECT_MODELS) << "Requested rows" << "start=" << start << "end=" << end << "roles=" << roles;
+
+ Q_ASSERT(start.size() == end.size());
+ Q_ASSERT(!start.isEmpty());
+
+ if (roles.isEmpty())
+ roles << m_availableRoles;
+
+ QtPrivate::IndexList parentList = start;
+ Q_ASSERT(!parentList.isEmpty());
+ parentList.pop_back();
+ QModelIndex parent = toQModelIndex(parentList, m_model);
+
+ const int startRow = start.last().row;
+ const int startColumn = start.last().column;
+ const int rowCount = m_model->rowCount(parent);
+ const int columnCount = m_model->columnCount(parent);
+
+ QtPrivate::DataEntries entries;
+ if (rowCount <= 0)
+ return entries;
+ const int endRow = std::min(end.last().row, rowCount - 1);
+ const int endColumn = std::min(end.last().column, columnCount - 1);
+ Q_ASSERT_X(endRow >= 0 && endRow < rowCount, __FUNCTION__, qPrintable(QString(QLatin1String("0 <= %1 < %2")).arg(endRow).arg(rowCount)));
+ Q_ASSERT_X(endColumn >= 0 && endColumn < columnCount, __FUNCTION__, qPrintable(QString(QLatin1String("0 <= %1 < %2")).arg(endColumn).arg(columnCount)));
+
+ auto roleData = createModelRoleData(roles);
+ for (int row = startRow; row <= endRow; ++row) {
+ for (int column = startColumn; column <= endColumn; ++column) {
+ const QModelIndex current = m_model->index(row, column, parent);
+ Q_ASSERT(current.isValid());
+ const QtPrivate::IndexList currentList = QtPrivate::toModelIndexList(current, m_model);
+ const QVariantList data = collectData(current, m_model, roleData);
+ const bool hasChildren = m_model->hasChildren(current);
+ const Qt::ItemFlags flags = m_model->flags(current);
+ qCDebug(QT_REMOTEOBJECT_MODELS) << Q_FUNC_INFO << "current=" << currentList << "data=" << data;
+ entries.data << QtPrivate::IndexValuePair(currentList, data, hasChildren, flags);
+ }
+ }
+ return entries;
+}
+
+QtPrivate::MetaAndDataEntries QAbstractItemModelSourceAdapter::replicaCacheRequest(size_t size, const QList<int> &roles)
+{
+ QtPrivate::MetaAndDataEntries res;
+ res.roles = roles.isEmpty() ? m_availableRoles : roles;
+ res.data = fetchTree(QModelIndex {}, size, res.roles);
+ const int rowCount = m_model->rowCount(QModelIndex{});
+ const int columnCount = m_model->columnCount(QModelIndex{});
+ res.size = QSize{columnCount, rowCount};
+ return res;
+}
+
+QVariantList QAbstractItemModelSourceAdapter::replicaHeaderRequest(QList<Qt::Orientation> orientations, QList<int> sections, QList<int> roles)
+{
+ qCDebug(QT_REMOTEOBJECT_MODELS) << Q_FUNC_INFO << "orientations=" << orientations << "sections=" << sections << "roles=" << roles;
+ QVariantList data;
+ Q_ASSERT(roles.size() == sections.size());
+ Q_ASSERT(roles.size() == orientations.size());
+ for (int i = 0; i < roles.size(); ++i) {
+ data << m_model->headerData(sections[i], orientations[i], roles[i]);
+ }
+ return data;
+}
+
+void QAbstractItemModelSourceAdapter::replicaSetCurrentIndex(QtPrivate::IndexList index, QItemSelectionModel::SelectionFlags command)
+{
+ if (m_selectionModel)
+ m_selectionModel->setCurrentIndex(toQModelIndex(index, m_model), command);
+}
+
+void QAbstractItemModelSourceAdapter::sourceDataChanged(const QModelIndex & topLeft, const QModelIndex & bottomRight, const QList<int> & roles) const
+{
+ QList<int> neededRoles = filterRoles(roles, availableRoles());
+ if (neededRoles.isEmpty()) {
+ qCDebug(QT_REMOTEOBJECT_MODELS) << Q_FUNC_INFO << "Needed roles is empty!";
+ return;
+ }
+ Q_ASSERT(topLeft.isValid());
+ Q_ASSERT(bottomRight.isValid());
+ QtPrivate::IndexList start = QtPrivate::toModelIndexList(topLeft, m_model);
+ QtPrivate::IndexList end = QtPrivate::toModelIndexList(bottomRight, m_model);
+ qCDebug(QT_REMOTEOBJECT_MODELS) << Q_FUNC_INFO << "start=" << start << "end=" << end << "neededRoles=" << neededRoles;
+ emit dataChanged(start, end, neededRoles);
+}
+
+void QAbstractItemModelSourceAdapter::sourceRowsInserted(const QModelIndex & parent, int start, int end)
+{
+ QtPrivate::IndexList parentList = QtPrivate::toModelIndexList(parent, m_model);
+ emit rowsInserted(parentList, start, end);
+}
+
+void QAbstractItemModelSourceAdapter::sourceColumnsInserted(const QModelIndex & parent, int start, int end)
+{
+ QtPrivate::IndexList parentList = QtPrivate::toModelIndexList(parent, m_model);
+ emit columnsInserted(parentList, start, end);
+}
+
+void QAbstractItemModelSourceAdapter::sourceRowsRemoved(const QModelIndex & parent, int start, int end)
+{
+ QtPrivate::IndexList parentList = QtPrivate::toModelIndexList(parent, m_model);
+ emit rowsRemoved(parentList, start, end);
+}
+
+void QAbstractItemModelSourceAdapter::sourceRowsMoved(const QModelIndex & sourceParent, int sourceRow, int count, const QModelIndex & destinationParent, int destinationChild) const
+{
+ emit rowsMoved(QtPrivate::toModelIndexList(sourceParent, m_model), sourceRow, count, QtPrivate::toModelIndexList(destinationParent, m_model), destinationChild);
+}
+
+void QAbstractItemModelSourceAdapter::sourceCurrentChanged(const QModelIndex & current, const QModelIndex & previous)
+{
+ QtPrivate::IndexList currentIndex = QtPrivate::toModelIndexList(current, m_model);
+ QtPrivate::IndexList previousIndex = QtPrivate::toModelIndexList(previous, m_model);
+ qCDebug(QT_REMOTEOBJECT_MODELS) << Q_FUNC_INFO << "current=" << currentIndex << "previous=" << previousIndex;
+ emit currentChanged(currentIndex, previousIndex);
+}
+
+void QAbstractItemModelSourceAdapter::sourceLayoutChanged(const QList<QPersistentModelIndex> &parents, QAbstractItemModel::LayoutChangeHint hint)
+{
+ QtPrivate::IndexList indexes;
+ for (const QPersistentModelIndex &idx : parents)
+ indexes << QtPrivate::toModelIndexList((QModelIndex)idx, m_model);
+ emit layoutChanged(indexes, hint);
+}
+
+QList<QtPrivate::IndexValuePair> QAbstractItemModelSourceAdapter::fetchTree(const QModelIndex &parent, size_t &size, const QList<int> &roles)
+{
+ QList<QtPrivate::IndexValuePair> entries;
+ const int rowCount = m_model->rowCount(parent);
+ const int columnCount = m_model->columnCount(parent);
+ if (!columnCount || !rowCount)
+ return entries;
+ entries.reserve(std::min(rowCount * columnCount, int(size)));
+ auto roleData = createModelRoleData(roles);
+ for (int row = 0; row < rowCount && size > 0; ++row)
+ for (int column = 0; column < columnCount && size > 0; ++column) {
+ const auto index = m_model->index(row, column, parent);
+ const QtPrivate::IndexList currentList = QtPrivate::toModelIndexList(index, m_model);
+ const QVariantList data = collectData(index, m_model, roleData);
+ const bool hasChildren = m_model->hasChildren(index);
+ const Qt::ItemFlags flags = m_model->flags(index);
+ int rc = m_model->rowCount(index);
+ int cc = m_model->columnCount(index);
+ QtPrivate::IndexValuePair rowData(currentList, data, hasChildren, flags, QSize{cc, rc});
+ --size;
+ if (hasChildren)
+ rowData.children = fetchTree(index, size, roles);
+ entries.push_back(rowData);
+ }
+ return entries;
+}
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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.LGPL3 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QREMOTEOBJECTS_ABSTRACT_ITEM_ADAPTER_P_H
+#define QREMOTEOBJECTS_ABSTRACT_ITEM_ADAPTER_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qremoteobjectabstractitemmodeltypes_p.h"
+#include "qremoteobjectsource.h"
+
+#include <QtCore/qsize.h>
+
+QT_BEGIN_NAMESPACE
+
+class QAbstractItemModel;
+class QItemSelectionModel;
+
+class QAbstractItemModelSourceAdapter : public QObject
+{
+ Q_OBJECT
+public:
+ Q_INVOKABLE explicit QAbstractItemModelSourceAdapter(QAbstractItemModel *object, QItemSelectionModel *sel, const QList<int> &roles = QList<int>());
+ Q_PROPERTY(QList<int> availableRoles READ availableRoles WRITE setAvailableRoles NOTIFY availableRolesChanged)
+ Q_PROPERTY(QIntHash roleNames READ roleNames)
+ static void registerTypes();
+ QItemSelectionModel* selectionModel() const;
+
+public Q_SLOTS:
+ QList<int> availableRoles() const { return m_availableRoles; }
+ void setAvailableRoles(QList<int> availableRoles)
+ {
+ if (availableRoles != m_availableRoles)
+ {
+ m_availableRoles = availableRoles;
+ Q_EMIT availableRolesChanged();
+ }
+ }
+
+ QIntHash roleNames() const {return m_model->roleNames();}
+
+ QSize replicaSizeRequest(QtPrivate::IndexList parentList);
+ QtPrivate::DataEntries replicaRowRequest(QtPrivate::IndexList start, QtPrivate::IndexList end, QList<int> roles);
+ QVariantList replicaHeaderRequest(QList<Qt::Orientation> orientations, QList<int> sections, QList<int> roles);
+ void replicaSetCurrentIndex(QtPrivate::IndexList index, QItemSelectionModel::SelectionFlags command);
+ void replicaSetData(const QtPrivate::IndexList &index, const QVariant &value, int role);
+ QtPrivate::MetaAndDataEntries replicaCacheRequest(size_t size, const QList<int> &roles);
+
+ void sourceDataChanged(const QModelIndex & topLeft, const QModelIndex & bottomRight, const QList<int> & roles = QList<int> ()) const;
+ void sourceRowsInserted(const QModelIndex & parent, int start, int end);
+ void sourceColumnsInserted(const QModelIndex & parent, int start, int end);
+ void sourceRowsRemoved(const QModelIndex & parent, int start, int end);
+ void sourceRowsMoved(const QModelIndex & sourceParent, int sourceRow, int count, const QModelIndex & destinationParent, int destinationChild) const;
+ void sourceCurrentChanged(const QModelIndex & current, const QModelIndex & previous);
+ void sourceLayoutChanged(const QList<QPersistentModelIndex> &parents, QAbstractItemModel::LayoutChangeHint hint);
+Q_SIGNALS:
+ void availableRolesChanged();
+ void dataChanged(QtPrivate::IndexList topLeft, QtPrivate::IndexList bottomRight, QList<int> roles) const;
+ void rowsInserted(QtPrivate::IndexList parent, int start, int end) const;
+ void rowsRemoved(QtPrivate::IndexList parent, int start, int end) const;
+ void rowsMoved(QtPrivate::IndexList sourceParent, int sourceRow, int count, QtPrivate::IndexList destinationParent, int destinationChild) const;
+ void currentChanged(QtPrivate::IndexList current, QtPrivate::IndexList previous);
+ void columnsInserted(QtPrivate::IndexList parent, int start, int end) const;
+ void layoutChanged(QtPrivate::IndexList parents, QAbstractItemModel::LayoutChangeHint hint);
+
+private:
+ QAbstractItemModelSourceAdapter();
+ QList<QtPrivate::IndexValuePair> fetchTree(const QModelIndex &parent, size_t &size, const QList<int> &roles);
+
+ QAbstractItemModel *m_model;
+ QItemSelectionModel *m_selectionModel;
+ QList<int> m_availableRoles;
+};
+
+template <class ObjectType, class AdapterType>
+struct QAbstractItemAdapterSourceAPI : public SourceApiMap
+{
+ QAbstractItemAdapterSourceAPI(const QString &name)
+ : SourceApiMap()
+ , m_signalArgTypes {}
+ , m_methodArgTypes {}
+ , m_name(name)
+ {
+ m_properties[0] = 2;
+ m_properties[1] = QtPrivate::qtro_property_index<AdapterType>(&AdapterType::availableRoles, static_cast<QList<int> (QObject::*)()>(nullptr),"availableRoles");
+ m_properties[2] = QtPrivate::qtro_property_index<AdapterType>(&AdapterType::roleNames, static_cast<QIntHash (QObject::*)()>(nullptr),"roleNames");
+ m_signals[0] = 10;
+ m_signals[1] = QtPrivate::qtro_signal_index<AdapterType>(&AdapterType::availableRolesChanged, static_cast<void (QObject::*)()>(nullptr),m_signalArgCount+0,&m_signalArgTypes[0]);
+ m_signals[2] = QtPrivate::qtro_signal_index<AdapterType>(&AdapterType::dataChanged, static_cast<void (QObject::*)(QtPrivate::IndexList,QtPrivate::IndexList,QList<int>)>(nullptr),m_signalArgCount+1,&m_signalArgTypes[1]);
+ m_signals[3] = QtPrivate::qtro_signal_index<AdapterType>(&AdapterType::rowsInserted, static_cast<void (QObject::*)(QtPrivate::IndexList,int,int)>(nullptr),m_signalArgCount+2,&m_signalArgTypes[2]);
+ m_signals[4] = QtPrivate::qtro_signal_index<AdapterType>(&AdapterType::rowsRemoved, static_cast<void (QObject::*)(QtPrivate::IndexList,int,int)>(nullptr),m_signalArgCount+3,&m_signalArgTypes[3]);
+ m_signals[5] = QtPrivate::qtro_signal_index<AdapterType>(&AdapterType::rowsMoved, static_cast<void (QObject::*)(QtPrivate::IndexList,int,int,QtPrivate::IndexList,int)>(nullptr),m_signalArgCount+4,&m_signalArgTypes[4]);
+ m_signals[6] = QtPrivate::qtro_signal_index<AdapterType>(&AdapterType::currentChanged, static_cast<void (QObject::*)(QtPrivate::IndexList,QtPrivate::IndexList)>(nullptr),m_signalArgCount+5,&m_signalArgTypes[5]);
+ m_signals[7] = QtPrivate::qtro_signal_index<ObjectType>(&ObjectType::modelReset, static_cast<void (QObject::*)()>(nullptr),m_signalArgCount+6,&m_signalArgTypes[6]);
+ m_signals[8] = QtPrivate::qtro_signal_index<ObjectType>(&ObjectType::headerDataChanged, static_cast<void (QObject::*)(Qt::Orientation,int,int)>(nullptr),m_signalArgCount+7,&m_signalArgTypes[7]);
+ m_signals[9] = QtPrivate::qtro_signal_index<AdapterType>(&AdapterType::columnsInserted, static_cast<void (QObject::*)(QtPrivate::IndexList,int,int)>(nullptr),m_signalArgCount+8,&m_signalArgTypes[8]);
+ m_signals[10] = QtPrivate::qtro_signal_index<AdapterType>(&AdapterType::layoutChanged, static_cast<void (QObject::*)(QtPrivate::IndexList,QAbstractItemModel::LayoutChangeHint)>(nullptr),m_signalArgCount+9,&m_signalArgTypes[9]);
+ m_methods[0] = 6;
+ m_methods[1] = QtPrivate::qtro_method_index<AdapterType>(&AdapterType::replicaSizeRequest, static_cast<void (QObject::*)(QtPrivate::IndexList)>(nullptr),"replicaSizeRequest(QtPrivate::IndexList)",m_methodArgCount+0,&m_methodArgTypes[0]);
+ m_methods[2] = QtPrivate::qtro_method_index<AdapterType>(&AdapterType::replicaRowRequest, static_cast<void (QObject::*)(QtPrivate::IndexList,QtPrivate::IndexList,QList<int>)>(nullptr),"replicaRowRequest(QtPrivate::IndexList,QtPrivate::IndexList,QList<int>)",m_methodArgCount+1,&m_methodArgTypes[1]);
+ m_methods[3] = QtPrivate::qtro_method_index<AdapterType>(&AdapterType::replicaHeaderRequest, static_cast<void (QObject::*)(QList<Qt::Orientation>,QList<int>,QList<int>)>(nullptr),"replicaHeaderRequest(QList<Qt::Orientation>,QList<int>,QList<int>)",m_methodArgCount+2,&m_methodArgTypes[2]);
+ m_methods[4] = QtPrivate::qtro_method_index<AdapterType>(&AdapterType::replicaSetCurrentIndex, static_cast<void (QObject::*)(QtPrivate::IndexList,QItemSelectionModel::SelectionFlags)>(nullptr),"replicaSetCurrentIndex(QtPrivate::IndexList,QItemSelectionModel::SelectionFlags)",m_methodArgCount+3,&m_methodArgTypes[3]);
+ m_methods[5] = QtPrivate::qtro_method_index<AdapterType>(&AdapterType::replicaSetData, static_cast<void (QObject::*)(QtPrivate::IndexList,QVariant,int)>(nullptr),"replicaSetData(QtPrivate::IndexList,QVariant,int)",m_methodArgCount+4,&m_methodArgTypes[4]);
+ m_methods[6] = QtPrivate::qtro_method_index<AdapterType>(&AdapterType::replicaCacheRequest, static_cast<void (QObject::*)(size_t,QList<int>)>(nullptr),"replicaCacheRequest(size_t,QList<int>)",m_methodArgCount+5,&m_methodArgTypes[5]);
+ }
+
+ QString name() const override { return m_name; }
+ QString typeName() const override { return QStringLiteral("QAbstractItemModelAdapter"); }
+ int enumCount() const override { return 0; }
+ int propertyCount() const override { return m_properties[0]; }
+ int signalCount() const override { return m_signals[0]; }
+ int methodCount() const override { return m_methods[0]; }
+ int sourceEnumIndex(int /*index*/) const override
+ {
+ return -1;
+ }
+ int sourcePropertyIndex(int index) const override
+ {
+ if (index < 0 || index >= m_properties[0])
+ return -1;
+ return m_properties[index+1];
+ }
+ int sourceSignalIndex(int index) const override
+ {
+ if (index < 0 || index >= m_signals[0])
+ return -1;
+ return m_signals[index+1];
+ }
+ int sourceMethodIndex(int index) const override
+ {
+ if (index < 0 || index >= m_methods[0])
+ return -1;
+ return m_methods[index+1];
+ }
+ int signalParameterCount(int index) const override { return m_signalArgCount[index]; }
+ int signalParameterType(int sigIndex, int paramIndex) const override { return m_signalArgTypes[sigIndex][paramIndex]; }
+ int methodParameterCount(int index) const override { return m_methodArgCount[index]; }
+ int methodParameterType(int methodIndex, int paramIndex) const override { return m_methodArgTypes[methodIndex][paramIndex]; }
+ QByteArrayList signalParameterNames(int index) const override
+ {
+ QByteArrayList res;
+ int count = signalParameterCount(index);
+ while (count--)
+ res << QByteArray{};
+ return res;
+ }
+ int propertyIndexFromSignal(int index) const override
+ {
+ switch (index) {
+ case 0: return m_properties[1];
+ }
+ return -1;
+ }
+ int propertyRawIndexFromSignal(int index) const override
+ {
+ switch (index) {
+ case 0: return 0;
+ }
+ return -1;
+ }
+ const QByteArray signalSignature(int index) const override
+ {
+ switch (index) {
+ case 0: return QByteArrayLiteral("availableRolesChanged()");
+ case 1: return QByteArrayLiteral("dataChanged(QtPrivate::IndexList,QtPrivate::IndexList,QList<int>)");
+ case 2: return QByteArrayLiteral("rowsInserted(QtPrivate::IndexList,int,int)");
+ case 3: return QByteArrayLiteral("rowsRemoved(QtPrivate::IndexList,int,int)");
+ case 4: return QByteArrayLiteral("rowsMoved(QtPrivate::IndexList,int,int,QtPrivate::IndexList,int)");
+ case 5: return QByteArrayLiteral("currentChanged(QtPrivate::IndexList,QtPrivate::IndexList)");
+ case 6: return QByteArrayLiteral("resetModel()");
+ case 7: return QByteArrayLiteral("headerDataChanged(Qt::Orientation,int,int)");
+ case 8: return QByteArrayLiteral("columnsInserted(QtPrivate::IndexList,int,int)");
+ case 9: return QByteArrayLiteral("layoutChanged(QtPrivate::IndexList,QAbstractItemModel::LayoutChangeHint)");
+ }
+ return QByteArrayLiteral("");
+ }
+ const QByteArray methodSignature(int index) const override
+ {
+ switch (index) {
+ case 0: return QByteArrayLiteral("replicaSizeRequest(QtPrivate::IndexList)");
+ case 1: return QByteArrayLiteral("replicaRowRequest(QtPrivate::IndexList,QtPrivate::IndexList,QList<int>)");
+ case 2: return QByteArrayLiteral("replicaHeaderRequest(QList<Qt::Orientation>,QList<int>,QList<int>)");
+ case 3: return QByteArrayLiteral("replicaSetCurrentIndex(QtPrivate::IndexList,QItemSelectionModel::SelectionFlags)");
+ case 4: return QByteArrayLiteral("replicaSetData(QtPrivate::IndexList,QVariant,int)");
+ case 5: return QByteArrayLiteral("replicaCacheRequest(size_t,QList<int>)");
+ }
+ return QByteArrayLiteral("");
+ }
+ QMetaMethod::MethodType methodType(int) const override
+ {
+ return QMetaMethod::Slot;
+ }
+ const QByteArray typeName(int index) const override
+ {
+ switch (index) {
+ case 0: return QByteArrayLiteral("QSize");
+ case 1: return QByteArrayLiteral("QtPrivate::DataEntries");
+ case 2: return QByteArrayLiteral("QVariantList");
+ case 3: return QByteArrayLiteral("");
+ case 5: return QByteArrayLiteral("QtPrivate::MetaAndDataEntries");
+ }
+ return QByteArrayLiteral("");
+ }
+
+ QByteArrayList methodParameterNames(int index) const override
+ {
+ QByteArrayList res;
+ int count = methodParameterCount(index);
+ while (count--)
+ res << QByteArray{};
+ return res;
+ }
+
+ QByteArray objectSignature() const override { return QByteArray{}; }
+ bool isAdapterSignal(int index) const override
+ {
+ switch (index) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 8:
+ case 9:
+ return true;
+ }
+ return false;
+ }
+ bool isAdapterMethod(int index) const override
+ {
+ switch (index) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ return true;
+ }
+ return false;
+ }
+ bool isAdapterProperty(int index) const override
+ {
+ switch (index) {
+ case 0:
+ case 1:
+ return true;
+ }
+ return false;
+ }
+
+ int m_properties[3];
+ int m_signals[11];
+ int m_methods[7];
+ int m_signalArgCount[10];
+ const int* m_signalArgTypes[10];
+ int m_methodArgCount[6];
+ const int* m_methodArgTypes[6];
+ QString m_name;
+};
+
+QT_END_NAMESPACE
+
+#endif //QREMOTEOBJECTS_ABSTRACT_ITEM_ADAPTER_P_H
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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.LGPL3 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qremoteobjectabstractitemmodelreplica.h"
+#include "qremoteobjectabstractitemmodelreplica_p.h"
+
+#include "qremoteobjectnode.h"
+
+#include <QtCore/qdebug.h>
+#include <QtCore/qrect.h>
+#include <QtCore/qpoint.h>
+
+QT_BEGIN_NAMESPACE
+
+inline QDebug operator<<(QDebug stream, const RequestedData &data)
+{
+ return stream.nospace() << "RequestedData[start=" << data.start << ", end=" << data.end << ", roles=" << data.roles << "]";
+}
+
+CacheData::CacheData(QAbstractItemModelReplicaImplementation *model, CacheData *parentItem)
+ : replicaModel(model)
+ , parent(parentItem)
+ , hasChildren(false)
+ , columnCount(0)
+ , rowCount(0)
+{
+ if (parent)
+ replicaModel->m_activeParents.insert(parent);
+}
+
+CacheData::~CacheData() {
+ if (parent && !replicaModel->m_activeParents.empty())
+ replicaModel->m_activeParents.erase(this);
+}
+
+QAbstractItemModelReplicaImplementation::QAbstractItemModelReplicaImplementation()
+ : QRemoteObjectReplica()
+ , m_selectionModel(nullptr)
+ , m_rootItem(this)
+{
+ QAbstractItemModelReplicaImplementation::registerMetatypes();
+ initializeModelConnections();
+ connect(this, &QAbstractItemModelReplicaImplementation::availableRolesChanged, this, [this]{
+ m_availableRoles.clear();
+ });
+}
+
+QAbstractItemModelReplicaImplementation::QAbstractItemModelReplicaImplementation(QRemoteObjectNode *node, const QString &name)
+ : QRemoteObjectReplica(ConstructWithNode)
+ , m_selectionModel(nullptr)
+ , m_rootItem(this)
+{
+ QAbstractItemModelReplicaImplementation::registerMetatypes();
+ initializeModelConnections();
+ initializeNode(node, name);
+ connect(this, &QAbstractItemModelReplicaImplementation::availableRolesChanged, this, [this]{
+ m_availableRoles.clear();
+ });
+}
+
+QAbstractItemModelReplicaImplementation::~QAbstractItemModelReplicaImplementation()
+{
+ m_rootItem.clear();
+ qDeleteAll(m_pendingRequests);
+}
+
+void QAbstractItemModelReplicaImplementation::initialize()
+{
+ QVariantList properties;
+ properties << QVariant::fromValue(QList<int>());
+ properties << QVariant::fromValue(QIntHash());
+ setProperties(std::move(properties));
+}
+
+void QAbstractItemModelReplicaImplementation::registerMetatypes()
+{
+ static bool alreadyRegistered = false;
+ if (alreadyRegistered)
+ return;
+
+ alreadyRegistered = true;
+ qRegisterMetaType<QAbstractItemModel*>();
+ qRegisterMetaType<Qt::Orientation>();
+ qRegisterMetaType<QList<Qt::Orientation>>();
+ qRegisterMetaType<QtPrivate::ModelIndex>();
+ qRegisterMetaType<QtPrivate::IndexList>();
+ qRegisterMetaType<QtPrivate::DataEntries>();
+ qRegisterMetaType<QtPrivate::MetaAndDataEntries>();
+ qRegisterMetaType<QItemSelectionModel::SelectionFlags>();
+ qRegisterMetaType<QSize>();
+ qRegisterMetaType<QIntHash>();
+}
+
+void QAbstractItemModelReplicaImplementation::initializeModelConnections()
+{
+ connect(this, &QAbstractItemModelReplicaImplementation::dataChanged, this, &QAbstractItemModelReplicaImplementation::onDataChanged);
+ connect(this, &QAbstractItemModelReplicaImplementation::rowsInserted, this, &QAbstractItemModelReplicaImplementation::onRowsInserted);
+ connect(this, &QAbstractItemModelReplicaImplementation::columnsInserted, this, &QAbstractItemModelReplicaImplementation::onColumnsInserted);
+ connect(this, &QAbstractItemModelReplicaImplementation::rowsRemoved, this, &QAbstractItemModelReplicaImplementation::onRowsRemoved);
+ connect(this, &QAbstractItemModelReplicaImplementation::rowsMoved, this, &QAbstractItemModelReplicaImplementation::onRowsMoved);
+ connect(this, &QAbstractItemModelReplicaImplementation::currentChanged, this, &QAbstractItemModelReplicaImplementation::onCurrentChanged);
+ connect(this, &QAbstractItemModelReplicaImplementation::modelReset, this, &QAbstractItemModelReplicaImplementation::onModelReset);
+ connect(this, &QAbstractItemModelReplicaImplementation::headerDataChanged, this, &QAbstractItemModelReplicaImplementation::onHeaderDataChanged);
+ connect(this, &QAbstractItemModelReplicaImplementation::layoutChanged, this, &QAbstractItemModelReplicaImplementation::onLayoutChanged);
+
+}
+
+inline void removeIndexFromRow(const QModelIndex &index, const QList<int> &roles, CachedRowEntry *entry)
+{
+ CachedRowEntry &entryRef = *entry;
+ if (index.column() < entryRef.size()) {
+ CacheEntry &entry = entryRef[index.column()];
+ if (roles.isEmpty()) {
+ entry.data.clear();
+ } else {
+ for (int role : roles)
+ entry.data.remove(role);
+ }
+ }
+}
+
+void QAbstractItemModelReplicaImplementation::onReplicaCurrentChanged(const QModelIndex ¤t, const QModelIndex &previous)
+{
+ Q_UNUSED(previous)
+ QtPrivate::IndexList currentIndex = QtPrivate::toModelIndexList(current, q);
+ qCDebug(QT_REMOTEOBJECT_MODELS) << Q_FUNC_INFO << "current=" << currentIndex;
+ replicaSetCurrentIndex(currentIndex, QItemSelectionModel::Clear|QItemSelectionModel::Select|QItemSelectionModel::Current);
+}
+
+void QAbstractItemModelReplicaImplementation::setModel(QAbstractItemModelReplica *model)
+{
+ q = model;
+ setParent(model);
+ m_selectionModel.reset(new QItemSelectionModel(model));
+ connect(m_selectionModel.data(), &QItemSelectionModel::currentChanged, this, &QAbstractItemModelReplicaImplementation::onReplicaCurrentChanged);
+}
+
+bool QAbstractItemModelReplicaImplementation::clearCache(const QtPrivate::IndexList &start, const QtPrivate::IndexList &end, const QList<int> &roles = QList<int>())
+{
+ Q_ASSERT(start.size() == end.size());
+
+ bool ok = true;
+ const QModelIndex startIndex = toQModelIndex(start, q, &ok);
+ if (!ok)
+ return false;
+ const QModelIndex endIndex = toQModelIndex(end, q, &ok);
+ if (!ok)
+ return false;
+ Q_ASSERT(startIndex.isValid());
+ Q_ASSERT(endIndex.isValid());
+ Q_ASSERT(startIndex.parent() == endIndex.parent());
+ Q_UNUSED(endIndex)
+ QModelIndex parentIndex = startIndex.parent();
+ auto parentItem = cacheData(parentIndex);
+
+ const int startRow = start.last().row;
+ const int lastRow = end.last().row;
+ const int startColumn = start.last().column;
+ const int lastColumn = end.last().column;
+ for (int row = startRow; row <= lastRow; ++row) {
+ Q_ASSERT_X(row >= 0 && row < parentItem->rowCount, __FUNCTION__, qPrintable(QString(QLatin1String("0 <= %1 < %2")).arg(row).arg(parentItem->rowCount)));
+ auto item = parentItem->children.get(row);
+ if (item) {
+ CachedRowEntry *entry = &(item->cachedRowEntry);
+ for (int column = startColumn; column <= lastColumn; ++column)
+ removeIndexFromRow(q->index(row, column, parentIndex), roles, entry);
+ }
+ }
+ return true;
+}
+
+void QAbstractItemModelReplicaImplementation::onDataChanged(const QtPrivate::IndexList &start, const QtPrivate::IndexList &end, const QList<int> &roles)
+{
+ qCDebug(QT_REMOTEOBJECT_MODELS) << Q_FUNC_INFO << "start=" << start << "end=" << end << "roles=" << roles;
+
+ // we need to clear the cache to make sure the new remote data is fetched if the new data call is happening
+ if (clearCache(start, end, roles)) {
+ bool ok = true;
+ const QModelIndex startIndex = toQModelIndex(start, q, &ok);
+ if (!ok)
+ return;
+ const QModelIndex endIndex = toQModelIndex(end, q, &ok);
+ if (!ok)
+ return;
+ Q_ASSERT(startIndex.parent() == endIndex.parent());
+ auto parentItem = cacheData(startIndex.parent());
+ int startRow = start.last().row;
+ int endRow = end.last().row;
+ bool dataChanged = false;
+ while (startRow <= endRow) {
+ for (;startRow <= endRow; startRow++) {
+ if (parentItem->children.exists(startRow))
+ break;
+ }
+
+ if (startRow > endRow)
+ break;
+
+ RequestedData data;
+ data.roles = roles;
+ data.start = start;
+ data.start.last().row = startRow;
+
+ while (startRow <= endRow && parentItem->children.exists(startRow))
+ ++startRow;
+
+ data.end = end;
+ data.end.last().row = startRow -1;
+
+ m_requestedData.append(data);
+ dataChanged = true;
+ }
+
+ if (dataChanged)
+ QMetaObject::invokeMethod(this, "fetchPendingData", Qt::QueuedConnection);
+ }
+}
+
+void QAbstractItemModelReplicaImplementation::onRowsInserted(const QtPrivate::IndexList &parent, int start, int end)
+{
+ qCDebug(QT_REMOTEOBJECT_MODELS) << Q_FUNC_INFO << "start=" << start << "end=" << end << "parent=" << parent;
+
+ bool treeFullyLazyLoaded = true;
+ const QModelIndex parentIndex = toQModelIndex(parent, q, &treeFullyLazyLoaded, true);
+ if (!treeFullyLazyLoaded)
+ return;
+
+ auto parentItem = cacheData(parentIndex);
+ q->beginInsertRows(parentIndex, start, end);
+ parentItem->insertChildren(start, end);
+ for (int i = start; i <= end; ++i)
+ m_headerData[1].append(CacheEntry());
+ q->endInsertRows();
+ if (!parentItem->hasChildren && parentItem->columnCount > 0) {
+ parentItem->hasChildren = true;
+ emit q->dataChanged(parentIndex, parentIndex);
+ }
+}
+
+void QAbstractItemModelReplicaImplementation::onColumnsInserted(const QtPrivate::IndexList &parent, int start, int end)
+{
+ qCDebug(QT_REMOTEOBJECT_MODELS) << Q_FUNC_INFO << "start=" << start << "end=" << end << "parent=" << parent;
+
+ bool treeFullyLazyLoaded = true;
+ const QModelIndex parentIndex = toQModelIndex(parent, q, &treeFullyLazyLoaded);
+ if (!treeFullyLazyLoaded)
+ return;
+
+ //Since we need to support QAIM and models that don't emit columnCountChanged
+ //check if we have a constant columnCount everywhere if thats the case don't insert
+ //more columns
+ auto parentItem = cacheData(parentIndex);
+ auto parentOfParent = parentItem->parent;
+ if (parentOfParent && parentItem != &m_rootItem)
+ if (parentOfParent->columnCount == parentItem->columnCount)
+ return;
+ q->beginInsertColumns(parentIndex, start, end);
+ parentItem->columnCount += end - start + 1;
+ for (int i = start; i <= end; ++i)
+ m_headerData[0].append(CacheEntry());
+ q->endInsertColumns();
+ if (!parentItem->hasChildren && parentItem->children.size() > 0) {
+ parentItem->hasChildren = true;
+ emit q->dataChanged(parentIndex, parentIndex);
+ }
+
+}
+
+void QAbstractItemModelReplicaImplementation::onRowsRemoved(const QtPrivate::IndexList &parent, int start, int end)
+{
+ qCDebug(QT_REMOTEOBJECT_MODELS) << Q_FUNC_INFO << "start=" << start << "end=" << end << "parent=" << parent;
+
+ bool treeFullyLazyLoaded = true;
+ const QModelIndex parentIndex = toQModelIndex(parent, q, &treeFullyLazyLoaded);
+ if (!treeFullyLazyLoaded)
+ return;
+
+ auto parentItem = cacheData(parentIndex);
+ q->beginRemoveRows(parentIndex, start, end);
+ if (parentItem)
+ parentItem->removeChildren(start, end);
+ m_headerData[1].erase(m_headerData[1].begin() + start, m_headerData[1].begin() + end + 1);
+ q->endRemoveRows();
+}
+
+void QAbstractItemModelReplicaImplementation::onRowsMoved(QtPrivate::IndexList srcParent, int srcRow, int count, QtPrivate::IndexList destParent, int destRow)
+{
+ qCDebug(QT_REMOTEOBJECT_MODELS) << Q_FUNC_INFO;
+
+ const QModelIndex sourceParent = toQModelIndex(srcParent, q);
+ const QModelIndex destinationParent = toQModelIndex(destParent, q);
+ Q_ASSERT(!sourceParent.isValid());
+ Q_ASSERT(!destinationParent.isValid());
+ q->beginMoveRows(sourceParent, srcRow, count, destinationParent, destRow);
+//TODO misses parents...
+ QtPrivate::IndexList start, end;
+ start << QtPrivate::ModelIndex(srcRow, 0);
+ end << QtPrivate::ModelIndex(srcRow + count, q->columnCount(sourceParent)-1);
+ clearCache(start, end);
+ QtPrivate::IndexList start2, end2;
+ start2 << QtPrivate::ModelIndex(destRow, 0);
+ end2 << QtPrivate::ModelIndex(destRow + count, q->columnCount(destinationParent)-1);
+ clearCache(start2, end2);
+ q->endMoveRows();
+}
+
+void QAbstractItemModelReplicaImplementation::onCurrentChanged(QtPrivate::IndexList current, QtPrivate::IndexList previous)
+{
+ qCDebug(QT_REMOTEOBJECT_MODELS) << Q_FUNC_INFO << "current=" << current << "previous=" << previous;
+ Q_UNUSED(previous)
+ Q_ASSERT(m_selectionModel);
+ bool ok;
+ // If we have several tree models sharing a selection model, we
+ // can't guarantee that all Replicas have the selected cell
+ // available.
+ const QModelIndex currentIndex = toQModelIndex(current, q, &ok);
+ // Ignore selection if we can't find the desired cell.
+ if (ok)
+ m_selectionModel->setCurrentIndex(currentIndex, QItemSelectionModel::Clear|QItemSelectionModel::Select|QItemSelectionModel::Current);
+}
+
+void QAbstractItemModelReplicaImplementation::handleInitDone(QRemoteObjectPendingCallWatcher *watcher)
+{
+ qCDebug(QT_REMOTEOBJECT_MODELS) << Q_FUNC_INFO;
+
+ handleModelResetDone(watcher);
+ m_initDone = true;
+ emit q->initialized();
+}
+
+void QAbstractItemModelReplicaImplementation::handleModelResetDone(QRemoteObjectPendingCallWatcher *watcher)
+{
+ QSize size;
+ if (m_initialAction == QtRemoteObjects::FetchRootSize)
+ size = watcher->returnValue().toSize();
+ else {
+ Q_ASSERT(watcher->returnValue().canConvert<QtPrivate::MetaAndDataEntries>());
+ size = watcher->returnValue().value<QtPrivate::MetaAndDataEntries>().size;
+ }
+
+ qCDebug(QT_REMOTEOBJECT_MODELS) << Q_FUNC_INFO << "size=" << size;
+
+ q->beginResetModel();
+ m_rootItem.clear();
+ if (size.height() > 0) {
+ m_rootItem.rowCount = size.height();
+ m_rootItem.hasChildren = true;
+ }
+
+ m_rootItem.columnCount = size.width();
+ m_headerData[0].resize(size.width());
+ m_headerData[1].resize(size.height());
+ {
+ QList<CacheEntry> &headerEntries = m_headerData[0];
+ for (int i = 0; i < size.width(); ++i )
+ headerEntries[i].data.clear();
+ }
+ {
+ QList<CacheEntry> &headerEntries = m_headerData[1];
+ for (int i = 0; i < size.height(); ++i )
+ headerEntries[i].data.clear();
+ }
+ if (m_initialAction == QtRemoteObjects::PrefetchData) {
+ auto entries = watcher->returnValue().value<QtPrivate::MetaAndDataEntries>();
+ for (int i = 0; i < entries.data.size(); ++i)
+ fillCache(entries.data[i], entries.roles);
+ }
+ q->endResetModel();
+ m_pendingRequests.removeAll(watcher);
+ delete watcher;
+}
+
+void QAbstractItemModelReplicaImplementation::handleSizeDone(QRemoteObjectPendingCallWatcher *watcher)
+{
+ SizeWatcher *sizeWatcher = static_cast<SizeWatcher*>(watcher);
+ const QSize size = sizeWatcher->returnValue().toSize();
+ auto parentItem = cacheData(sizeWatcher->parentList);
+ const QModelIndex parent = toQModelIndex(sizeWatcher->parentList, q);
+
+ if (size.width() != parentItem->columnCount) {
+ const int columnCount = std::max(0, parentItem->columnCount);
+ Q_ASSERT_X(size.width() >= parentItem->columnCount, __FUNCTION__, "The column count should only shrink in columnsRemoved!!");
+ parentItem->columnCount = size.width();
+ if (size.width() > columnCount) {
+ Q_ASSERT(size.width() > 0);
+ q->beginInsertColumns(parent, columnCount, size.width() - 1);
+ q->endInsertColumns();
+ } else {
+ Q_ASSERT_X(size.width() == columnCount, __FUNCTION__, qPrintable(QString(QLatin1String("%1 != %2")).arg(size.width()).arg(columnCount)));
+ }
+ }
+
+ Q_ASSERT_X(size.height() >= parentItem->rowCount, __FUNCTION__, "The new size and the current size should match!!");
+ if (!parentItem->rowCount) {
+ if (size.height() > 0) {
+ q->beginInsertRows(parent, 0, size.height() - 1);
+ parentItem->rowCount = size.height();
+ q->endInsertRows();
+ }
+ } else {
+ Q_ASSERT_X(parentItem->rowCount == size.height(), __FUNCTION__, qPrintable(QString(QLatin1String("%1 != %2")).arg(parentItem->rowCount).arg(size.height())));
+ }
+ m_pendingRequests.removeAll(watcher);
+ delete watcher;
+}
+
+void QAbstractItemModelReplicaImplementation::init()
+{
+ qCDebug(QT_REMOTEOBJECT_MODELS) << Q_FUNC_INFO << this->node()->objectName();
+ QRemoteObjectPendingCallWatcher *watcher = doModelReset();
+ connect(watcher, &QRemoteObjectPendingCallWatcher::finished, this, &QAbstractItemModelReplicaImplementation::handleInitDone);
+}
+
+QRemoteObjectPendingCallWatcher* QAbstractItemModelReplicaImplementation::doModelReset()
+{
+ qDeleteAll(m_pendingRequests);
+ m_pendingRequests.clear();
+ QtPrivate::IndexList parentList;
+ QRemoteObjectPendingCallWatcher *watcher;
+ if (m_initialAction == QtRemoteObjects::FetchRootSize) {
+ auto call = replicaSizeRequest(parentList);
+ watcher = new SizeWatcher(parentList, call);
+ } else {
+ auto call = replicaCacheRequest(m_rootItem.children.cacheSize, m_initialFetchRolesHint);
+ watcher = new QRemoteObjectPendingCallWatcher(call);
+ }
+ m_pendingRequests.push_back(watcher);
+ return watcher;
+}
+
+inline void fillCacheEntry(CacheEntry *entry, const QtPrivate::IndexValuePair &pair, const QList<int> &roles)
+{
+ Q_ASSERT(entry);
+
+ const QVariantList &data = pair.data;
+ Q_ASSERT(roles.size() == data.size());
+
+ entry->flags = pair.flags;
+
+ qCDebug(QT_REMOTEOBJECT_MODELS) << Q_FUNC_INFO << "data.size=" << data.size();
+ for (int i = 0; i < data.size(); ++i) {
+ const int role = roles[i];
+ const QVariant dataVal = data[i];
+ qCDebug(QT_REMOTEOBJECT_MODELS) << Q_FUNC_INFO << "role=" << role << "data=" << dataVal;
+ entry->data[role] = dataVal;
+ }
+}
+
+inline void fillRow(CacheData *item, const QtPrivate::IndexValuePair &pair, const QAbstractItemModel *model, const QList<int> &roles)
+{
+ CachedRowEntry &rowRef = item->cachedRowEntry;
+ const QModelIndex index = toQModelIndex(pair.index, model);
+ Q_ASSERT(index.isValid());
+ qCDebug(QT_REMOTEOBJECT_MODELS) << Q_FUNC_INFO << "row=" << index.row() << "column=" << index.column();
+ if (index.column() == 0)
+ item->hasChildren = pair.hasChildren;
+ bool existed = false;
+ for (int i = 0; i < rowRef.size(); ++i) {
+ if (i == index.column()) {
+ fillCacheEntry(&rowRef[i], pair, roles);
+ existed = true;
+ }
+ }
+ qCDebug(QT_REMOTEOBJECT_MODELS) << Q_FUNC_INFO << "existed=" << existed;
+ if (!existed) {
+ CacheEntry entries;
+ fillCacheEntry(&entries, pair, roles);
+ rowRef.append(entries);
+ }
+}
+
+int collectEntriesForRow(QtPrivate::DataEntries* filteredEntries, int row, const QtPrivate::DataEntries &entries, int startIndex)
+{
+ Q_ASSERT(filteredEntries);
+ const int size = int(entries.data.size());
+ for (int i = startIndex; i < size; ++i)
+ {
+ const QtPrivate::IndexValuePair &pair = entries.data[i];
+ if (pair.index.last().row == row)
+ filteredEntries->data << pair;
+ else
+ return i;
+ }
+ return size;
+}
+
+void QAbstractItemModelReplicaImplementation::fillCache(const QtPrivate::IndexValuePair &pair, const QList<int> &roles)
+{
+ if (auto item = createCacheData(pair.index)) {
+ fillRow(item, pair, q, roles);
+ item->rowCount = pair.size.height();
+ item->columnCount = pair.size.width();
+ }
+ for (const auto &it : pair.children)
+ fillCache(it, roles);
+}
+
+void QAbstractItemModelReplicaImplementation::requestedData(QRemoteObjectPendingCallWatcher *qobject)
+{
+ RowWatcher *watcher = static_cast<RowWatcher *>(qobject);
+ Q_ASSERT(watcher);
+ Q_ASSERT(watcher->start.size() == watcher->end.size());
+
+ qCDebug(QT_REMOTEOBJECT_MODELS) << Q_FUNC_INFO << "start=" << watcher->start << "end=" << watcher->end;
+
+ QtPrivate::IndexList parentList = watcher->start;
+ Q_ASSERT(!parentList.isEmpty());
+ parentList.pop_back();
+ auto parentItem = cacheData(parentList);
+ QtPrivate::DataEntries entries = watcher->returnValue().value<QtPrivate::DataEntries>();
+
+ const int rowCount = parentItem->rowCount;
+ const int columnCount = parentItem->columnCount;
+
+ if (rowCount < 1 || columnCount < 1)
+ return;
+
+ const int startRow = std::min(watcher->start.last().row, rowCount - 1);
+ const int endRow = std::min(watcher->end.last().row, rowCount - 1);
+ const int startColumn = std::min(watcher->start.last().column, columnCount - 1);
+ const int endColumn = std::min(watcher->end.last().column, columnCount - 1);
+ Q_ASSERT_X(startRow >= 0 && startRow < parentItem->rowCount, __FUNCTION__, qPrintable(QString(QLatin1String("0 <= %1 < %2")).arg(startRow).arg(parentItem->rowCount)));
+ Q_ASSERT_X(endRow >= 0 && endRow < parentItem->rowCount, __FUNCTION__, qPrintable(QString(QLatin1String("0 <= %1 < %2")).arg(endRow).arg(parentItem->rowCount)));
+
+ for (int i = 0; i < entries.data.size(); ++i) {
+ QtPrivate::IndexValuePair pair = entries.data[i];
+ if (auto item = createCacheData(pair.index))
+ fillRow(item, pair, q, watcher->roles);
+ }
+
+ const QModelIndex parentIndex = toQModelIndex(parentList, q);
+ const QModelIndex startIndex = q->index(startRow, startColumn, parentIndex);
+ const QModelIndex endIndex = q->index(endRow, endColumn, parentIndex);
+ Q_ASSERT(startIndex.isValid());
+ Q_ASSERT(endIndex.isValid());
+ emit q->dataChanged(startIndex, endIndex, watcher->roles);
+ m_pendingRequests.removeAll(watcher);
+ delete watcher;
+}
+
+void QAbstractItemModelReplicaImplementation::fetchPendingData()
+{
+ if (m_requestedData.isEmpty())
+ return;
+
+ qCDebug(QT_REMOTEOBJECT_MODELS) << Q_FUNC_INFO << "m_requestedData.size=" << m_requestedData.size();
+
+ std::vector<RequestedData> finalRequests;
+ RequestedData curData;
+ for (const RequestedData &data : qExchange(m_requestedData, {})) {
+ qCDebug(QT_REMOTEOBJECT_MODELS) << Q_FUNC_INFO << "REQUESTED start=" << data.start << "end=" << data.end << "roles=" << data.roles;
+
+ Q_ASSERT(!data.start.isEmpty());
+ Q_ASSERT(!data.end.isEmpty());
+ Q_ASSERT(data.start.size() == data.end.size());
+ if (curData.start.isEmpty() || curData.start.last().row == -1 || curData.start.last().column == -1)
+ curData = data;
+ if (curData.start.size() != data.start.size()) {
+ finalRequests.push_back(curData);
+ curData = data;
+ } else {
+ if (data.start.size() > 1) {
+ for (int i = 0; i < data.start.size() - 1; ++i) {
+ if (curData.start[i].row != data.start[i].row ||
+ curData.start[i].column != data.start[i].column) {
+ finalRequests.push_back(curData);
+ curData = data;
+ }
+ }
+ }
+
+ const QtPrivate::ModelIndex curIndStart = curData.start.last();
+ const QtPrivate::ModelIndex curIndEnd = curData.end.last();
+ const QtPrivate::ModelIndex dataIndStart = data.start.last();
+ const QtPrivate::ModelIndex dataIndEnd = data.end.last();
+ const QtPrivate::ModelIndex resStart(std::min(curIndStart.row, dataIndStart.row), std::min(curIndStart.column, dataIndStart.column));
+ const QtPrivate::ModelIndex resEnd(std::max(curIndEnd.row, dataIndEnd.row), std::max(curIndEnd.column, dataIndEnd.column));
+ QList<int> roles = curData.roles;
+ if (!curData.roles.isEmpty()) {
+ for (int role : data.roles) {
+ if (!curData.roles.contains(role))
+ roles.append(role);
+ }
+ }
+ QRect firstRect( QPoint(curIndStart.row, curIndStart.column), QPoint(curIndEnd.row, curIndEnd.column));
+ QRect secondRect( QPoint(dataIndStart.row, dataIndStart.column), QPoint(dataIndEnd.row, dataIndEnd.column));
+
+ const bool borders = (qAbs(curIndStart.row - dataIndStart.row) == 1) ||
+ (qAbs(curIndStart.column - dataIndStart.column) == 1) ||
+ (qAbs(curIndEnd.row - dataIndEnd.row) == 1) ||
+ (qAbs(curIndEnd.column - dataIndEnd.column) == 1);
+
+ if ((resEnd.row - resStart.row < 100) && (firstRect.intersects(secondRect) || borders)) {
+ QtPrivate::IndexList start = curData.start;
+ start.pop_back();
+ start.push_back(resStart);
+ QtPrivate::IndexList end = curData.end;
+ end.pop_back();
+ end.push_back(resEnd);
+ curData.start = start;
+ curData.end = end;
+ curData.roles = roles;
+ Q_ASSERT(!start.isEmpty());
+ Q_ASSERT(!end.isEmpty());
+ } else {
+ finalRequests.push_back(curData);
+ curData = data;
+ }
+ }
+ }
+ finalRequests.push_back(curData);
+ //qCDebug(QT_REMOTEOBJECT_MODELS) << "Final requests" << finalRequests;
+ int rows = 0;
+ // There is no point to eat more than can chew
+ for (auto it = finalRequests.rbegin(); it != finalRequests.rend() && size_t(rows) < m_rootItem.children.cacheSize; ++it) {
+ qCDebug(QT_REMOTEOBJECT_MODELS) << Q_FUNC_INFO << "FINAL start=" << it->start << "end=" << it->end << "roles=" << it->roles;
+
+ QRemoteObjectPendingReply<QtPrivate::DataEntries> reply = replicaRowRequest(it->start, it->end, it->roles);
+ RowWatcher *watcher = new RowWatcher(it->start, it->end, it->roles, reply);
+ rows += 1 + it->end.first().row - it->start.first().row;
+ m_pendingRequests.push_back(watcher);
+ connect(watcher, &RowWatcher::finished, this, &QAbstractItemModelReplicaImplementation::requestedData);
+ }
+}
+
+void QAbstractItemModelReplicaImplementation::onModelReset()
+{
+ if (!m_initDone)
+ return;
+
+ qCDebug(QT_REMOTEOBJECT_MODELS) << Q_FUNC_INFO;
+ QRemoteObjectPendingCallWatcher *watcher = doModelReset();
+ connect(watcher, &QRemoteObjectPendingCallWatcher::finished, this, &QAbstractItemModelReplicaImplementation::handleModelResetDone);
+}
+
+void QAbstractItemModelReplicaImplementation::onHeaderDataChanged(Qt::Orientation orientation, int first, int last)
+{
+ // TODO clean cache
+ const int index = orientation == Qt::Horizontal ? 0 : 1;
+ QList<CacheEntry> &entries = m_headerData[index];
+ for (int i = first; i <= last && i < entries.size(); ++i )
+ entries[i].data.clear();
+ emit q->headerDataChanged(orientation, first, last);
+}
+
+void QAbstractItemModelReplicaImplementation::fetchPendingHeaderData()
+{
+ QList<int> roles;
+ QList<int> sections;
+ QList<Qt::Orientation> orientations;
+ for (const RequestedHeaderData &data : qAsConst(m_requestedHeaderData)) {
+ roles.push_back(data.role);
+ sections.push_back(data.section);
+ orientations.push_back(data.orientation);
+ }
+ QRemoteObjectPendingReply<QVariantList> reply = replicaHeaderRequest(orientations, sections, roles);
+ HeaderWatcher *watcher = new HeaderWatcher(orientations, sections, roles, reply);
+ connect(watcher, &HeaderWatcher::finished, this, &QAbstractItemModelReplicaImplementation::requestedHeaderData);
+ m_requestedHeaderData.clear();
+ m_pendingRequests.push_back(watcher);
+}
+
+void QAbstractItemModelReplicaImplementation::onLayoutChanged(const QtPrivate::IndexList &parents,
+ QAbstractItemModel::LayoutChangeHint hint)
+{
+ QList<QPersistentModelIndex> indexes;
+ for (const QtPrivate::ModelIndex &parent : qAsConst(parents)) {
+ const QModelIndex parentIndex = toQModelIndex(QtPrivate::IndexList{parent}, q);
+ indexes << QPersistentModelIndex(parentIndex);
+ }
+ QRemoteObjectPendingCallWatcher *watcher;
+ auto call = replicaCacheRequest(m_rootItem.children.cacheSize, m_initialFetchRolesHint);
+ watcher = new QRemoteObjectPendingCallWatcher(call);
+ m_pendingRequests.push_back(watcher);
+ connect(watcher, &QRemoteObjectPendingCallWatcher::finished, this, [this, watcher, indexes, hint]() {
+ Q_ASSERT(watcher->returnValue().canConvert<QtPrivate::MetaAndDataEntries>());
+ const QSize size = watcher->returnValue().value<QtPrivate::MetaAndDataEntries>().size;
+
+ q->layoutAboutToBeChanged(indexes, hint);
+ m_rootItem.clear();
+ if (size.height() > 0) {
+ m_rootItem.rowCount = size.height();
+ m_rootItem.hasChildren = true;
+ }
+
+ m_rootItem.columnCount = size.width();
+ if (m_initialAction == QtRemoteObjects::PrefetchData) {
+ auto entries = watcher->returnValue().value<QtPrivate::MetaAndDataEntries>();
+ for (int i = 0; i < entries.data.size(); ++i)
+ fillCache(entries.data[i], entries.roles);
+ }
+ m_pendingRequests.removeAll(watcher);
+ watcher->deleteLater();
+ emit q->layoutChanged(indexes, hint);
+ });
+}
+
+static inline QList<QPair<int, int>> listRanges(const QList<int> &list)
+{
+ QList<QPair<int, int>> result;
+ if (!list.isEmpty()) {
+ QPair<int, int> currentElem = qMakePair(list.first(), list.first());
+ const auto end = list.constEnd();
+ for (auto it = list.constBegin() + 1; it != end; ++it) {
+ if (currentElem.first == *it + 1)
+ currentElem.first = *it;
+ else if ( currentElem.second == *it -1)
+ currentElem.second = *it;
+ else if (currentElem.first <= *it && currentElem.second >= *it)
+ continue;
+ else {
+ result.push_back(currentElem);
+ currentElem.first = *it;
+ currentElem.second = *it;
+ }
+ }
+ result.push_back(currentElem);
+ }
+ return result;
+}
+
+void QAbstractItemModelReplicaImplementation::requestedHeaderData(QRemoteObjectPendingCallWatcher *qobject)
+{
+ HeaderWatcher *watcher = static_cast<HeaderWatcher *>(qobject);
+ Q_ASSERT(watcher);
+
+ QVariantList data = watcher->returnValue().value<QVariantList>();
+ Q_ASSERT(watcher->orientations.size() == data.size());
+ Q_ASSERT(watcher->sections.size() == data.size());
+ Q_ASSERT(watcher->roles.size() == data.size());
+ QList<int> horizontalSections;
+ QList<int> verticalSections;
+
+ for (int i = 0; i < data.size(); ++i) {
+ if (watcher->orientations[i] == Qt::Horizontal)
+ horizontalSections.append(watcher->sections[i]);
+ else
+ verticalSections.append(watcher->sections[i]);
+ const int index = watcher->orientations[i] == Qt::Horizontal ? 0 : 1;
+ const int role = watcher->roles[i];
+ QHash<int, QVariant> &dat = m_headerData[index][watcher->sections[i]].data;
+ dat[role] = data[i];
+ }
+ QList<QPair<int, int>> horRanges = listRanges(horizontalSections);
+ QList<QPair<int, int>> verRanges = listRanges(verticalSections);
+
+ for (int i = 0; i < horRanges.size(); ++i)
+ emit q->headerDataChanged(Qt::Horizontal, horRanges[i].first, horRanges[i].second);
+ for (int i = 0; i < verRanges.size(); ++i)
+ emit q->headerDataChanged(Qt::Vertical, verRanges[i].first, verRanges[i].second);
+ m_pendingRequests.removeAll(watcher);
+ delete watcher;
+}
+
+/*!
+ \class QAbstractItemModelReplica
+ \inmodule QtRemoteObjects
+ \brief The QAbstractItemModelReplica class serves as a convenience class for
+ Replicas of Sources based on QAbstractItemModel.
+
+ QAbstractItemModelReplica makes replicating QAbstractItemModels more
+ efficient by employing caching and pre-fetching.
+
+ \sa QAbstractItemModel
+*/
+
+/*!
+ \internal
+*/
+QAbstractItemModelReplica::QAbstractItemModelReplica(QAbstractItemModelReplicaImplementation *rep, QtRemoteObjects::InitialAction action, const QList<int> &rolesHint)
+ : QAbstractItemModel()
+ , d(rep)
+{
+ d->m_initialAction = action;
+ d->m_initialFetchRolesHint = rolesHint;
+
+ rep->setModel(this);
+ connect(rep, &QAbstractItemModelReplicaImplementation::initialized, d.data(), &QAbstractItemModelReplicaImplementation::init);
+}
+
+/*!
+ Destroys the instance of QAbstractItemModelReplica.
+*/
+QAbstractItemModelReplica::~QAbstractItemModelReplica()
+{
+}
+
+static QVariant findData(const CachedRowEntry &row, const QModelIndex &index, int role, bool *cached = nullptr)
+{
+ if (index.column() < row.size()) {
+ const CacheEntry &entry = row[index.column()];
+ QHash<int, QVariant>::ConstIterator it = entry.data.constFind(role);
+ if (it != entry.data.constEnd()) {
+ if (cached)
+ *cached = true;
+ return it.value();
+ }
+ }
+ if (cached)
+ *cached = false;
+ return QVariant();
+}
+
+/*!
+ Returns a pointer to the QItemSelectionModel for the current
+ QAbstractItemModelReplica.
+*/
+QItemSelectionModel* QAbstractItemModelReplica::selectionModel() const
+{
+ return d->m_selectionModel.data();
+}
+
+/*!
+ \reimp
+*/
+bool QAbstractItemModelReplica::setData(const QModelIndex &index, const QVariant &value, int role)
+{
+ if (role == Qt::UserRole - 1) {
+ auto parent = d->cacheData(index);
+ if (!parent)
+ return false;
+ bool ok = true;
+ auto row = value.toInt(&ok);
+ if (ok)
+ parent->ensureChildren(row, row);
+ return ok;
+ }
+ if (!index.isValid())
+ return false;
+ if (index.row() < 0 || index.row() >= rowCount(index.parent()))
+ return false;
+ if (index.column() < 0 || index.column() >= columnCount(index.parent()))
+ return false;
+
+ const QList<int> &availRoles = availableRoles();
+ const auto res = std::find(availRoles.begin(), availRoles.end(), role);
+ if (res == availRoles.end()) {
+ qCWarning(QT_REMOTEOBJECT_MODELS) << "Tried to setData for index" << index << "on a not supported role" << role;
+ return false;
+ }
+ // sendInvocationRequest to change server side data;
+ d->replicaSetData(QtPrivate::toModelIndexList(index, this), value, role);
+ return true;
+}
+
+/*!
+ Returns the \a role data for the item at \a index if available in cache.
+ A default-constructed QVariant is returned if the index is invalid, the role
+ is not one of the available roles, the \l {Replica} is uninitialized or
+ the data was not available.
+ If the data was not available in cache it will be requested from the
+ \l {Source}.
+
+ \sa QAbstractItemModel::data(), hasData(), setData(), isInitialized()
+*/
+QVariant QAbstractItemModelReplica::data(const QModelIndex &index, int role) const
+{
+ if (!index.isValid())
+ return QVariant();
+
+ QModelRoleData roleData(role);
+ multiData(index, roleData);
+ return roleData.data();
+}
+
+/*!
+ \reimp
+*/
+void QAbstractItemModelReplica::multiData(const QModelIndex &index,
+ QModelRoleDataSpan roleDataSpan) const
+{
+ Q_ASSERT(checkIndex(index, CheckIndexOption::IndexIsValid));
+
+ if (!d->isInitialized()) {
+ qCDebug(QT_REMOTEOBJECT_MODELS)<<"Data not initialized yet";
+
+ for (auto &roleData : roleDataSpan)
+ roleData.clearData();
+ return;
+ }
+
+ QList<int> rolesToFetch;
+ const auto roles = availableRoles();
+ if (auto item = d->cacheData(index); item) {
+ // If the index is found in cache, try to find the data for each role
+ for (auto &roleData : roleDataSpan) {
+ const auto role = roleData.role();
+ if (roles.contains(role)) {
+ bool cached = false;
+ QVariant result = findData(item->cachedRowEntry, index, role, &cached);
+ if (cached) {
+ roleData.setData(std::move(result));
+ } else {
+ roleData.clearData();
+ rolesToFetch.push_back(role);
+ }
+ } else {
+ roleData.clearData();
+ }
+ }
+ } else {
+ // If the index is not found in cache, schedule all roles for fetching
+ for (auto &roleData : roleDataSpan) {
+ const auto role = roleData.role();
+ if (roles.contains(role))
+ rolesToFetch.push_back(role);
+ roleData.clearData();
+ }
+ }
+
+ if (rolesToFetch.empty())
+ return;
+
+ auto parentItem = d->cacheData(index.parent());
+ Q_ASSERT(parentItem);
+ Q_ASSERT(index.row() < parentItem->rowCount);
+ const int row = index.row();
+ QtPrivate::IndexList parentList = QtPrivate::toModelIndexList(index.parent(), this);
+ QtPrivate::IndexList start = QtPrivate::IndexList() << parentList << QtPrivate::ModelIndex(row, 0);
+ QtPrivate::IndexList end = QtPrivate::IndexList() << parentList << QtPrivate::ModelIndex(row, std::max(0, parentItem->columnCount - 1));
+ Q_ASSERT(toQModelIndex(start, this).isValid());
+
+ RequestedData data;
+ data.start = start;
+ data.end = end;
+ data.roles = rolesToFetch;
+ d->m_requestedData.push_back(data);
+ qCDebug(QT_REMOTEOBJECT_MODELS) << "FETCH PENDING DATA" << start << end << rolesToFetch;
+ QMetaObject::invokeMethod(d.data(), "fetchPendingData", Qt::QueuedConnection);
+}
+
+/*!
+ \reimp
+*/
+QModelIndex QAbstractItemModelReplica::parent(const QModelIndex &index) const
+{
+ if (!index.isValid() || !index.internalPointer())
+ return QModelIndex();
+ auto parent = static_cast<CacheData*>(index.internalPointer());
+ Q_ASSERT(parent);
+ if (parent == &d->m_rootItem)
+ return QModelIndex();
+ if (d->m_activeParents.find(parent) == d->m_activeParents.end() || d->m_activeParents.find(parent->parent) == d->m_activeParents.end())
+ return QModelIndex();
+ int row = parent->parent->children.find(parent);
+ Q_ASSERT(row >= 0);
+ return createIndex(row, 0, parent->parent);
+}
+
+/*!
+ \reimp
+*/
+QModelIndex QAbstractItemModelReplica::index(int row, int column, const QModelIndex &parent) const
+{
+ auto parentItem = d->cacheData(parent);
+ if (!parentItem)
+ return QModelIndex();
+
+ Q_ASSERT_X((parent.isValid() && parentItem && parentItem != &d->m_rootItem) || (!parent.isValid() && parentItem == &d->m_rootItem), __FUNCTION__, qPrintable(QString(QLatin1String("isValid=%1 equals=%2")).arg(parent.isValid()).arg(parentItem == &d->m_rootItem)));
+
+ // hmpf, following works around a Q_ASSERT-bug in QAbstractItemView::setModel which does just call
+ // d->model->index(0,0) without checking the range before-hand what triggers our assert in case the
+ // model is empty when view::setModel is called :-/ So, work around with the following;
+ if (row < 0 || row >= parentItem->rowCount)
+ return QModelIndex();
+
+ if (column < 0 || column >= parentItem->columnCount)
+ return QModelIndex();
+
+ if (parentItem != &d->m_rootItem)
+ parentItem->ensureChildren(row, row);
+ return createIndex(row, column, reinterpret_cast<void*>(parentItem));
+}
+
+/*!
+ \reimp
+*/
+bool QAbstractItemModelReplica::hasChildren(const QModelIndex &parent) const
+{
+ auto parentItem = d->cacheData(parent);
+ if (parent.isValid() && parent.column() != 0)
+ return false;
+ else
+ return parentItem ? parentItem->hasChildren : false;
+}
+
+/*!
+ \reimp
+*/
+int QAbstractItemModelReplica::rowCount(const QModelIndex &parent) const
+{
+ auto parentItem = d->cacheData(parent);
+ const bool canHaveChildren = parentItem && parentItem->hasChildren && !parentItem->rowCount && parent.column() == 0;
+ if (canHaveChildren) {
+ QtPrivate::IndexList parentList = QtPrivate::toModelIndexList(parent, this);
+ QRemoteObjectPendingReply<QSize> reply = d->replicaSizeRequest(parentList);
+ SizeWatcher *watcher = new SizeWatcher(parentList, reply);
+ connect(watcher, &SizeWatcher::finished, d.data(), &QAbstractItemModelReplicaImplementation::handleSizeDone);
+ } else if (parent.column() > 0) {
+ return 0;
+ }
+
+ return parentItem ? parentItem->rowCount : 0;
+}
+
+/*!
+ \reimp
+*/
+int QAbstractItemModelReplica::columnCount(const QModelIndex &parent) const
+{
+ if (parent.isValid() && parent.column() > 0)
+ return 0;
+ auto parentItem = d->cacheData(parent);
+ if (!parentItem)
+ return 0;
+ while (parentItem->columnCount < 0 && parentItem->parent)
+ parentItem = parentItem->parent;
+ return std::max(0, parentItem->columnCount);
+}
+
+/*!
+ Returns the data for the given \a role and \a section in the header with the
+ specified \a orientation.
+
+ If the data is not available it will be requested from the \l {Source}.
+
+ \sa QAbstractItemModel::headerData()
+*/
+QVariant QAbstractItemModelReplica::headerData(int section, Qt::Orientation orientation, int role) const
+{
+ const int index = orientation == Qt::Horizontal ? 0 : 1;
+ const QList<CacheEntry> elem = d->m_headerData[index];
+ if (section >= elem.size())
+ return QVariant();
+
+ const QHash<int, QVariant> &dat = elem.at(section).data;
+ QHash<int, QVariant>::ConstIterator it = dat.constFind(role);
+ if (it != dat.constEnd())
+ return it.value();
+
+ RequestedHeaderData data;
+ data.role = role;
+ data.section = section;
+ data.orientation = orientation;
+ d->m_requestedHeaderData.push_back(data);
+ QMetaObject::invokeMethod(d.data(), "fetchPendingHeaderData", Qt::QueuedConnection);
+ return QVariant();
+}
+
+/*!
+ \reimp
+*/
+Qt::ItemFlags QAbstractItemModelReplica::flags(const QModelIndex &index) const
+{
+ CacheEntry *entry = d->cacheEntry(index);
+ return entry ? entry->flags : Qt::NoItemFlags;
+}
+
+/*!
+ \fn void QAbstractItemModelReplica::initialized()
+
+ The initialized signal is emitted the first time we receive data
+ from the \l {Source}.
+
+ \sa isInitialized()
+*/
+
+/*!
+ Returns \c true if this replica has been initialized with data from the
+ \l {Source} object. Returns \c false otherwise.
+
+ \sa initialized()
+*/
+bool QAbstractItemModelReplica::isInitialized() const
+{
+ return d->isInitialized();
+}
+
+/*!
+ Returns \c true if there exists \a role data for the item at \a index.
+ Returns \c false in any other case.
+*/
+bool QAbstractItemModelReplica::hasData(const QModelIndex &index, int role) const
+{
+ if (!d->isInitialized() || !index.isValid())
+ return false;
+ auto item = d->cacheData(index);
+ if (!item)
+ return false;
+ bool cached = false;
+ const CachedRowEntry &entry = item->cachedRowEntry;
+ QVariant result = findData(entry, index, role, &cached);
+ Q_UNUSED(result)
+ return cached;
+}
+
+/*!
+ Returns the current size of the internal cache.
+ By default this is set to the value of the \c QTRO_NODES_CACHE_SIZE
+ environment variable, or a default of \c 1000 if it is invalid or doesn't
+ exist.
+
+ \sa setRootCacheSize()
+*/
+size_t QAbstractItemModelReplica::rootCacheSize() const
+{
+ return d->m_rootItem.children.cacheSize;
+}
+
+/*!
+ Sets the size of the internal cache to \a rootCacheSize.
+
+ \sa rootCacheSize()
+*/
+void QAbstractItemModelReplica::setRootCacheSize(size_t rootCacheSize)
+{
+ d->m_rootItem.children.setCacheSize(rootCacheSize);
+}
+
+/*!
+ Returns a list of available roles.
+
+ \sa QAbstractItemModel
+*/
+QList<int> QAbstractItemModelReplica::availableRoles() const
+{
+ return d->availableRoles();
+}
+
+/*!
+ \reimp
+*/
+QHash<int, QByteArray> QAbstractItemModelReplica::roleNames() const
+{
+ return d->roleNames();
+}
+
+QT_END_NAMESPACE
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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.LGPL3 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QREMOTEOBJECTS_ABSTRACTITEMMODELREPLICA_H
+#define QREMOTEOBJECTS_ABSTRACTITEMMODELREPLICA_H
+
+#include <QtRemoteObjects/qtremoteobjectglobal.h>
+
+#include <QtCore/qabstractitemmodel.h>
+#include <QtCore/qitemselectionmodel.h>
+
+QT_BEGIN_NAMESPACE
+
+class QAbstractItemModelReplicaImplementation;
+
+class Q_REMOTEOBJECTS_EXPORT QAbstractItemModelReplica : public QAbstractItemModel
+{
+ Q_OBJECT
+public:
+ ~QAbstractItemModelReplica() override;
+
+ QItemSelectionModel* selectionModel() const;
+
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const final;
+ void multiData(const QModelIndex &index, QModelRoleDataSpan roleDataSpan) const override;
+ bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;
+ QModelIndex parent(const QModelIndex & index) const override;
+ QModelIndex index(int row, int column, const QModelIndex & parent = QModelIndex()) const override;
+ bool hasChildren(const QModelIndex & parent = QModelIndex()) const override;
+ int rowCount(const QModelIndex & parent = QModelIndex()) const override;
+ int columnCount(const QModelIndex & parent = QModelIndex()) const override;
+ QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
+ Qt::ItemFlags flags(const QModelIndex &index) const override;
+ QList<int> availableRoles() const;
+ QHash<int, QByteArray> roleNames() const override;
+
+ bool isInitialized() const;
+ bool hasData(const QModelIndex &index, int role) const;
+
+ size_t rootCacheSize() const;
+ void setRootCacheSize(size_t rootCacheSize);
+
+Q_SIGNALS:
+ void initialized();
+
+private:
+ explicit QAbstractItemModelReplica(QAbstractItemModelReplicaImplementation *rep, QtRemoteObjects::InitialAction action, const QList<int> &rolesHint);
+ QScopedPointer<QAbstractItemModelReplicaImplementation> d;
+ friend class QAbstractItemModelReplicaImplementation;
+ friend class QRemoteObjectNode;
+};
+
+QT_END_NAMESPACE
+
+#endif // QREMOTEOBJECTS_ABSTRACTITEMMODELREPLICA_H
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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.LGPL3 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QREMOTEOBJECTS_ABSTRACT_ITEM_REPLICA_P_H
+#define QREMOTEOBJECTS_ABSTRACT_ITEM_REPLICA_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qremoteobjectabstractitemmodeltypes_p.h"
+#include "qremoteobjectabstractitemmodelreplica.h"
+#include "qremoteobjectreplica.h"
+#include "qremoteobjectpendingcall.h"
+#include <list>
+#include <unordered_map>
+#include <unordered_set>
+
+QT_BEGIN_NAMESPACE
+
+namespace {
+ const int DefaultNodesCacheSize = 1000;
+}
+
+struct CacheEntry
+{
+ QHash<int, QVariant> data;
+ Qt::ItemFlags flags;
+
+ explicit CacheEntry()
+ : flags(Qt::NoItemFlags)
+ {}
+};
+
+using CachedRowEntry = QList<CacheEntry>;
+
+template <class Key, class Value>
+struct LRUCache
+{
+ typedef std::pair<Key, Value*> Pair;
+ std::list<Pair> cachedItems;
+ typedef typename std::list<Pair>::iterator CacheIterator;
+ std::unordered_map<Key, CacheIterator> cachedItemsMap;
+ size_t cacheSize;
+
+ explicit LRUCache()
+ {
+ bool ok;
+ cacheSize = qEnvironmentVariableIntValue("QTRO_NODES_CACHE_SIZE" , &ok);
+ if (!ok)
+ cacheSize = DefaultNodesCacheSize;
+ }
+
+ ~LRUCache()
+ {
+ clear();
+ }
+
+ inline void cleanCache()
+ {
+ Q_ASSERT(cachedItems.size() == cachedItemsMap.size());
+
+ auto it = cachedItems.rbegin();
+ while (cachedItemsMap.size() > cacheSize) {
+ // Do not trash elements with children
+ // Workaround QTreeView bugs which caches the children indexes for very long time
+ while (it->second->hasChildren && it != cachedItems.rend())
+ ++it;
+
+ if (it == cachedItems.rend())
+ break;
+
+ cachedItemsMap.erase(it->first);
+ delete it->second;
+ cachedItems.erase((++it).base());
+ }
+ Q_ASSERT(cachedItems.size() == cachedItemsMap.size());
+ }
+
+ void setCacheSize(size_t rootCacheSize)
+ {
+ cacheSize = rootCacheSize;
+ cleanCache();
+ cachedItemsMap.reserve(rootCacheSize);
+ }
+
+ void changeKeys(Key key, Key delta) {
+ std::vector<std::pair<Key, CacheIterator>> changed;
+ auto it = cachedItemsMap.begin();
+ while (it != cachedItemsMap.end()) {
+ if (it->first >= key) {
+ changed.emplace_back(it->first + delta, it->second);
+ it->second->first += delta;
+ it = cachedItemsMap.erase(it);
+ } else {
+ ++it;
+ }
+ }
+ for (auto pair : changed)
+ cachedItemsMap[pair.first] = pair.second;
+ }
+
+ void insert(Key key, Value *value)
+ {
+ changeKeys(key, 1);
+ ensure(key, value);
+ Q_ASSERT(cachedItems.size() == cachedItemsMap.size());
+ }
+
+ void ensure(Key key, Value *value)
+ {
+ cachedItems.emplace_front(key, value);
+ cachedItemsMap[key] = cachedItems.begin();
+ cleanCache();
+ }
+
+ void remove(Key key)
+ {
+ auto it = cachedItemsMap.find(key);
+ if (it != cachedItemsMap.end()) {
+ delete it->second->second;
+ cachedItems.erase(it->second);
+ cachedItemsMap.erase(it);
+ }
+ changeKeys(key, -1);
+ Q_ASSERT(cachedItems.size() == cachedItemsMap.size());
+ }
+
+ Value *get(Key key)
+ {
+ auto it = cachedItemsMap.find(key);
+ if (it == cachedItemsMap.end())
+ return nullptr;
+
+ // Move the accessed item to front
+ cachedItems.splice(cachedItems.begin(), cachedItems, it->second);
+ Q_ASSERT(it->second->first == key);
+ return it->second->second;
+ }
+
+ Key find(Value *val)
+ {
+ for (auto it = cachedItemsMap.begin(); it != cachedItemsMap.end(); ++it) {
+ if (it->second->second == val)
+ return it->first;
+ }
+ Q_ASSERT_X(false, __FUNCTION__, "Value not found");
+ return Key{};
+ }
+
+ bool exists(Value *val)
+ {
+ for (const auto &pair : cachedItems)
+ if (pair.second == val)
+ return true;
+
+ return false;
+ }
+
+ bool exists(Key key)
+ {
+ return cachedItemsMap.find(key) != cachedItemsMap.end();
+ }
+
+ size_t size()
+ {
+ return cachedItemsMap.size();
+ }
+
+ void clear()
+ {
+ for (const auto &pair : cachedItems)
+ delete pair.second;
+ cachedItems.clear();
+ cachedItemsMap.clear();
+ }
+};
+
+class QAbstractItemModelReplicaImplementation;
+struct CacheData
+{
+ QAbstractItemModelReplicaImplementation *replicaModel;
+ CacheData *parent;
+ CachedRowEntry cachedRowEntry;
+
+ bool hasChildren;
+ LRUCache<int, CacheData> children;
+ int columnCount;
+ int rowCount;
+
+ explicit CacheData(QAbstractItemModelReplicaImplementation *model, CacheData *parentItem = nullptr);
+
+ ~CacheData();
+
+ void ensureChildren(int start, int end)
+ {
+ for (int i = start; i <= end; ++i)
+ if (!children.exists(i))
+ children.ensure(i, new CacheData(replicaModel, this));
+ }
+
+ void insertChildren(int start, int end) {
+ Q_ASSERT_X(start >= 0 && start <= end, __FUNCTION__, qPrintable(QString(QLatin1String("0 <= %1 <= %2")).arg(start).arg(end)));
+ for (int i = start; i <= end; ++i) {
+ auto cacheData = new CacheData(replicaModel, this);
+ cacheData->columnCount = columnCount;
+ children.insert(i, cacheData);
+ ++rowCount;
+ }
+ if (rowCount)
+ hasChildren = true;
+ }
+ void removeChildren(int start, int end) {
+ Q_ASSERT_X(start >= 0 && start <= end && end < rowCount, __FUNCTION__, qPrintable(QString(QLatin1String("0 <= %1 <= %2 < %3")).arg(start).arg(end).arg(rowCount)));
+ for (int i = end; i >= start; --i) {
+ children.remove(i);
+ --rowCount;
+ }
+ hasChildren = rowCount;
+ }
+ void clear() {
+ cachedRowEntry.clear();
+ children.clear();
+ hasChildren = false;
+ columnCount = 0;
+ rowCount = 0;
+ }
+};
+
+struct RequestedData
+{
+ QtPrivate::IndexList start;
+ QtPrivate::IndexList end;
+ QList<int> roles;
+};
+
+struct RequestedHeaderData
+{
+ int role;
+ int section;
+ Qt::Orientation orientation;
+};
+
+class SizeWatcher : public QRemoteObjectPendingCallWatcher
+{
+ Q_OBJECT
+public:
+ SizeWatcher(QtPrivate::IndexList _parentList, const QRemoteObjectPendingReply<QSize> &reply)
+ : QRemoteObjectPendingCallWatcher(reply),
+ parentList(_parentList) {}
+ QtPrivate::IndexList parentList;
+};
+
+class RowWatcher : public QRemoteObjectPendingCallWatcher
+{
+ Q_OBJECT
+public:
+ RowWatcher(QtPrivate::IndexList _start, QtPrivate::IndexList _end, QList<int> _roles, const QRemoteObjectPendingReply<QtPrivate::DataEntries> &reply)
+ : QRemoteObjectPendingCallWatcher(reply),
+ start(_start),
+ end(_end),
+ roles(_roles) {}
+ QtPrivate::IndexList start, end;
+ QList<int> roles;
+};
+
+class HeaderWatcher : public QRemoteObjectPendingCallWatcher
+{
+ Q_OBJECT
+public:
+ HeaderWatcher(QList<Qt::Orientation> _orientations, QList<int> _sections, QList<int> _roles, const QRemoteObjectPendingReply<QVariantList> &reply)
+ : QRemoteObjectPendingCallWatcher(reply),
+ orientations(_orientations),
+ sections(_sections),
+ roles(_roles) {}
+ QList<Qt::Orientation> orientations;
+ QList<int> sections, roles;
+};
+
+class QAbstractItemModelReplicaImplementation : public QRemoteObjectReplica
+{
+ Q_OBJECT
+ //TODO Use an input name for the model on the Replica side
+ Q_CLASSINFO(QCLASSINFO_REMOTEOBJECT_TYPE, "ServerModelAdapter")
+ Q_PROPERTY(QList<int> availableRoles READ availableRoles NOTIFY availableRolesChanged)
+ Q_PROPERTY(QIntHash roleNames READ roleNames)
+public:
+ QAbstractItemModelReplicaImplementation();
+ QAbstractItemModelReplicaImplementation(QRemoteObjectNode *node, const QString &name);
+ ~QAbstractItemModelReplicaImplementation() override;
+ void initialize() override;
+ static void registerMetatypes();
+
+ inline const QList<int> &availableRoles() const
+ {
+ if (m_availableRoles.isEmpty())
+ m_availableRoles = propAsVariant(0).value<QList<int>>();
+ return m_availableRoles;
+ }
+
+ QHash<int, QByteArray> roleNames() const
+ {
+ QIntHash roles = propAsVariant(1).value<QIntHash>();
+ return roles;
+ }
+
+ void setModel(QAbstractItemModelReplica *model);
+ bool clearCache(const QtPrivate::IndexList &start, const QtPrivate::IndexList &end, const QList<int> &roles);
+
+Q_SIGNALS:
+ void availableRolesChanged();
+ void dataChanged(QtPrivate::IndexList topLeft, QtPrivate::IndexList bottomRight, QList<int> roles);
+ void rowsInserted(QtPrivate::IndexList parent, int first, int last);
+ void rowsRemoved(QtPrivate::IndexList parent, int first, int last);
+ void rowsMoved(QtPrivate::IndexList parent, int start, int end, QtPrivate::IndexList destination, int row);
+ void currentChanged(QtPrivate::IndexList current, QtPrivate::IndexList previous);
+ void modelReset();
+ void headerDataChanged(Qt::Orientation,int,int);
+ void columnsInserted(QtPrivate::IndexList parent, int first, int last);
+ void layoutChanged(QtPrivate::IndexList parents, QAbstractItemModel::LayoutChangeHint hint);
+public Q_SLOTS:
+ QRemoteObjectPendingReply<QSize> replicaSizeRequest(QtPrivate::IndexList parentList)
+ {
+ static int __repc_index = QAbstractItemModelReplicaImplementation::staticMetaObject.indexOfSlot("replicaSizeRequest(QtPrivate::IndexList)");
+ QVariantList __repc_args;
+ __repc_args << QVariant::fromValue(parentList);
+ return QRemoteObjectPendingReply<QSize>(sendWithReply(QMetaObject::InvokeMetaMethod, __repc_index, __repc_args));
+ }
+ QRemoteObjectPendingReply<QtPrivate::DataEntries> replicaRowRequest(QtPrivate::IndexList start, QtPrivate::IndexList end, QList<int> roles)
+ {
+ static int __repc_index = QAbstractItemModelReplicaImplementation::staticMetaObject.indexOfSlot("replicaRowRequest(QtPrivate::IndexList,QtPrivate::IndexList,QList<int>)");
+ QVariantList __repc_args;
+ __repc_args << QVariant::fromValue(start) << QVariant::fromValue(end) << QVariant::fromValue(roles);
+ return QRemoteObjectPendingReply<QtPrivate::DataEntries>(sendWithReply(QMetaObject::InvokeMetaMethod, __repc_index, __repc_args));
+ }
+ QRemoteObjectPendingReply<QVariantList> replicaHeaderRequest(QList<Qt::Orientation> orientations, QList<int> sections, QList<int> roles)
+ {
+ static int __repc_index = QAbstractItemModelReplicaImplementation::staticMetaObject.indexOfSlot("replicaHeaderRequest(QList<Qt::Orientation>,QList<int>,QList<int>)");
+ QVariantList __repc_args;
+ __repc_args << QVariant::fromValue(orientations) << QVariant::fromValue(sections) << QVariant::fromValue(roles);
+ return QRemoteObjectPendingReply<QVariantList>(sendWithReply(QMetaObject::InvokeMetaMethod, __repc_index, __repc_args));
+ }
+ void replicaSetCurrentIndex(QtPrivate::IndexList index, QItemSelectionModel::SelectionFlags command)
+ {
+ static int __repc_index = QAbstractItemModelReplicaImplementation::staticMetaObject.indexOfSlot("replicaSetCurrentIndex(QtPrivate::IndexList,QItemSelectionModel::SelectionFlags)");
+ QVariantList __repc_args;
+ __repc_args << QVariant::fromValue(index) << QVariant::fromValue(command);
+ send(QMetaObject::InvokeMetaMethod, __repc_index, __repc_args);
+ }
+ void replicaSetData(QtPrivate::IndexList index, const QVariant &value, int role)
+ {
+ static int __repc_index = QAbstractItemModelReplicaImplementation::staticMetaObject.indexOfSlot("replicaSetData(QtPrivate::IndexList,QVariant,int)");
+ QVariantList __repc_args;
+ __repc_args << QVariant::fromValue(index) << QVariant::fromValue(value) << QVariant::fromValue(role);
+ send(QMetaObject::InvokeMetaMethod, __repc_index, __repc_args);
+ }
+ QRemoteObjectPendingReply<QtPrivate::MetaAndDataEntries> replicaCacheRequest(size_t size, QList<int> roles)
+ {
+ static int __repc_index = QAbstractItemModelReplicaImplementation::staticMetaObject.indexOfSlot("replicaCacheRequest(size_t,QList<int>)");
+ QVariantList __repc_args;
+ __repc_args << QVariant::fromValue(size) << QVariant::fromValue(roles);
+ return QRemoteObjectPendingReply<QtPrivate::MetaAndDataEntries>(sendWithReply(QMetaObject::InvokeMetaMethod, __repc_index, __repc_args));
+ }
+ void onHeaderDataChanged(Qt::Orientation orientation, int first, int last);
+ void onDataChanged(const QtPrivate::IndexList &start, const QtPrivate::IndexList &end, const QList<int> &roles);
+ void onRowsInserted(const QtPrivate::IndexList &parent, int start, int end);
+ void onRowsRemoved(const QtPrivate::IndexList &parent, int start, int end);
+ void onColumnsInserted(const QtPrivate::IndexList &parent, int start, int end);
+ void onRowsMoved(QtPrivate::IndexList srcParent, int srcRow, int count, QtPrivate::IndexList destParent, int destRow);
+ void onCurrentChanged(QtPrivate::IndexList current, QtPrivate::IndexList previous);
+ void onModelReset();
+ void requestedData(QRemoteObjectPendingCallWatcher *);
+ void requestedHeaderData(QRemoteObjectPendingCallWatcher *);
+ void init();
+ void fetchPendingData();
+ void fetchPendingHeaderData();
+ void handleInitDone(QRemoteObjectPendingCallWatcher *watcher);
+ void handleModelResetDone(QRemoteObjectPendingCallWatcher *watcher);
+ void handleSizeDone(QRemoteObjectPendingCallWatcher *watcher);
+ void onReplicaCurrentChanged(const QModelIndex ¤t, const QModelIndex &previous);
+ void fillCache(const QtPrivate::IndexValuePair &pair,const QList<int> &roles);
+ void onLayoutChanged(const QtPrivate::IndexList &parents, QAbstractItemModel::LayoutChangeHint hint);
+public:
+ QScopedPointer<QItemSelectionModel> m_selectionModel;
+ QList<CacheEntry> m_headerData[2];
+
+ CacheData m_rootItem;
+ inline CacheData* cacheData(const QModelIndex &index) const {
+ if (!index.isValid())
+ return const_cast<CacheData*>(&m_rootItem);
+ if (index.internalPointer()) {
+ auto parent = static_cast<CacheData*>(index.internalPointer());
+ if (m_activeParents.find(parent) != m_activeParents.end())
+ return parent->children.get(index.row());
+ }
+ return nullptr;
+ }
+ inline CacheData* cacheData(const QtPrivate::IndexList &index) const {
+ return cacheData(toQModelIndex(index, q));
+ }
+ inline CacheData* createCacheData(const QtPrivate::IndexList &index) const {
+ auto modelIndex = toQModelIndex(index, q);
+ cacheData(modelIndex.parent())->ensureChildren(modelIndex.row() , modelIndex.row());
+ return cacheData(modelIndex);
+ }
+ inline CacheEntry* cacheEntry(const QModelIndex &index) const {
+ auto data = cacheData(index);
+ if (!data || index.column() < 0 || index.column() >= data->cachedRowEntry.size())
+ return nullptr;
+ CacheEntry &entry = data->cachedRowEntry[index.column()];
+ return &entry;
+ }
+ inline CacheEntry* cacheEntry(const QtPrivate::IndexList &index) const {
+ return cacheEntry(toQModelIndex(index, q));
+ }
+
+ QRemoteObjectPendingCallWatcher *doModelReset();
+ void initializeModelConnections();
+
+ bool m_initDone = false;
+ QList<RequestedData> m_requestedData;
+ QList<RequestedHeaderData> m_requestedHeaderData;
+ QList<QRemoteObjectPendingCallWatcher*> m_pendingRequests;
+ QAbstractItemModelReplica *q;
+ mutable QList<int> m_availableRoles;
+ std::unordered_set<CacheData*> m_activeParents;
+ QtRemoteObjects::InitialAction m_initialAction;
+ QList<int> m_initialFetchRolesHint;
+};
+
+QT_END_NAMESPACE
+
+#endif // QREMOTEOBJECTS_ABSTRACT_ITEM_REPLICA_P_H
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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.LGPL3 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QREMOTEOBJECTS_ABSTRACT_ITEM_MODEL_TYPES_P_H
+#define QREMOTEOBJECTS_ABSTRACT_ITEM_MODEL_TYPES_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qabstractitemmodel.h>
+#include <QtCore/qdatastream.h>
+#include <QtCore/qdebug.h>
+#include <QtCore/qitemselectionmodel.h>
+#include <QtCore/qlist.h>
+#include <QtCore/qnamespace.h>
+#include <QtCore/qpair.h>
+#include <QtCore/qsize.h>
+#include <QtCore/qvariant.h>
+#include <QtRemoteObjects/qtremoteobjectglobal.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QtPrivate {
+
+struct ModelIndex
+{
+ ModelIndex() : row(-1), column(-1) {}
+ ModelIndex(int row_, int column_)
+ : row(row_)
+ , column(column_)
+ {}
+
+ inline bool operator==(const ModelIndex &other) const { return row == other.row && column == other.column; }
+ inline bool operator!=(const ModelIndex &other) const { return !(*this == other); }
+ int row;
+ int column;
+};
+
+typedef QList<ModelIndex> IndexList;
+
+struct IndexValuePair
+{
+ explicit IndexValuePair(const IndexList index_ = IndexList(), const QVariantList &data_ = QVariantList(),
+ bool hasChildren_ = false, const Qt::ItemFlags &flags_ = Qt::ItemFlags(), const QSize &size_ = {})
+ : index(index_)
+ , data(data_)
+ , flags(flags_)
+ , hasChildren(hasChildren_)
+ , size(size_)
+ {}
+
+ inline bool operator==(const IndexValuePair &other) const { return index == other.index && data == other.data && hasChildren == other.hasChildren && flags == other.flags; }
+ inline bool operator!=(const IndexValuePair &other) const { return !(*this == other); }
+
+ IndexList index;
+ QVariantList data;
+ Qt::ItemFlags flags;
+ bool hasChildren;
+ QList<IndexValuePair> children;
+ QSize size;
+};
+
+struct DataEntries
+{
+ inline bool operator==(const DataEntries &other) const { return data == other.data; }
+ inline bool operator!=(const DataEntries &other) const { return !(*this == other); }
+
+ QList<IndexValuePair> data;
+};
+
+struct MetaAndDataEntries : DataEntries
+{
+ QList<int> roles;
+ QSize size;
+};
+
+inline QDebug operator<<(QDebug stream, const ModelIndex &index)
+{
+ return stream.nospace() << "ModelIndex[row=" << index.row << ", column=" << index.column << "]";
+}
+
+inline QDataStream& operator<<(QDataStream &stream, const ModelIndex &index)
+{
+ return stream << index.row << index.column;
+}
+
+inline QDataStream& operator>>(QDataStream &stream, ModelIndex &index)
+{
+ return stream >> index.row >> index.column;
+}
+
+inline QDataStream& operator<<(QDataStream &stream, Qt::Orientation orient)
+{
+ return stream << static_cast<int>(orient);
+}
+
+inline QDataStream& operator>>(QDataStream &stream, Qt::Orientation &orient)
+{
+ int val;
+ QDataStream &ret = stream >> val;
+ orient = static_cast<Qt::Orientation>(val);
+ return ret;
+}
+
+inline QDataStream& operator<<(QDataStream &stream, QItemSelectionModel::SelectionFlags command)
+{
+ return stream << static_cast<int>(command);
+}
+
+inline QDataStream& operator>>(QDataStream &stream, QItemSelectionModel::SelectionFlags &command)
+{
+ int val;
+ QDataStream &ret = stream >> val;
+ command = static_cast<QItemSelectionModel::SelectionFlags>(val);
+ return ret;
+}
+
+inline QDebug operator<<(QDebug stream, const IndexValuePair &pair)
+{
+ return stream.nospace() << "IndexValuePair[index=" << pair.index << ", data=" << pair.data << ", hasChildren=" << pair.hasChildren << ", flags=" << pair.flags << "]";
+}
+
+inline QDataStream& operator<<(QDataStream &stream, const IndexValuePair &pair)
+{
+ return stream << pair.index << pair.data << pair.hasChildren << static_cast<int>(pair.flags) << pair.children << pair.size;
+}
+
+inline QDataStream& operator>>(QDataStream &stream, IndexValuePair &pair)
+{
+ int flags;
+ QDataStream &ret = stream >> pair.index >> pair.data >> pair.hasChildren >> flags >> pair.children >> pair.size;
+ pair.flags = static_cast<Qt::ItemFlags>(flags);
+ return ret;
+}
+
+inline QDebug operator<<(QDebug stream, const DataEntries &entries)
+{
+ return stream.nospace() << "DataEntries[" << entries.data << "]";
+}
+
+inline QDataStream& operator<<(QDataStream &stream, const DataEntries &entries)
+{
+ return stream << entries.data;
+}
+
+inline QDataStream& operator>>(QDataStream &stream, DataEntries &entries)
+{
+ return stream >> entries.data;
+}
+
+inline QDataStream& operator<<(QDataStream &stream, const MetaAndDataEntries &entries)
+{
+ return stream << entries.data << entries.roles << entries.size;
+}
+
+inline QDataStream& operator>>(QDataStream &stream, MetaAndDataEntries &entries)
+{
+ return stream >> entries.data >> entries.roles >> entries.size;
+}
+
+inline QString modelIndexToString(const IndexList &list)
+{
+ QString s;
+ QDebug(&s) << list;
+ return s;
+}
+
+inline QString modelIndexToString(const ModelIndex &index)
+{
+ QString s;
+ QDebug(&s) << index;
+ return s;
+}
+
+inline QModelIndex toQModelIndex(const IndexList &list, const QAbstractItemModel *model, bool *ok = nullptr, bool ensureItem = false)
+{
+ if (ok)
+ *ok = true;
+ QModelIndex result;
+ for (int i = 0; i < list.count(); ++i) {
+ const ModelIndex &index = list[i];
+ if (ensureItem)
+ const_cast<QAbstractItemModel *>(model)->setData(result, index.row, Qt::UserRole - 1);
+
+ result = model->index(index.row, index.column, result);
+ if (!result.isValid()) {
+ if (ok) {
+ *ok = false;
+ } else {
+ qFatal("Internal error: invalid index=%s in indexList=%s",
+ qPrintable(modelIndexToString(list[i])), qPrintable(modelIndexToString(list)));
+ }
+ return QModelIndex();
+ }
+ }
+ return result;
+}
+
+inline IndexList toModelIndexList(const QModelIndex &index, const QAbstractItemModel *model)
+{
+ IndexList list;
+ if (index.isValid()) {
+ list << ModelIndex(index.row(), index.column());
+ for (QModelIndex curIndex = model->parent(index); curIndex.isValid(); curIndex = model->parent(curIndex))
+ list.prepend(ModelIndex(curIndex.row(), curIndex.column()));
+ }
+ return list;
+}
+
+} // namespace QtPrivate
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(QtPrivate::ModelIndex)
+Q_DECLARE_METATYPE(QtPrivate::IndexList)
+Q_DECLARE_METATYPE(QtPrivate::DataEntries)
+Q_DECLARE_METATYPE(QtPrivate::MetaAndDataEntries)
+Q_DECLARE_METATYPE(QtPrivate::IndexValuePair)
+Q_DECLARE_METATYPE(Qt::Orientation)
+Q_DECLARE_METATYPE(QItemSelectionModel::SelectionFlags)
+
+#endif // QREMOTEOBJECTS_ABSTRACT_ITEM_MODEL_TYPES_P_H
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2021 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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.LGPL3 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtCore/qiodevice.h>
+
+#include "qremoteobjectcontainers_p.h"
+#include "qremoteobjectpacket_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QDataStream &operator>>(QDataStream &ds, QtROSequentialContainer &p)
+{
+ QByteArray typeName;
+ quint32 count;
+ ds >> typeName;
+ p.setValueType(typeName);
+ ds >> count;
+ p.reserve(count);
+ QVariant value{p.m_valueType, nullptr};
+ for (quint32 i = 0; i < count; i++) {
+ if (!p.m_valueType.load(ds, value.data())) {
+ qWarning("QSQ_: unable to load type '%s', returning an empty list.", p.m_valueTypeName.constData());
+ p.clear();
+ break;
+ }
+ p.append(value);
+ }
+ return ds;
+}
+
+QDataStream &operator<<(QDataStream &ds, const QtROSequentialContainer &p)
+{
+ ds << p.m_valueTypeName;
+ auto pos = ds.device()->pos();
+ quint32 count = p.count();
+ ds << count;
+ for (quint32 i = 0; i < count; i++) {
+ if (!p.m_valueType.save(ds, p.at(i).data())) {
+ ds.device()->seek(pos);
+ ds.resetStatus();
+ ds << quint32(0);
+ qWarning("QSQ_: unable to save type '%s'.", p.m_valueTypeName.constData());
+ break;
+ }
+ }
+ return ds;
+}
+
+const char *descopedName(QMetaType type) {
+ auto name = QByteArray::fromRawData(type.name(), qstrlen(type.name()));
+ int index = name.lastIndexOf(':'); // Returns -1 if not found
+ return type.name() + index + 1;
+}
+
+QDataStream &operator>>(QDataStream &ds, QtROAssociativeContainer &p)
+{
+ QByteArray keyTypeName, valueTypeName;
+ quint32 count;
+ ds >> keyTypeName;
+ ds >> valueTypeName;
+ p.setTypes(keyTypeName, valueTypeName);
+ ds >> count;
+ p.m_keys.reserve(count);
+ auto transferType = p.m_keyType;
+ if (p.m_keyType.flags().testFlag(QMetaType::IsEnumeration))
+ transferType = QRemoteObjectPackets::transferTypeForEnum(p.m_keyType);
+ QVariant key{transferType, nullptr};
+ QVariant value{p.m_valueType, nullptr};
+ for (quint32 i = 0; i < count; i++) {
+ if (!transferType.load(ds, key.data())) {
+ qWarning("QAS_: unable to load key '%s', returning an empty map.", p.m_keyTypeName.constData());
+ p.clear();
+ break;
+ }
+ if (!p.m_valueType.load(ds, value.data())) {
+ qWarning("QAS_: unable to load value '%s', returning an empty map.", p.m_valueTypeName.constData());
+ p.clear();
+ break;
+ }
+ if (transferType != p.m_keyType) {
+ bool isFlag = false;
+ QVariant enumKey(key);
+ enumKey.convert(p.m_keyType);
+ p.m_keys.append(enumKey);
+ if (auto meta = p.m_keyType.metaObject()) {
+ int index = meta->indexOfEnumerator(descopedName(p.m_keyType));
+ isFlag = meta->enumerator(index).isFlag();
+ }
+ // If multiple flag values are set, toString() returns an empty string
+ // Thus, for flags, we convert the integer value to a string
+ if (isFlag)
+ p.insert(key.toString(), value);
+ else
+ p.insert(enumKey.toString(), value);
+ } else {
+ p.insert(key.toString(), value);
+ p.m_keys.append(key);
+ }
+ }
+ return ds;
+}
+
+QDataStream &operator<<(QDataStream &ds, const QtROAssociativeContainer &p)
+{
+ ds << p.m_keyTypeName;
+ ds << p.m_valueTypeName;
+ auto pos = ds.device()->pos();
+ quint32 count = p.count();
+ ds << count;
+ QAssociativeIterable map(&p);
+ QAssociativeIterable::const_iterator iter = map.begin();
+ auto transferType = p.m_keyType;
+ if (p.m_keyType.flags().testFlag(QMetaType::IsEnumeration))
+ transferType = QRemoteObjectPackets::transferTypeForEnum(p.m_keyType);
+ bool keySaved;
+ for (quint32 i = 0; i < count; i++) {
+ if (transferType != p.m_keyType) {
+ QVariant intKey(iter.key());
+ intKey.convert(transferType);
+ keySaved = transferType.save(ds, intKey.data());
+ } else {
+ keySaved = transferType.save(ds, iter.key().data());
+ }
+ if (!keySaved) {
+ ds.device()->seek(pos);
+ ds.resetStatus();
+ ds << quint32(0);
+ qWarning("QAS_: unable to save type '%s'.", p.m_valueTypeName.constData());
+ break;
+ }
+ if (!p.m_valueType.save(ds, iter.value().data())) {
+ ds.device()->seek(pos);
+ ds.resetStatus();
+ ds << quint32(0);
+ qWarning("QAS_: unable to save type '%s'.", p.m_valueTypeName.constData());
+ break;
+ }
+ iter++;
+ }
+ return ds;
+}
+
+QT_END_NAMESPACE
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2021 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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.LGPL3 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#pragma once
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qassociativeiterable.h>
+#include <QtCore/qsequentialiterable.h>
+#include <QtCore/qvariant.h>
+
+QT_BEGIN_NAMESPACE
+
+class QtROSequentialContainer : public QVariantList
+{
+public:
+ QtROSequentialContainer() = default;
+ QtROSequentialContainer(const QSequentialIterable &lst)
+ {
+ m_valueType = lst.metaContainer().valueMetaType();
+ reserve(lst.size());
+ for (const auto v : lst)
+ append(v);
+ }
+ void setValueType(const QByteArray &valueTypeName)
+ {
+ m_valueTypeName = valueTypeName;
+ m_valueType = QMetaType::fromName(valueTypeName.constData());
+ clear();
+ }
+
+ QMetaType m_valueType;
+ QByteArray m_typeName, m_valueTypeName;
+};
+
+QDataStream &operator>>(QDataStream &ds, QtROSequentialContainer &p);
+
+QDataStream &operator<<(QDataStream &ds, const QtROSequentialContainer &p);
+
+class QtROAssociativeContainer : public QVariantMap
+{
+public:
+ QtROAssociativeContainer() = default;
+ QtROAssociativeContainer(const QAssociativeIterable &map)
+ {
+ m_keyType = map.metaContainer().keyMetaType();
+ m_valueType = map.metaContainer().mappedMetaType();
+ m_keys.reserve(map.size());
+ QAssociativeIterable::const_iterator iter = map.begin();
+ const QAssociativeIterable::const_iterator end = map.end();
+ for ( ; iter != end; ++iter) {
+ m_keys.append(iter.key());
+ insert(iter.key().toString(), iter.value());
+ }
+ }
+ void setTypes(const QByteArray &keyTypeName, const QByteArray &valueTypeName)
+ {
+ m_keyTypeName = keyTypeName;
+ m_keyType = QMetaType::fromName(keyTypeName.constData());
+ m_valueTypeName = valueTypeName;
+ m_valueType = QMetaType::fromName(valueTypeName.constData());
+ clear();
+ m_keys.clear();
+ }
+
+ QMetaType m_keyType, m_valueType;
+ QByteArray m_typeName, m_keyTypeName, m_valueTypeName;
+ QVariantList m_keys; // Map uses QString for key, this doesn't lose information for proxy
+};
+
+QDataStream &operator>>(QDataStream &ds, QtROAssociativeContainer &p);
+
+QDataStream &operator<<(QDataStream &ds, const QtROAssociativeContainer &p);
+
+QT_END_NAMESPACE
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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.LGPL3 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qremoteobjectdynamicreplica.h"
+#include "qremoteobjectreplica_p.h"
+
+#include <QtCore/qmetaobject.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QRemoteObjectDynamicReplica
+ \inmodule QtRemoteObjects
+ \brief A dynamically instantiated \l {Replica}.
+
+ There are generated replicas (replicas having the header files produced by
+ the \l {repc} {Replica Compiler}), and dynamic replicas, that are generated
+ on-the-fly. This is the class for the dynamic type of replica.
+
+ When the connection to the \l {Source} object is made, the initialization
+ step passes the current property values (see \l {Replica Initialization}).
+ In a DynamicReplica, the property/signal/slot details are also sent,
+ allowing the replica object to be created on-the-fly. This can be convenient
+ in QML or scripting, but has two primary disadvantages. First, the object is
+ in effect "empty" until it is successfully initialized by the \l {Source}.
+ Second, in C++, calls must be made using QMetaObject::invokeMethod(), as the
+ moc generated lookup will not be available.
+
+ This class does not have a public constructor. It can only be instantiated
+ by using the dynamic QRemoteObjectNode::acquire method.
+*/
+
+QRemoteObjectDynamicReplica::QRemoteObjectDynamicReplica()
+ : QRemoteObjectReplica()
+{
+}
+
+QRemoteObjectDynamicReplica::QRemoteObjectDynamicReplica(QRemoteObjectNode *node, const QString &name)
+ : QRemoteObjectReplica(ConstructWithNode)
+{
+ initializeNode(node, name);
+}
+
+/*!
+ Destroys the dynamic replica.
+
+ \sa {Replica Ownership}
+*/
+QRemoteObjectDynamicReplica::~QRemoteObjectDynamicReplica()
+{
+}
+
+/*!
+ \internal
+ Returns a pointer to the dynamically generated meta-object of this object, or
+ QRemoteObjectDynamicReplica's metaObject if the object is not initialized. This
+ function overrides the QObject::metaObject() virtual function to provide the same
+ functionality for dynamic replicas.
+
+ \sa QObject::metaObject(), {Replica Initialization}
+*/
+const QMetaObject* QRemoteObjectDynamicReplica::metaObject() const
+{
+ auto impl = qSharedPointerCast<QRemoteObjectReplicaImplementation>(d_impl);
+ // Returning nullptr will likely result in a crash if this type is used before the
+ // definition is received. Note: QRemoteObjectDynamicReplica doesn't include the
+ // QObject macro, so it's metaobject would resolve to QRemoteObjectReplica::metaObject()
+ // if we weren't overriding it.
+ if (!impl->m_metaObject) {
+ qWarning() << "Dynamic metaobject is not assigned, returning generic Replica metaObject.";
+ qWarning() << "This may cause issues if used for more than checking the Replica state.";
+ return QRemoteObjectReplica::metaObject();
+ }
+
+ return impl->m_metaObject;
+}
+
+/*!
+ \internal
+ This function overrides the QObject::qt_metacast() virtual function to provide the same functionality for dynamic replicas.
+
+ \sa QObject::qt_metacast()
+*/
+void *QRemoteObjectDynamicReplica::qt_metacast(const char *name)
+{
+ if (!name)
+ return nullptr;
+
+ if (!strcmp(name, "QRemoteObjectDynamicReplica"))
+ return static_cast<void*>(const_cast<QRemoteObjectDynamicReplica*>(this));
+
+ // not entirely sure that one is needed... TODO: check
+ auto impl = qSharedPointerCast<QRemoteObjectReplicaImplementation>(d_impl);
+ if (QString::fromLatin1(name) == impl->m_objectName)
+ return static_cast<void*>(const_cast<QRemoteObjectDynamicReplica*>(this));
+
+ return QObject::qt_metacast(name);
+}
+
+/*!
+ \internal
+ This function overrides the QObject::qt_metacall() virtual function to provide the same functionality for dynamic replicas.
+
+ \sa QObject::qt_metacall()
+*/
+int QRemoteObjectDynamicReplica::qt_metacall(QMetaObject::Call call, int id, void **argv)
+{
+ static const bool debugArgs = qEnvironmentVariableIsSet("QT_REMOTEOBJECT_DEBUG_ARGUMENTS");
+
+ auto impl = qSharedPointerCast<QConnectedReplicaImplementation>(d_impl);
+
+ int saved_id = id;
+ id = QRemoteObjectReplica::qt_metacall(call, id, argv);
+ if (id < 0 || impl->m_metaObject == nullptr)
+ return id;
+
+ if (call == QMetaObject::ReadProperty || call == QMetaObject::WriteProperty) {
+ QMetaProperty mp = metaObject()->property(saved_id);
+
+ if (call == QMetaObject::WriteProperty) {
+ QVariantList args;
+ if (mp.userType() == QMetaType::QVariant)
+ args << *reinterpret_cast<QVariant*>(argv[0]);
+ else
+ args << QVariant(mp.metaType(), argv[0]);
+ QRemoteObjectReplica::send(QMetaObject::WriteProperty, saved_id, args);
+ } else {
+ if (mp.userType() == QMetaType::QVariant)
+ *reinterpret_cast<QVariant*>(argv[0]) = impl->m_propertyStorage[id];
+ else {
+ const QVariant value = propAsVariant(id);
+ mp.metaType().destruct(argv[0]);
+ mp.metaType().construct(argv[0], value.data());
+ }
+ }
+
+ id = -1;
+ } else if (call == QMetaObject::InvokeMetaMethod) {
+ if (id < impl->m_numSignals) {
+ qCDebug(QT_REMOTEOBJECT) << "DynamicReplica Activate" << impl->m_metaObject->method(saved_id).methodSignature();
+ // signal relay from Source world to Replica
+ QMetaObject::activate(this, impl->m_metaObject, id, argv);
+
+ } else {
+ // method relay from Replica to Source
+ const QMetaMethod mm = impl->m_metaObject->method(saved_id);
+ const int nParam = mm.parameterCount();
+ QVariantList args;
+ args.reserve(nParam);
+ for (int i = 0; i < nParam; ++i) {
+ const auto metaType = mm.parameterMetaType(i);
+ if (metaType.flags().testFlag(QMetaType::IsEnumeration)) {
+ auto transferType = QRemoteObjectPackets::transferTypeForEnum(metaType);
+ args.push_back(QVariant(transferType, argv[i + 1]));
+ } else
+ args.push_back(QVariant(metaType, argv[i + 1]));
+ }
+
+ if (debugArgs) {
+ qCDebug(QT_REMOTEOBJECT) << "method" << mm.methodSignature() << "invoked - args:" << args;
+ } else {
+ qCDebug(QT_REMOTEOBJECT) << "method" << mm.methodSignature() << "invoked";
+ }
+
+ if (mm.returnType() == QMetaType::Void)
+ QRemoteObjectReplica::send(QMetaObject::InvokeMetaMethod, saved_id, args);
+ else {
+ QRemoteObjectPendingCall call = QRemoteObjectReplica::sendWithReply(QMetaObject::InvokeMetaMethod, saved_id, args);
+ if (argv[0])
+ *(static_cast<QRemoteObjectPendingCall*>(argv[0])) = call;
+ }
+ }
+
+ id = -1;
+ }
+
+ return id;
+}
+
+QT_END_NAMESPACE
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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.LGPL3 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDYNAMICREMOTEOBJECT_H
+#define QDYNAMICREMOTEOBJECT_H
+
+#include <QtRemoteObjects/qremoteobjectreplica.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_REMOTEOBJECTS_EXPORT QRemoteObjectDynamicReplica : public QRemoteObjectReplica
+{
+public:
+ ~QRemoteObjectDynamicReplica() override;
+
+ const QMetaObject *metaObject() const override;
+ void *qt_metacast(const char *name) override;
+ int qt_metacall(QMetaObject::Call call, int id, void **argv) override;
+
+private:
+ explicit QRemoteObjectDynamicReplica();
+ explicit QRemoteObjectDynamicReplica(QRemoteObjectNode *node, const QString &name);
+ friend class QRemoteObjectNodePrivate;
+ friend class QRemoteObjectNode;
+};
+
+QT_END_NAMESPACE
+
+#endif
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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.LGPL3 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "private/qmetaobjectbuilder_p.h"
+
+#include "qremoteobjectcontainers_p.h"
+#include "qremoteobjectnode.h"
+#include "qremoteobjectnode_p.h"
+
+#include "qremoteobjectregistry.h"
+#include "qremoteobjectdynamicreplica.h"
+#include "qremoteobjectpacket_p.h"
+#include "qremoteobjectregistrysource_p.h"
+#include "qremoteobjectreplica_p.h"
+#include "qremoteobjectsource_p.h"
+#include "qremoteobjectabstractitemmodelreplica_p.h"
+#include "qremoteobjectabstractitemmodeladapter_p.h"
+#include <QtCore/qabstractitemmodel.h>
+#include <memory>
+#include <algorithm>
+
+QT_BEGIN_NAMESPACE
+
+using namespace QtRemoteObjects;
+using namespace QRemoteObjectStringLiterals;
+
+using GadgetType = QList<QVariant>;
+
+struct ManagedGadgetTypeEntry
+{
+ GadgetType gadgetType;
+ QMetaType gadgetMetaType;
+ QList<QMetaType> enumMetaTypes;
+ std::shared_ptr<QMetaObject> metaObject;
+
+ void unregisterMetaTypes()
+ {
+ QMetaType::unregisterMetaType(gadgetMetaType);
+ for (auto enumMetaType : enumMetaTypes)
+ QMetaType::unregisterMetaType(enumMetaType);
+ }
+};
+
+static QMutex s_managedTypesMutex;
+static QHash<int, ManagedGadgetTypeEntry> s_managedTypes;
+static QHash<int, QSet<QtROIoDeviceBase*>> s_trackedConnections;
+
+static void GadgetsStaticMetacallFunction(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
+{
+ if (_c == QMetaObject::ReadProperty) {
+ GadgetType *_t = reinterpret_cast<GadgetType *>(_o);
+ if (_id < _t->size()) {
+ const auto &prop = _t->at(_id);
+ prop.metaType().destruct(_a[0]);
+ prop.metaType().construct(_a[0], prop.constData());
+ }
+ } else if (_c == QMetaObject::WriteProperty) {
+ GadgetType *_t = reinterpret_cast<GadgetType *>(_o);
+ if (_id < _t->size()) {
+ auto & prop = (*_t)[_id];
+ prop = QVariant(prop.metaType(), _a[0]);
+ }
+ }
+}
+
+static void GadgetTypedDestructor(const QtPrivate::QMetaTypeInterface *, void *ptr)
+{
+ reinterpret_cast<GadgetType*>(ptr)->~GadgetType();
+}
+
+static void GadgetTypedConstructor(const QtPrivate::QMetaTypeInterface *interface, void *where)
+{
+ GadgetType *gadget = new(where) GadgetType;
+ QMutexLocker lock(&s_managedTypesMutex);
+ auto it = s_managedTypes.find(interface->typeId);
+ if (it == s_managedTypes.end()) {
+ delete gadget;
+ gadget = nullptr;
+ return;
+ }
+ *gadget = it->gadgetType;
+}
+
+static void GadgetTypedCopyConstructor(const QtPrivate::QMetaTypeInterface *, void *where, const void *copy)
+{
+ new(where) GadgetType(*reinterpret_cast<const GadgetType*>(copy));
+}
+
+static void GadgetTypedMoveConstructor(const QtPrivate::QMetaTypeInterface *, void *where, void *copy)
+{
+ new(where) GadgetType(std::move(*reinterpret_cast<GadgetType*>(copy)));
+}
+
+static bool GadgetEqualsFn(const QtPrivate::QMetaTypeInterface *, const void *a, const void *b)
+{
+ return *reinterpret_cast<const GadgetType*>(a) == *reinterpret_cast<const GadgetType*>(b);
+}
+
+static void GadgetDebugStreamFn(const QtPrivate::QMetaTypeInterface *, QDebug &dbg, const void *a)
+{
+ const GadgetType *gadgetProperties = reinterpret_cast<const GadgetType *>(a);
+ for (const auto &prop : *gadgetProperties)
+ dbg << prop;
+}
+
+static void GadgetDataStreamOutFn(const QtPrivate::QMetaTypeInterface *, QDataStream &ds, const void *a)
+{
+ const GadgetType *gadgetProperties = reinterpret_cast<const GadgetType *>(a);
+ for (const auto &prop : *gadgetProperties)
+ ds << prop;
+}
+
+static void GadgetDataStreamInFn(const QtPrivate::QMetaTypeInterface *, QDataStream &ds, void *a)
+{
+ GadgetType *gadgetProperties = reinterpret_cast<GadgetType *>(a);
+ for (auto &prop : *gadgetProperties)
+ ds >> prop;
+}
+
+// Like the Q_GADGET static methods above, we need constructor/destructor methods
+// in order to use dynamically defined enums with QVariant or as signal/slot
+// parameters (i.e., the queued connection mechanism, which QtRO leverages).
+//
+// We will need the enum methods to support different sizes when typed scope enum
+// support is added, so might as well use that now.
+template<typename T>
+static void EnumDestructor(const QtPrivate::QMetaTypeInterface *, void *ptr)
+{
+ static_cast<T*>(ptr)->~T();
+}
+
+template<typename T>
+static void EnumConstructor(const QtPrivate::QMetaTypeInterface *, void *where)
+{
+ new(where) T;
+}
+
+template<typename T>
+static void EnumCopyConstructor(const QtPrivate::QMetaTypeInterface *, void *where, const void *copy)
+{
+ new(where) T(*static_cast<const T*>(copy));
+}
+
+template<typename T>
+static void EnumMoveConstructor(const QtPrivate::QMetaTypeInterface *, void *where, void *copy)
+{
+ new(where) T(std::move(*static_cast<T*>(copy)));
+}
+
+// Not used, but keeping these in case we end up with a need for save/load.
+template<typename T>
+static void EnumSaveOperator(QDataStream & out, const void *data)
+{
+ const T value = *static_cast<const T *>(data);
+ out << value;
+}
+
+template<typename T>
+static void EnumLoadOperator(QDataStream &in, void *data)
+{
+ T value = *static_cast<T *>(data);
+ in >> value;
+}
+
+template<typename T>
+static bool EnumEqualsFn(const QtPrivate::QMetaTypeInterface *, const void *a, const void *b)
+{
+ return *static_cast<const T*>(a) == *static_cast<const T*>(b);
+}
+
+template<typename T>
+static bool EnumLessThanFn(const QtPrivate::QMetaTypeInterface *, const void *a, const void *b)
+{
+ return *static_cast<const T*>(a) < *static_cast<const T*>(b);
+}
+
+template<typename T>
+static void EnumDebugStreamFn(const QtPrivate::QMetaTypeInterface *, QDebug &dbg, const void *a)
+{
+ dbg << *static_cast<const T *>(a);
+}
+
+template<typename T>
+static void EnumDataStreamOutFn(const QtPrivate::QMetaTypeInterface *, QDataStream &ds, const void *a)
+{
+ ds << *static_cast<const T *>(a);
+}
+
+template<typename T>
+static void EnumDataStreamInFn(const QtPrivate::QMetaTypeInterface *, QDataStream &ds, void *a)
+{
+ ds >> *static_cast<T *>(a);
+}
+
+static QString name(const QMetaObject * const mobj)
+{
+ const int ind = mobj->indexOfClassInfo(QCLASSINFO_REMOTEOBJECT_TYPE);
+ return ind >= 0 ? QString::fromLatin1(mobj->classInfo(ind).value()) : QString();
+}
+
+QString QtRemoteObjects::getTypeNameAndMetaobjectFromClassInfo(const QMetaObject *& meta) {
+ QString typeName;
+ const int ind = meta->indexOfClassInfo(QCLASSINFO_REMOTEOBJECT_TYPE);
+ if (ind != -1) { //We have an object created from repc or at least with QCLASSINFO defined
+ typeName = QString::fromLatin1(meta->classInfo(ind).value());
+ while (true) {
+ Q_ASSERT(meta->superClass());//This recurses to QObject, which doesn't have QCLASSINFO_REMOTEOBJECT_TYPE
+ //At the point superclass doesn't have the same QCLASSINFO_REMOTEOBJECT_TYPE,
+ //we have the metaobject we should work from
+ if (ind != meta->superClass()->indexOfClassInfo(QCLASSINFO_REMOTEOBJECT_TYPE))
+ break;
+ meta = meta->superClass();
+ }
+ }
+ return typeName;
+}
+
+template <typename K, typename V, typename Query>
+bool map_contains(const QMap<K,V> &map, const Query &key, typename QMap<K,V>::const_iterator &result)
+{
+ const typename QMap<K,V>::const_iterator it = map.find(key);
+ if (it == map.end())
+ return false;
+ result = it;
+ return true;
+}
+
+/*!
+ \qmltype Node
+ \instantiates QRemoteObjectNode
+ \inqmlmodule QtRemoteObjects
+ \brief A node on a Qt Remote Objects network.
+
+ The Node type provides an entry point to a Qt Remote Objects network. A network
+ can be as simple as two nodes, or an arbitrarily complex set of processes and devices.
+
+ A Node does not have a url that other nodes can connect to, and thus is able to acquire
+ replicas only. It is not able to share source objects.
+
+*/
+
+QRemoteObjectNodePrivate::QRemoteObjectNodePrivate()
+ : QObjectPrivate()
+ , registry(nullptr)
+ , retryInterval(250)
+ , lastError(QRemoteObjectNode::NoError)
+ , persistedStore(nullptr)
+{ }
+
+QRemoteObjectNodePrivate::~QRemoteObjectNodePrivate()
+{
+}
+
+QRemoteObjectSourceLocations QRemoteObjectNodePrivate::remoteObjectAddresses() const
+{
+ if (registry)
+ return registry->sourceLocations();
+ return QRemoteObjectSourceLocations();
+}
+
+QRemoteObjectSourceLocations QRemoteObjectRegistryHostPrivate::remoteObjectAddresses() const
+{
+ if (registrySource)
+ return registrySource->sourceLocations();
+ return QRemoteObjectSourceLocations();
+}
+
+/*!
+ \reimp
+*/
+void QRemoteObjectNode::timerEvent(QTimerEvent*)
+{
+ Q_D(QRemoteObjectNode);
+
+ for (auto it = d->pendingReconnect.begin(), end = d->pendingReconnect.end(); it != end; /*erasing*/) {
+ const auto &conn = *it;
+ if (conn->isOpen()) {
+ it = d->pendingReconnect.erase(it);
+ } else {
+ conn->connectToServer();
+ ++it;
+ }
+ }
+
+ if (d->pendingReconnect.isEmpty())
+ d->reconnectTimer.stop();
+
+ qRODebug(this) << "timerEvent" << d->pendingReconnect.size();
+}
+
+/*!
+ \qmlproperty int Node::heartbeatInterval
+
+ Heartbeat interval in ms.
+
+ The heartbeat (only helpful for socket connections) will periodically send a
+ message to connected nodes to detect whether the connection was disrupted.
+ Qt Remote Objects will try to reconnect automatically if it detects a dropped
+ connection. This function can help with that detection since the client will
+ only detect that the server is unavailable when it tries to send data.
+
+ A value of \c 0 (the default) will disable the heartbeat.
+*/
+
+
+/*!
+ \property QRemoteObjectNode::heartbeatInterval
+ \brief Heartbeat interval in ms.
+
+ The heartbeat (only helpful for socket connections) will periodically send a
+ message to connected nodes to detect whether the connection was disrupted.
+ Qt Remote Objects will try to reconnect automatically if it detects a dropped
+ connection. This function can help with that detection since the client will
+ only detect that the server is unavailable when it tries to send data.
+
+ A value of \c 0 (the default) will disable the heartbeat.
+*/
+int QRemoteObjectNode::heartbeatInterval() const
+{
+ Q_D(const QRemoteObjectNode);
+ return d->m_heartbeatInterval;
+}
+
+void QRemoteObjectNode::setHeartbeatInterval(int interval)
+{
+ Q_D(QRemoteObjectNode);
+ if (d->m_heartbeatInterval == interval)
+ return;
+ d->m_heartbeatInterval = interval;
+ emit heartbeatIntervalChanged(interval);
+}
+
+/*!
+ \since 5.12
+ \typedef QRemoteObjectNode::RemoteObjectSchemaHandler
+
+ Typedef for a std::function method that can take a QUrl input and is
+ responsible for creating the communications channel between this node and
+ the node hosting the desired \l Source. As some types of QIODevices (e.g.,
+ QSslSocket) require additional steps before the device is ready for use,
+ the method is responsible for calling \l addClientSideConnection once the
+ connection is fully established.
+*/
+
+/*!
+ \since 5.12
+ \brief Provide a custom method to handle externally provided schemas
+
+ This method is tied to the \l Registry and \l {External Schemas}. By
+ registering a std::function handler for an external schema, the registered
+ method will be called when the registry is notified of a \l Source you've
+ acquired being available. Without this registration, QtRO would only be
+ able to handle the "built-in" schemas.
+
+ The provided method, \a handler, will be called when the registry sees a \l
+ Source object on a new (not yet connected) Node with a {QUrl::schema()} of
+ \a schema. The \a handler, of type \l
+ QRemoteObjectNode::RemoteObjectSchemaHandler will get the \l QUrl of the
+ Node providing the \l Source as an input parameter, and is responsible for
+ establishing the communications channel (a \l QIODevice of some sort) and
+ calling \l addClientSideConnection with it.
+
+ \sa RemoteObjectSchemaHandler
+*/
+void QRemoteObjectNode::registerExternalSchema(const QString &schema, QRemoteObjectNode::RemoteObjectSchemaHandler handler)
+{
+ Q_D(QRemoteObjectNode);
+ d->schemaHandlers.insert(schema, handler);
+}
+
+/*!
+ \since 5.11
+ \brief Forward Remote Objects from another network
+
+ The proxy functionality is useful when you want to share \l Source objects
+ over multiple networks. For instance, if you have an embedded target using
+ target-only connections (like local) and you want to make some of those
+ same objects available externally.
+
+ As a concrete example, say you have a set of processes talking to each
+ other on your target hardware using a registry, with the \l Registry at
+ "local:registry" and separate processes using a node at "local:MyHost" that
+ holds \l Source objects. If you wanted to access these objects, but over
+ tcp, you could create a new proxyNode like so:
+
+\code
+ // myInternalHost is a node only visible on the device...
+ QRemoteObjectHost myInternalHost("local:MyHost");
+ myInternalHost.enableRemoting<SomeObject>(&someObject);
+
+ // Regular host node, listening on port 12123, so visible to other
+ // devices
+ QRemoteObjectHost proxyNode("tcp://localhost:12123");
+
+ // Enable proxying objects from nodes on the local machine's internal
+ // QtRO bus
+ proxyNode.proxy("local:registry");
+\endcode
+
+ And from another device you create another node:
+
+\code
+ // NB: localhost resolves to a different ip address than proxyNode
+ QRemoteObjectHost nodeOnRemoteDevice("tcp://localhost:23234");
+
+ // Connect to the target's proxyNode directly, or use a tcp registry...
+ nodeOnRemoteDevice.connectToNode("tcp://<target device>:12123");
+
+ // Because of the proxy, we can get the object over tcp/ip port 12123,
+ // even though we can't connect directly to "local:MyHost"
+ SomeObject *so = nodeOnRemoteDevice.acquire<SomeObject>();
+\endcode
+
+ This would (internally) create a node in proxyNode, which (again
+ internally/automatically) connects to the provided registry (given by the
+ \a registryUrl parameter, "local:registry" in this example). Whenever
+ local:registry emits the \l remoteObjectAdded signal, the
+ \c QRemoteObjectSourceLocation is passed to the \a filter given to the proxy
+ call. If this method returns true (the default filter simply returns true
+ without any filtering), the object is acquired() from the internal node and
+ enableRemoting() (once the replica is initialized) is called on proxyNode.
+
+ If a \a hostUrl is provided (which is required to enable reverseProxy, but
+ not needed otherwise), the internal node will be a \l QRemoteObjectHost node
+ configured with the provided address. If no \a hostUrl is provided, the
+ internal node will be a QRemoteObjectNode (not HostNode).
+
+ Returns \c true if the object is acquired from the internal node.
+
+ \sa reverseProxy()
+*/
+bool QRemoteObjectHostBase::proxy(const QUrl ®istryUrl, const QUrl &hostUrl, RemoteObjectNameFilter filter)
+{
+ Q_D(QRemoteObjectHostBase);
+ if (!registryUrl.isValid() || !QtROClientFactory::instance()->isValid(registryUrl)) {
+ qROWarning(this) << "Can't proxy to registryUrl (invalid url or schema)" << registryUrl;
+ return false;
+ }
+
+ if (!hostUrl.isEmpty() && !QtROClientFactory::instance()->isValid(hostUrl)) {
+ qROWarning(this) << "Can't proxy using hostUrl (invalid schema)" << hostUrl;
+ return false;
+ }
+
+ if (d->proxyInfo) {
+ qROWarning(this) << "Proxying from multiple objects is currently not supported.";
+ return false;
+ }
+
+ QRemoteObjectNode *node;
+ if (hostUrl.isEmpty()) {
+ node = new QRemoteObjectNode(registryUrl);
+ } else {
+ node = new QRemoteObjectHost(hostUrl, registryUrl);
+ }
+ d->proxyInfo = new ProxyInfo(node, this, filter);
+ return true;
+}
+
+/*!
+ \since 5.11
+ \brief Forwards remote objects to another network.
+
+ The reverseProxy() function allows the \l proxy() functionality to be
+ extended, in effect mirroring the proxy functionality in the "reverse"
+ direction. These are distinct, because node communication is not symmetric,
+ one side calls enableRemoting() with a \l Source object, the other side
+ calls acquire() to get a \l Replica. Using \l proxy() allows you to
+ "observe" objects on a target device remotely via acquire, but it does not
+ allow off-target \l Source objects to be acquired from the device's local:*
+ network. That is where \l reverseProxy() comes in. If a proxyNode is
+ created like so:
+
+\code
+ // myInternalHost is a node only visible on the device...
+ QRemoteObjectHost myInternalHost("local:MyHost");
+
+ // RegistryHost node, listening on port 12123, so visible to other
+ // devices. The node must be a RegistryHost, so the Sources on
+ // the "outside" network can be forwarded to the inner network.
+ QRemoteObjectRegistryHost proxyNode("tcp://localhost:12123");
+
+ // Enable proxying objects from nodes on the local machine's internal
+ // QtRO bus. Note the hostUrl parameter is now needed.
+ proxyNode.proxy("local:registry", "local:fromProxy");
+ proxyNode.reverseProxy();
+\endcode
+
+ And from another device you create another node:
+
+\code
+ // NB: localhost resolves to a different ip address than proxyNode
+ QRemoteObjectHost nodeOnRemoteDevice("tcp://localhost:23234");
+
+ // Connect to the target's proxyNode directly, or use a tcp registry...
+ nodeOnRemoteDevice.connectToNode("tcp://<target device>:12123");
+
+ // Because of the reverseProxy, we can expose objects on this device
+ // and they will make their way to proxyNode...
+ nodeOnRemoteDevice.enableRemoting<OtherObject>(&otherObject);
+\endcode
+
+\code
+ // Acquire() can now see the objects on other devices through proxyNode,
+ // due to the reverseProxy call.
+ OtherObject *oo = myInternalHost.acquire<OtherObject>();
+\endcode
+
+ While the \l proxy() functionality allows \l Source objects on another
+ network to be acquired(), reverseProxy() allows \l Source objects to be
+ "pushed" to an otherwise inaccessible network.
+
+ \note proxy() needs to be called before \l reverseProxy(), and a
+ hostUrl needs to be provided to \l proxy for \l reverseProxy() to work. The
+ \l reverseProxy() method allows a separate \a filter to be applied. This
+ reverseProxy specific filter will receive notifications of new \l Source
+ objects on \c proxyNode and acquire them on the internal node if they pass the
+ \a filter.
+
+ Returns \c true on success, \c false otherwise.
+
+ \note Currently the reverse proxy functionality is supported only for
+ QRemoteObjectRegistryHost. Calling this method on a QRemoteObjectHost node
+ will always return \c false.
+
+ \sa proxy()
+*/
+bool QRemoteObjectHostBase::reverseProxy(QRemoteObjectHostBase::RemoteObjectNameFilter filter)
+{
+ Q_D(QRemoteObjectHostBase);
+
+ if (!d->proxyInfo) {
+ qROWarning(this) << "proxy() needs to be called before setting up reverse proxy.";
+ return false;
+ }
+
+ QRemoteObjectHost *host = qobject_cast<QRemoteObjectHost *>(d->proxyInfo->proxyNode);
+ if (!host) {
+ qROWarning(this) << "proxy() needs called with host-url to enable reverse proxy.";
+ return false;
+ }
+
+ return d->proxyInfo->setReverseProxy(filter);
+}
+
+/*!
+ \internal The replica needs to have a default constructor to be able
+ to create a replica from QML. In order for it to be properly
+ constructed, there needs to be a way to associate the replica with a
+ node and start the replica initialization. Thus we need a public
+ method on node to facilitate that. That's initializeReplica.
+*/
+void QRemoteObjectNode::initializeReplica(QRemoteObjectReplica *instance, const QString &name)
+{
+ Q_D(QRemoteObjectNode);
+ if (instance->inherits("QRemoteObjectDynamicReplica")) {
+ d->setReplicaImplementation(nullptr, instance, name);
+ } else {
+ const QMetaObject *meta = instance->metaObject();
+ // This is a templated acquire, so we tell the Source we don't need
+ // them to send the class definition. Thus we need to store the
+ // metaObject for this class - if this is a nested class, the QObject
+ // could be a nullptr or updated from the source,
+ d->dynamicTypeManager.addFromMetaObject(meta);
+ d->setReplicaImplementation(meta, instance, name.isEmpty() ? ::name(meta) : name);
+ }
+}
+
+void QRemoteObjectNodePrivate::setLastError(QRemoteObjectNode::ErrorCode errorCode)
+{
+ Q_Q(QRemoteObjectNode);
+ lastError = errorCode;
+ emit q->error(lastError);
+}
+
+void QRemoteObjectNodePrivate::setReplicaImplementation(const QMetaObject *meta, QRemoteObjectReplica *instance, const QString &name)
+{
+ qROPrivDebug() << "Starting setReplicaImplementation for" << name;
+ openConnectionIfNeeded(name);
+ QMutexLocker locker(&mutex);
+ if (hasInstance(name)) {
+ qCDebug(QT_REMOTEOBJECT)<<"setReplicaImplementation - using existing instance";
+ QSharedPointer<QRemoteObjectReplicaImplementation> rep = qSharedPointerCast<QRemoteObjectReplicaImplementation>(replicas.value(name).toStrongRef());
+ Q_ASSERT(rep);
+ instance->d_impl = rep;
+ rep->configurePrivate(instance);
+ } else {
+ instance->d_impl.reset(handleNewAcquire(meta, instance, name));
+ instance->initialize();
+ replicas.insert(name, instance->d_impl.toWeakRef());
+ qROPrivDebug() << "setReplicaImplementation - Created new instance" << name<<remoteObjectAddresses();
+ }
+}
+
+/*!
+ Returns a pointer to the Node's \l {QRemoteObjectRegistry}, if the Node
+ is using the Registry feature; otherwise it returns \nullptr.
+*/
+const QRemoteObjectRegistry *QRemoteObjectNode::registry() const
+{
+ Q_D(const QRemoteObjectNode);
+ return d->registry;
+}
+
+/*!
+ \class QRemoteObjectAbstractPersistedStore
+ \inmodule QtRemoteObjects
+ \brief A class which provides the methods for setting PROP values of a
+ replica to value they had the last time the replica was used.
+
+ This can be used to provide a "reasonable" value to be displayed until the
+ connection to the source is established and current values are available.
+
+ This class must be overridden to provide an implementation for saving (\l
+ QRemoteObjectAbstractPersistedStore::saveProperties) and restoring (\l
+ QRemoteObjectAbstractPersistedStore::restoreProperties) PROP values. The derived
+ type can then be set for a node, and any replica acquired from that node
+ will then automatically store PERSISTED properties when the replica
+ destructor is called, and retrieve the values when the replica is
+ instantiated.
+*/
+
+/*!
+ Constructs a QRemoteObjectAbstractPersistedStore with the given \a parent.
+ The default value of \a parent is \nullptr.
+*/
+QRemoteObjectAbstractPersistedStore::QRemoteObjectAbstractPersistedStore(QObject *parent)
+ : QObject(parent)
+{
+}
+
+QRemoteObjectAbstractPersistedStore::~QRemoteObjectAbstractPersistedStore()
+{
+}
+
+/*!
+ \fn virtual void QRemoteObjectAbstractPersistedStore::saveProperties(const QString &repName, const QByteArray &repSig, const QVariantList &values)
+
+ This method will be provided the replica class's \a repName, \a repSig and the list of
+ \a values that PERSISTED properties have when the replica destructor was
+ called. It is the responsibility of the inheriting class to store the
+ information in a manner consistent for \l
+ QRemoteObjectAbstractPersistedStore::restoreProperties to retrieve.
+
+ \sa QRemoteObjectAbstractPersistedStore::restoreProperties
+*/
+
+/*!
+ \fn virtual QVariantList QRemoteObjectAbstractPersistedStore::restoreProperties(const QString &repName, const QByteArray &repSig)
+
+ This method will be provided the replica class's \a repName and \a repSig when the
+ replica is being initialized. It is the responsibility of the inheriting
+ class to get the last values persisted by \l
+ QRemoteObjectAbstractPersistedStore::saveProperties and return them. An empty
+ QVariantList should be returned if no values are available.
+
+ \sa QRemoteObjectAbstractPersistedStore::saveProperties
+*/
+
+
+QRemoteObjectAbstractPersistedStore *QRemoteObjectNode::persistedStore() const
+{
+ Q_D(const QRemoteObjectNode);
+ return d->persistedStore;
+}
+
+/*!
+ \qmlproperty QRemoteObjectAbstractPersistedStore Node::persistedStore
+
+ Allows setting a \l QRemoteObjectAbstractPersistedStore instance for the node.
+
+ Allows replica \l PROP members with the PERSISTED trait to save their current value when the
+ replica is deleted and restore a stored value the next time the replica is started.
+
+ Requires a \l QRemoteObjectAbstractPersistedStore class implementation to control where and how
+ persistence is handled. A default QSettings-based implementation is provided by SettingsStore.
+*/
+
+/*!
+ \since 5.11
+ \property QRemoteObjectNode::persistedStore
+ \brief Allows setting a \l QRemoteObjectAbstractPersistedStore instance for the node.
+
+ Allows replica \l PROP members with the PERSISTED trait to save their current value when the
+ replica is deleted and restore a stored value the next time the replica is started.
+
+ Requires a \l QRemoteObjectAbstractPersistedStore class implementation to control where and how
+ persistence is handled.
+*/
+void QRemoteObjectNode::setPersistedStore(QRemoteObjectAbstractPersistedStore *persistedStore)
+{
+ Q_D(QRemoteObjectNode);
+ d->persistedStore = persistedStore;
+}
+
+QRemoteObjectAbstractPersistedStore::QRemoteObjectAbstractPersistedStore(QRemoteObjectAbstractPersistedStorePrivate &dptr, QObject *parent)
+ : QObject(dptr, parent)
+{
+}
+
+QRemoteObjectAbstractPersistedStorePrivate::QRemoteObjectAbstractPersistedStorePrivate()
+{
+}
+
+QRemoteObjectAbstractPersistedStorePrivate::~QRemoteObjectAbstractPersistedStorePrivate()
+{
+}
+
+QRemoteObjectMetaObjectManager::~QRemoteObjectMetaObjectManager()
+{
+ for (QMetaObject *mo : dynamicTypes) {
+ for (auto metaType : enumTypes[mo])
+ QMetaType::unregisterMetaType(metaType);
+ enumTypes.remove(mo);
+ free(mo); //QMetaObjectBuilder uses malloc, not new
+ }
+}
+
+const QMetaObject *QRemoteObjectMetaObjectManager::metaObjectForType(const QString &type)
+{
+ qCDebug(QT_REMOTEOBJECT) << "metaObjectForType: looking for" << type << "static keys:" << staticTypes.keys() << "dynamic keys:" << dynamicTypes.keys();
+ Q_ASSERT(staticTypes.contains(type) || dynamicTypes.contains(type));
+ auto it = staticTypes.constFind(type);
+ if (it != staticTypes.constEnd())
+ return it.value();
+ return dynamicTypes.value(type);
+}
+
+static void trackConnection(int typeId, QtROIoDeviceBase *connection)
+{
+ QMutexLocker lock(&s_managedTypesMutex);
+ if (s_trackedConnections[typeId].contains(connection))
+ return;
+ s_trackedConnections[typeId].insert(connection);
+ auto unregisterIfNotUsed = [typeId, connection]{
+ QMutexLocker lock(&s_managedTypesMutex);
+ Q_ASSERT(s_trackedConnections.contains(typeId));
+ Q_ASSERT(s_trackedConnections[typeId].contains(connection));
+ s_trackedConnections[typeId].remove(connection);
+ if (s_trackedConnections[typeId].isEmpty()) {
+ s_trackedConnections.remove(typeId);
+ s_managedTypes[typeId].unregisterMetaTypes();
+ s_managedTypes.remove(typeId); // Destroys the meta types
+ }
+ };
+
+ // Unregister the type only when the connection is destroyed
+ // Do not unregister types when the connections is discconected, because
+ // if it gets reconnected it will not register the types again
+ QObject::connect(connection, &QtROIoDeviceBase::destroyed, unregisterIfNotUsed);
+}
+
+struct EnumPair {
+ QByteArray name;
+ int value;
+};
+
+struct EnumData {
+ QByteArray name;
+ bool isFlag, isScoped;
+ quint32 keyCount, size;
+ QList<EnumPair> values;
+};
+
+struct GadgetProperty {
+ QByteArray name;
+ QByteArray type;
+};
+
+struct GadgetData {
+ QList<GadgetProperty> properties;
+ QList<EnumData> enums;
+};
+
+static const char *strDup(const QByteArray &s)
+{
+ auto result = new char[uint(s.size()) + 1];
+ auto end = std::copy(s.cbegin(), s.cend(), result);
+ *end = 0;
+ return result;
+}
+
+using Gadgets = QHash<QByteArray, GadgetData>;
+struct TypeInfo : public QtPrivate::QMetaTypeInterface
+{
+ const QMetaObject *metaObject;
+};
+static const QMetaObject *metaObjectFn(const QtPrivate::QMetaTypeInterface *self)
+{
+ return static_cast<const TypeInfo *>(self)->metaObject;
+}
+
+template <class Int>
+static TypeInfo *enumMetaType(const QByteArray &name, uint size, const QMetaObject *meta=nullptr)
+{
+ static const auto flags = QMetaType::IsEnumeration | QMetaType::NeedsConstruction
+ | QMetaType::NeedsDestruction;
+
+ auto typeInfo = new TypeInfo {
+ {
+ 0, alignof(Int), size, uint(flags), 0, metaObjectFn, strDup(name),
+ EnumConstructor<Int>,
+ EnumCopyConstructor<Int>,
+ EnumMoveConstructor<Int>,
+ EnumDestructor<Int>,
+ EnumEqualsFn<Int>,
+ EnumLessThanFn<Int>,
+ EnumDebugStreamFn<Int>,
+ EnumDataStreamOutFn<Int>,
+ EnumDataStreamInFn<Int>,
+ nullptr
+ }, meta
+ };
+ return typeInfo;
+}
+
+static TypeInfo *registerEnum(const QByteArray &name, uint size=4u)
+{
+ TypeInfo *result = nullptr;
+ if (QMetaType::fromName(name).isValid())
+ return result;
+ switch (size) {
+ case 1:
+ result = enumMetaType<qint8>(name, size);
+ break;
+ case 2:
+ result = enumMetaType<qint16>(name, size);
+ break;
+ case 4:
+ result = enumMetaType<qint32>(name, size);
+ break;
+ // Qt currently only supports enum values of 4 or less bytes (QMetaEnum value(index) returns int)
+// case 8: id = QMetaType::registerType(name.constData(), nullptr, nullptr, &EnumDestructor<qint64>,
+// &EnumConstructor<qint64>, size, flags, meta);
+// break;
+ default:
+ qWarning() << "Invalid enum detected" << name << "with size" << size << ". Defaulting to register as int.";
+ size = 4;
+ result = enumMetaType<qint32>(name, size);
+ break;
+ }
+#ifdef QTRO_VERBOSE_PROTOCOL
+ qDebug() << "Registering new enum" << name << "size:" << size;
+#endif
+ return result;
+}
+
+static int registerGadgets(QtROIoDeviceBase *connection, Gadgets &gadgets, QByteArray typeName)
+{
+ const auto &gadget = gadgets.take(typeName);
+ // TODO Look at having registerGadgets return QMetaType index of the id of the type
+ int typeId = QMetaType::fromName(typeName).id();
+ if (typeId != QMetaType::UnknownType) {
+ trackConnection(typeId, connection);
+ return typeId;
+ }
+
+ ManagedGadgetTypeEntry entry;
+
+ QMetaObjectBuilder gadgetBuilder;
+ gadgetBuilder.setClassName(typeName);
+ gadgetBuilder.setFlags(DynamicMetaObject | PropertyAccessInStaticMetaCall);
+ for (const auto &prop : gadget.properties) {
+ int propertyType = QMetaType::fromName(prop.type).id();
+ if (!propertyType && gadgets.contains(prop.type))
+ propertyType = registerGadgets(connection, gadgets, prop.type);
+ entry.gadgetType.push_back(QVariant(QMetaType(propertyType)));
+ auto dynamicProperty = gadgetBuilder.addProperty(prop.name, prop.type);
+ dynamicProperty.setWritable(true);
+ dynamicProperty.setReadable(true);
+ }
+ QList<TypeInfo *> enumsToBeAssignedMetaObject;
+ enumsToBeAssignedMetaObject.reserve(gadget.enums.length());
+ for (const auto &enumData: gadget.enums) {
+ auto enumBuilder = gadgetBuilder.addEnumerator(enumData.name);
+ enumBuilder.setIsFlag(enumData.isFlag);
+ enumBuilder.setIsScoped(enumData.isScoped);
+
+ for (quint32 k = 0; k < enumData.keyCount; ++k) {
+ const auto pair = enumData.values.at(k);
+ enumBuilder.addKey(pair.name, pair.value);
+ }
+ const QByteArray registeredName = QByteArray(typeName).append("::").append(enumData.name);
+ auto typeInfo = registerEnum(registeredName, enumData.size);
+ if (typeInfo)
+ enumsToBeAssignedMetaObject.append(typeInfo);
+ }
+ auto meta = gadgetBuilder.toMetaObject();
+ entry.metaObject = std::shared_ptr<QMetaObject>{meta, [](QMetaObject *ptr){ ::free(ptr); }};
+ for (auto typeInfo : enumsToBeAssignedMetaObject) {
+ typeInfo->metaObject = meta;
+ auto metaType = QMetaType(typeInfo);
+ entry.enumMetaTypes.append(metaType);
+ auto id = metaType.id();
+ qCDebug(QT_REMOTEOBJECT) << "Registering new gadget enum with id" << id << typeInfo->name << "size:" << typeInfo->size;
+ }
+
+ QMetaType::TypeFlags flags = QMetaType::IsGadget;
+ if (meta->propertyCount()) {
+ meta->d.static_metacall = &GadgetsStaticMetacallFunction;
+ meta->d.superdata = nullptr;
+ flags |= QMetaType::NeedsConstruction | QMetaType::NeedsDestruction;
+ auto typeInfo = new TypeInfo {
+ {
+ 0, alignof(GadgetType), sizeof(GadgetType), uint(flags), 0, metaObjectFn,
+ strDup(typeName),
+ GadgetTypedConstructor,
+ GadgetTypedCopyConstructor,
+ GadgetTypedMoveConstructor,
+ GadgetTypedDestructor,
+ GadgetEqualsFn,
+ nullptr, /* LessThanFn */
+ GadgetDebugStreamFn,
+ GadgetDataStreamOutFn,
+ GadgetDataStreamInFn,
+ nullptr /* LegacyRegisterOp */
+ },
+ meta
+ };
+ entry.gadgetMetaType = QMetaType(typeInfo);
+ } else {
+ auto typeInfo = new TypeInfo {
+ {
+ 0, alignof(GadgetType), sizeof(GadgetType), uint(flags), 0, metaObjectFn,
+ strDup(typeName),
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr
+ },
+ meta
+ };
+ entry.gadgetMetaType = QMetaType(typeInfo);
+ }
+ const int gadgetTypeId = entry.gadgetMetaType.id();
+ trackConnection(gadgetTypeId, connection);
+ QMutexLocker lock(&s_managedTypesMutex);
+ s_managedTypes.insert(gadgetTypeId, entry);
+ return gadgetTypeId;
+}
+
+static void registerAllGadgets(QtROIoDeviceBase *connection, Gadgets &gadgets)
+{
+ while (!gadgets.isEmpty())
+ registerGadgets(connection, gadgets, gadgets.constBegin().key());
+}
+
+static void deserializeEnum(QDataStream &ds, EnumData &enumData)
+{
+ ds >> enumData.name;
+ ds >> enumData.isFlag;
+ ds >> enumData.isScoped;
+ ds >> enumData.size;
+ ds >> enumData.keyCount;
+ for (quint32 i = 0; i < enumData.keyCount; i++) {
+ EnumPair pair;
+ ds >> pair.name;
+ ds >> pair.value;
+ enumData.values.push_back(pair);
+ }
+}
+
+static void parseGadgets(QtROIoDeviceBase *connection, QDataStream &in)
+{
+ quint32 qtEnums, numGadgets;
+ in >> qtEnums; // Qt enums - just need registration
+ for (quint32 i = 0; i < qtEnums; ++i) {
+ QByteArray enumName;
+ in >> enumName;
+ QMetaType type(enumMetaType<qint32>(enumName, 4, &Qt::staticMetaObject));
+ type.id();
+ }
+ in >> numGadgets;
+ if (numGadgets == 0)
+ return;
+ Gadgets gadgets;
+ for (quint32 i = 0; i < numGadgets; ++i) {
+ QByteArray type;
+ in >> type;
+ quint32 numProperties, numEnums;
+ in >> numProperties;
+ auto &properties = gadgets[type].properties;
+ for (quint32 p = 0; p < numProperties; ++p) {
+ GadgetProperty prop;
+ in >> prop.name;
+ in >> prop.type;
+ properties.push_back(prop);
+ }
+ in >> numEnums;
+ auto &enums = gadgets[type].enums;
+ for (quint32 e = 0; e < numEnums; ++e) {
+ EnumData enumData;
+ deserializeEnum(in, enumData);
+ enums.push_back(enumData);
+ }
+ }
+ registerAllGadgets(connection, gadgets);
+}
+
+QMetaObject *QRemoteObjectMetaObjectManager::addDynamicType(QtROIoDeviceBase *connection, QDataStream &in)
+{
+ QMetaObjectBuilder builder;
+ builder.setSuperClass(&QRemoteObjectReplica::staticMetaObject);
+ builder.setFlags(DynamicMetaObject);
+
+ QString typeString;
+ QByteArray type;
+ quint32 numEnums = 0;
+ quint32 numSignals = 0;
+ quint32 numMethods = 0;
+ quint32 numProperties = 0;
+ QHash<QByteArray, QByteArray> classEnums;
+
+ in >> typeString;
+ type = typeString.toLatin1();
+ builder.addClassInfo(QCLASSINFO_REMOTEOBJECT_TYPE, type);
+ builder.setClassName(type);
+
+ in >> numEnums;
+ QList<quint32> enumSizes(numEnums);
+ enumsToBeAssignedMetaObject.reserve(numEnums);
+ for (quint32 i = 0; i < numEnums; ++i) {
+ EnumData enumData;
+ deserializeEnum(in, enumData);
+ auto enumBuilder = builder.addEnumerator(enumData.name);
+ enumBuilder.setIsFlag(enumData.isFlag);
+ enumBuilder.setIsScoped(enumData.isScoped);
+ enumSizes[i] = enumData.size;
+
+ for (quint32 k = 0; k < enumData.keyCount; ++k) {
+ const auto pair = enumData.values.at(k);
+ enumBuilder.addKey(pair.name, pair.value);
+ }
+ const QByteArray registeredName = QByteArray(type).append("::").append(enumData.name);
+ classEnums[enumData.name] = registeredName;
+ auto typeInfo = registerEnum(registeredName, enumData.size);
+ if (typeInfo) {
+ enumsToBeAssignedMetaObject[typeInfo] = QMetaType(typeInfo);
+ int id = enumsToBeAssignedMetaObject[typeInfo].id();
+ qCDebug(QT_REMOTEOBJECT) << "Registering new class enum with id" << id << typeInfo->name << "size:" << typeInfo->size;
+ }
+ }
+ parseGadgets(connection, in);
+
+ int curIndex = 0;
+
+ in >> numSignals;
+ for (quint32 i = 0; i < numSignals; ++i) {
+ QByteArray signature;
+ QByteArrayList paramNames;
+ in >> signature;
+ in >> paramNames;
+ ++curIndex;
+ auto mmb = builder.addSignal(signature);
+ mmb.setParameterNames(paramNames);
+ }
+
+ in >> numMethods;
+ for (quint32 i = 0; i < numMethods; ++i) {
+ QByteArray signature, returnType;
+ QByteArrayList paramNames;
+ in >> signature;
+ in >> returnType;
+ in >> paramNames;
+ ++curIndex;
+ const bool isVoid = returnType.isEmpty() || returnType == QByteArrayLiteral("void");
+ QMetaMethodBuilder mmb;
+ if (isVoid)
+ mmb = builder.addMethod(signature);
+ else
+ mmb = builder.addMethod(signature, QByteArrayLiteral("QRemoteObjectPendingCall"));
+ mmb.setParameterNames(paramNames);
+ }
+
+ in >> numProperties;
+
+ for (quint32 i = 0; i < numProperties; ++i) {
+ QByteArray name;
+ QByteArray typeName;
+ QByteArray signalName;
+ in >> name;
+ in >> typeName;
+ in >> signalName;
+
+ auto choppedName = QByteArray::fromRawData(typeName.constData(),
+ typeName.size() - 1); // Remove trailing null
+ // The typeName for class enums is qualified with the class name.
+ // Need to remove the class name before checking if it's a class enum.
+ if (auto idx = choppedName.indexOf("::"); idx >= 0) {
+ choppedName = choppedName.sliced(idx + 2);
+ if (classEnums.contains(choppedName))
+ typeName = classEnums[choppedName] + '\0'; // Update to the enum's registered name
+ }
+
+ if (signalName.isEmpty())
+ builder.addProperty(name, typeName);
+ else
+ builder.addProperty(name, typeName, builder.indexOfSignal(signalName));
+ }
+
+ auto meta = builder.toMetaObject();
+ for (auto typeInfo : enumsToBeAssignedMetaObject.keys()) {
+ auto typeInfoWithMetaObject = static_cast<TypeInfo *>(typeInfo);
+ typeInfoWithMetaObject->metaObject = meta;
+ enumTypes[meta].append(enumsToBeAssignedMetaObject.take(typeInfo));
+ }
+ dynamicTypes.insert(typeString, meta);
+ return meta;
+}
+
+void QRemoteObjectMetaObjectManager::addFromMetaObject(const QMetaObject *metaObject)
+{
+ QString className = QLatin1String(metaObject->className());
+ if (!className.endsWith(QLatin1String("Replica")))
+ return;
+ if (className == QLatin1String("QRemoteObjectDynamicReplica") || staticTypes.contains(className))
+ return;
+ className.chop(7); //Remove 'Replica' from name
+ staticTypes.insert(className, metaObject);
+}
+
+void QRemoteObjectNodePrivate::connectReplica(QObject *object, QRemoteObjectReplica *instance)
+{
+ int nConnections = 0;
+ const QMetaObject *us = instance->metaObject();
+ const QMetaObject *them = object->metaObject();
+
+ static const int memberOffset = QRemoteObjectReplica::staticMetaObject.methodCount();
+ for (int idx = memberOffset; idx < us->methodCount(); ++idx) {
+ const QMetaMethod mm = us->method(idx);
+
+ qROPrivDebug() << idx << mm.name();
+ if (mm.methodType() != QMetaMethod::Signal)
+ continue;
+
+ // try to connect to a signal on the parent that has the same method signature
+ QByteArray sig = QMetaObject::normalizedSignature(mm.methodSignature().constData());
+ qROPrivDebug() << sig;
+ if (them->indexOfSignal(sig.constData()) == -1)
+ continue;
+
+ sig.prepend(QSIGNAL_CODE + '0');
+ const char * const csig = sig.constData();
+ const bool res = QObject::connect(object, csig, instance, csig);
+ Q_UNUSED(res)
+ ++nConnections;
+
+ qROPrivDebug() << sig << res;
+ }
+
+ qROPrivDebug() << "# connections =" << nConnections;
+}
+
+void QRemoteObjectNodePrivate::openConnectionIfNeeded(const QString &name)
+{
+ qROPrivDebug() << Q_FUNC_INFO << name << this;
+ if (!remoteObjectAddresses().contains(name)) {
+ qROPrivDebug() << name << "not available - available addresses:" << remoteObjectAddresses();
+ return;
+ }
+
+ if (!initConnection(remoteObjectAddresses().value(name).hostUrl))
+ qROPrivWarning() << "failed to open connection to" << name;
+}
+
+bool QRemoteObjectNodePrivate::initConnection(const QUrl &address)
+{
+ Q_Q(QRemoteObjectNode);
+ if (requestedUrls.contains(address)) {
+ qROPrivDebug() << "Connection already requested for " << address.toString();
+ return true;
+ }
+
+ requestedUrls.insert(address);
+
+ if (schemaHandlers.contains(address.scheme())) {
+ schemaHandlers[address.scheme()](address);
+ return true;
+ }
+
+ QtROClientIoDevice *connection = QtROClientFactory::instance()->create(address, q);
+ if (!connection) {
+ qROPrivWarning() << "Could not create QtROClientIoDevice for client. Invalid url/scheme provided?" << address;
+ return false;
+ }
+ qROPrivDebug() << "Opening connection to" << address.toString();
+ qROPrivDebug() << "Replica Connection isValid" << connection->isOpen();
+ QObject::connect(connection, &QtROClientIoDevice::shouldReconnect, q, [this, connection]() {
+ onShouldReconnect(connection);
+ });
+ QObject::connect(connection, &QtROIoDeviceBase::readyRead, q, [this, connection]() {
+ onClientRead(connection);
+ });
+ connection->connectToServer();
+
+ return true;
+}
+
+bool QRemoteObjectNodePrivate::hasInstance(const QString &name)
+{
+ if (!replicas.contains(name))
+ return false;
+
+ QSharedPointer<QReplicaImplementationInterface> rep = replicas.value(name).toStrongRef();
+ if (!rep) { //already deleted
+ replicas.remove(name);
+ return false;
+ }
+
+ return true;
+}
+
+static QDebug operator<<(QDebug debug,
+ const QHash<QString, QWeakPointer<QReplicaImplementationInterface>> &hash)
+{
+ const QDebugStateSaver saver(debug);
+ debug.nospace() << "QHash(";
+ for (auto it = hash.cbegin(); it != hash.cend(); ++it)
+ debug << '(' << it.key() << ", " << it.value().isNull() << ')';
+ debug << ')';
+ return debug;
+}
+
+void QRemoteObjectNodePrivate::onRemoteObjectSourceAdded(const QRemoteObjectSourceLocation &entry)
+{
+ qROPrivDebug() << "onRemoteObjectSourceAdded" << entry << replicas << replicas.contains(entry.first);
+ if (!entry.first.isEmpty()) {
+ QRemoteObjectSourceLocations locs = registry->sourceLocations();
+ locs[entry.first] = entry.second;
+ //TODO Is there a way to extend QRemoteObjectSourceLocations in place?
+ registry->d_impl->setProperty(0, QVariant::fromValue(locs));
+ registry->notifySourceLocationsChanged();
+ qROPrivDebug() << "onRemoteObjectSourceAdded, now locations =" << locs;
+ }
+ if (replicas.contains(entry.first)) //We have a replica waiting on this remoteObject
+ {
+ QSharedPointer<QReplicaImplementationInterface> rep = replicas.value(entry.first).toStrongRef();
+ if (!rep) { //replica has been deleted, remove from list
+ replicas.remove(entry.first);
+ return;
+ }
+
+ initConnection(entry.second.hostUrl);
+
+ qROPrivDebug() << "Called initConnection due to new RemoteObjectSource added via registry" << entry.first;
+ }
+}
+
+void QRemoteObjectNodePrivate::onRemoteObjectSourceRemoved(const QRemoteObjectSourceLocation &entry)
+{
+ if (!entry.first.isEmpty()) {
+ QRemoteObjectSourceLocations locs = registry->sourceLocations();
+ locs.remove(entry.first);
+ registry->d_impl->setProperty(0, QVariant::fromValue(locs));
+ registry->notifySourceLocationsChanged();
+ }
+}
+
+void QRemoteObjectNodePrivate::onRegistryInitialized()
+{
+ qROPrivDebug() << "Registry Initialized" << remoteObjectAddresses();
+
+ const auto remotes = remoteObjectAddresses();
+ for (auto i = remotes.cbegin(), end = remotes.cend(); i != end; ++i) {
+ if (replicas.contains(i.key())) //We have a replica waiting on this remoteObject
+ {
+ QSharedPointer<QReplicaImplementationInterface> rep = replicas.value(i.key()).toStrongRef();
+ if (rep && !requestedUrls.contains(i.value().hostUrl))
+ initConnection(i.value().hostUrl);
+ else if (!rep) //replica has been deleted, remove from list
+ replicas.remove(i.key());
+
+ continue;
+ }
+ }
+}
+
+void QRemoteObjectNodePrivate::onShouldReconnect(QtROClientIoDevice *ioDevice)
+{
+ Q_Q(QRemoteObjectNode);
+
+ const auto remoteObjects = ioDevice->remoteObjects();
+ for (const QString &remoteObject : remoteObjects) {
+ connectedSources.remove(remoteObject);
+ ioDevice->removeSource(remoteObject);
+ if (replicas.contains(remoteObject)) { //We have a replica waiting on this remoteObject
+ QSharedPointer<QConnectedReplicaImplementation> rep = qSharedPointerCast<QConnectedReplicaImplementation>(replicas.value(remoteObject).toStrongRef());
+ if (rep && !rep->connectionToSource.isNull()) {
+ rep->setDisconnected();
+ } else if (!rep) {
+ replicas.remove(remoteObject);
+ }
+ }
+ }
+ if (requestedUrls.contains(ioDevice->url())) {
+ // Only try to reconnect to URLs requested via connectToNode
+ // If we connected via registry, wait for the registry to see the node/source again
+ pendingReconnect.insert(ioDevice);
+ if (!reconnectTimer.isActive()) {
+ reconnectTimer.start(retryInterval, q);
+ qROPrivDebug() << "Starting reconnect timer";
+ }
+ } else {
+ qROPrivDebug() << "Url" << ioDevice->url().toDisplayString().toLatin1()
+ << "lost. We will reconnect Replicas if they reappear on the Registry.";
+ }
+}
+
+//This version of handleNewAcquire creates a QConnectedReplica. If this is a
+//host node, the QRemoteObjectHostBasePrivate overload is called instead.
+QReplicaImplementationInterface *QRemoteObjectNodePrivate::handleNewAcquire(const QMetaObject *meta, QRemoteObjectReplica *instance, const QString &name)
+{
+ Q_Q(QRemoteObjectNode);
+ QConnectedReplicaImplementation *rp = new QConnectedReplicaImplementation(name, meta, q);
+ rp->configurePrivate(instance);
+ if (connectedSources.contains(name)) { //Either we have a peer connections, or existing connection via registry
+ handleReplicaConnection(connectedSources[name].objectSignature, rp, connectedSources[name].device);
+ } else {
+ //No existing connection, but we know we can connect via registry
+ const auto &sourceLocations = remoteObjectAddresses();
+ const auto it = sourceLocations.constFind(name);
+ // This will try the connection, and if successful, the remoteObjects will be sent
+ // The link to the replica will be handled then
+ if (it != sourceLocations.constEnd())
+ initConnection(it.value().hostUrl);
+ }
+ return rp;
+}
+
+void QRemoteObjectNodePrivate::handleReplicaConnection(const QString &name)
+{
+ QSharedPointer<QRemoteObjectReplicaImplementation> rep = qSharedPointerCast<QRemoteObjectReplicaImplementation>(replicas.value(name).toStrongRef());
+ if (!rep) { //replica has been deleted, remove from list
+ replicas.remove(name);
+ return;
+ }
+
+ if (rep->isShortCircuit())
+ return;
+
+ QConnectedReplicaImplementation *connectedRep = static_cast<QConnectedReplicaImplementation *>(rep.data());
+ if (connectedRep->connectionToSource.isNull()) {
+ const auto sourceInfo = connectedSources.value(name);
+ handleReplicaConnection(sourceInfo.objectSignature, connectedRep, sourceInfo.device);
+ }
+}
+
+void QRemoteObjectNodePrivate::handleReplicaConnection(const QByteArray &sourceSignature, QConnectedReplicaImplementation *rep, QtROIoDeviceBase *connection)
+{
+ if (!checkSignatures(rep->m_objectSignature, sourceSignature)) {
+ qROPrivWarning() << "Signature mismatch for" << rep->m_metaObject->className() << (rep->m_objectName.isEmpty() ? QLatin1String("(unnamed)") : rep->m_objectName);
+ rep->setState(QRemoteObjectReplica::SignatureMismatch);
+ return;
+ }
+ rep->setConnection(connection);
+}
+
+//Host Nodes can use the more efficient InProcess Replica if we (this Node) hold the Source for the
+//requested Replica. If not, fall back to the Connected Replica case.
+QReplicaImplementationInterface *QRemoteObjectHostBasePrivate::handleNewAcquire(const QMetaObject *meta, QRemoteObjectReplica *instance, const QString &name)
+{
+ QMap<QString, QRemoteObjectSourceBase*>::const_iterator mapIt;
+ if (remoteObjectIo && map_contains(remoteObjectIo->m_sourceObjects, name, mapIt)) {
+ Q_Q(QRemoteObjectHostBase);
+ QInProcessReplicaImplementation *rp = new QInProcessReplicaImplementation(name, meta, q);
+ rp->configurePrivate(instance);
+ connectReplica(mapIt.value()->m_object, instance);
+ rp->connectionToSource = mapIt.value();
+ return rp;
+ }
+ return QRemoteObjectNodePrivate::handleNewAcquire(meta, instance, name);
+}
+
+void QRemoteObjectNodePrivate::onClientRead(QObject *obj)
+{
+ using namespace QRemoteObjectPackets;
+ QtROIoDeviceBase *connection = qobject_cast<QtROIoDeviceBase*>(obj);
+ QRemoteObjectPacketTypeEnum packetType;
+ Q_ASSERT(connection);
+ auto &codec = connection->d_func()->m_codec;
+
+ do {
+ if (!connection->read(packetType, rxName))
+ return;
+
+ if (packetType != Handshake && codec == nullptr) {
+ qROPrivWarning() << "Expected Handshake, got " << packetType;
+ setLastError(QRemoteObjectNode::ProtocolMismatch);
+ connection->close();
+ break;
+ }
+
+ switch (packetType) {
+ case QRemoteObjectPacketTypeEnum::Pong:
+ {
+ QSharedPointer<QRemoteObjectReplicaImplementation> rep = qSharedPointerCast<QRemoteObjectReplicaImplementation>(replicas.value(rxName).toStrongRef());
+ if (rep)
+ rep->notifyAboutReply(0, {});
+ else //replica has been deleted, remove from list
+ replicas.remove(rxName);
+ break;
+ }
+ case QRemoteObjectPacketTypeEnum::Handshake:
+ if (rxName != QtRemoteObjects::protocolVersion) {
+ qWarning() << "*** Protocol Mismatch, closing connection ***. Got" << rxName << "expected" << QtRemoteObjects::protocolVersion;
+ setLastError(QRemoteObjectNode::ProtocolMismatch);
+ connection->close();
+ } else {
+ // TODO should have some sort of manager for the codec
+ codec = new QRemoteObjectPackets::QDataStreamCodec;
+ }
+ break;
+ case QRemoteObjectPacketTypeEnum::ObjectList:
+ {
+ codec->deserializeObjectListPacket(connection->d_func()->stream(), rxObjects);
+ qROPrivDebug() << "newObjects:" << rxObjects;
+ // We need to make sure all of the source objects are in connectedSources before we add connections,
+ // otherwise nested QObjects could fail (we want to acquire children before parents, and the object
+ // list is unordered)
+ for (const auto &remoteObject : qAsConst(rxObjects)) {
+ qROPrivDebug() << " connectedSources.contains(" << remoteObject << ")" << connectedSources.contains(remoteObject.name) << replicas.contains(remoteObject.name);
+ if (!connectedSources.contains(remoteObject.name)) {
+ connectedSources[remoteObject.name] = SourceInfo{connection, remoteObject.typeName, remoteObject.signature};
+ connection->addSource(remoteObject.name);
+ // Make sure we handle Registry first if it is available
+ if (remoteObject.name == QLatin1String("Registry") && replicas.contains(remoteObject.name))
+ handleReplicaConnection(remoteObject.name);
+ }
+ }
+ for (const auto &remoteObject : qAsConst(rxObjects)) {
+ if (replicas.contains(remoteObject.name)) //We have a replica waiting on this remoteObject
+ handleReplicaConnection(remoteObject.name);
+ }
+ break;
+ }
+ case QRemoteObjectPacketTypeEnum::InitPacket:
+ {
+ qROPrivDebug() << "InitPacket-->" << rxName << this;
+ QSharedPointer<QConnectedReplicaImplementation> rep = qSharedPointerCast<QConnectedReplicaImplementation>(replicas.value(rxName).toStrongRef());
+ //Use m_rxArgs (a QVariantList to hold the properties QVariantList)
+ codec->deserializeInitPacket(connection->d_func()->stream(), rxArgs);
+ if (rep)
+ {
+ handlePointerToQObjectProperties(rep.data(), rxArgs);
+ rep->initialize(std::move(rxArgs));
+ } else { //replica has been deleted, remove from list
+ replicas.remove(rxName);
+ }
+ break;
+ }
+ case QRemoteObjectPacketTypeEnum::InitDynamicPacket:
+ {
+ qROPrivDebug() << "InitDynamicPacket-->" << rxName << this;
+ const QMetaObject *meta = dynamicTypeManager.addDynamicType(connection, connection->d_func()->stream());
+ codec->deserializeInitPacket(connection->d_func()->stream(), rxArgs);
+ QSharedPointer<QConnectedReplicaImplementation> rep = qSharedPointerCast<QConnectedReplicaImplementation>(replicas.value(rxName).toStrongRef());
+ if (rep)
+ {
+ rep->setDynamicMetaObject(meta);
+ handlePointerToQObjectProperties(rep.data(), rxArgs);
+ rep->setDynamicProperties(std::move(rxArgs));
+ } else { //replica has been deleted, remove from list
+ replicas.remove(rxName);
+ }
+ break;
+ }
+ case QRemoteObjectPacketTypeEnum::RemoveObject:
+ {
+ qROPrivDebug() << "RemoveObject-->" << rxName << this;
+ connectedSources.remove(rxName);
+ connection->removeSource(rxName);
+ if (replicas.contains(rxName)) { //We have a replica using the removed source
+ QSharedPointer<QConnectedReplicaImplementation> rep = qSharedPointerCast<QConnectedReplicaImplementation>(replicas.value(rxName).toStrongRef());
+ if (rep && !rep->connectionToSource.isNull()) {
+ rep->connectionToSource.clear();
+ rep->setState(QRemoteObjectReplica::Suspect);
+ } else if (!rep) {
+ replicas.remove(rxName);
+ }
+ }
+ break;
+ }
+ case QRemoteObjectPacketTypeEnum::PropertyChangePacket:
+ {
+ int propertyIndex;
+ codec->deserializePropertyChangePacket(connection->d_func()->stream(), propertyIndex, rxValue);
+ QSharedPointer<QRemoteObjectReplicaImplementation> rep = qSharedPointerCast<QRemoteObjectReplicaImplementation>(replicas.value(rxName).toStrongRef());
+ if (rep) {
+ QConnectedReplicaImplementation *connectedRep = nullptr;
+ if (!rep->isShortCircuit()) {
+ connectedRep = static_cast<QConnectedReplicaImplementation *>(rep.data());
+ if (!connectedRep->childIndices().contains(propertyIndex))
+ connectedRep = nullptr; //connectedRep will be a valid pointer only if propertyIndex is a child index
+ }
+ if (connectedRep)
+ rep->setProperty(propertyIndex, handlePointerToQObjectProperty(connectedRep, propertyIndex, rxValue));
+ else {
+ const QMetaProperty property = rep->m_metaObject->property(propertyIndex + rep->m_metaObject->propertyOffset());
+ if (property.userType() == QMetaType::QVariant && rxValue.canConvert<QRO_>()) {
+ // This is a type that requires registration
+ QRO_ typeInfo = rxValue.value<QRO_>();
+ QDataStream in(typeInfo.classDefinition);
+ parseGadgets(connection, in);
+ QDataStream ds(typeInfo.parameters);
+ ds >> rxValue;
+ }
+ rep->setProperty(propertyIndex, decodeVariant(std::move(rxValue), property.metaType()));
+ }
+ } else { //replica has been deleted, remove from list
+ replicas.remove(rxName);
+ }
+ break;
+ }
+ case QRemoteObjectPacketTypeEnum::InvokePacket:
+ {
+ int call, index, serialId, propertyIndex;
+ codec->deserializeInvokePacket(connection->d_func()->stream(), call, index, rxArgs, serialId, propertyIndex);
+ QSharedPointer<QRemoteObjectReplicaImplementation> rep = qSharedPointerCast<QRemoteObjectReplicaImplementation>(replicas.value(rxName).toStrongRef());
+ if (rep) {
+ static QVariant null(QMetaType::fromType<QObject *>(), nullptr);
+ QVariant paramValue;
+ // Qt usually supports 9 arguments, so ten should be usually safe
+ QVarLengthArray<void*, 10> param(rxArgs.size() + 1);
+ param[0] = null.data(); //Never a return value
+ if (rxArgs.size()) {
+ auto signal = rep->m_metaObject->method(index+rep->m_signalOffset);
+ for (int i = 0; i < rxArgs.size(); i++) {
+ if (signal.parameterType(i) == QMetaType::QVariant)
+ param[i + 1] = const_cast<void*>(reinterpret_cast<const void*>(&rxArgs.at(i)));
+ else {
+ rxArgs[i] = decodeVariant(std::move(rxArgs[i]), signal.parameterMetaType(i));
+ param[i + 1] = const_cast<void *>(rxArgs.at(i).data());
+ }
+ }
+ } else if (propertyIndex != -1) {
+ param.resize(2);
+ paramValue = rep->getProperty(propertyIndex);
+ param[1] = paramValue.data();
+ }
+ qROPrivDebug() << "Replica Invoke-->" << rxName << rep->m_metaObject->method(index+rep->m_signalOffset).name() << index << rep->m_signalOffset;
+ // We activate on rep->metaobject() so the private metacall is used, not m_metaobject (which
+ // is the class thie replica looks like)
+ QMetaObject::activate(rep.data(), rep->metaObject(), index+rep->m_signalOffset, param.data());
+ } else { //replica has been deleted, remove from list
+ replicas.remove(rxName);
+ }
+ break;
+ }
+ case QRemoteObjectPacketTypeEnum::InvokeReplyPacket:
+ {
+ int ackedSerialId;
+ codec->deserializeInvokeReplyPacket(connection->d_func()->stream(), ackedSerialId, rxValue);
+ QSharedPointer<QRemoteObjectReplicaImplementation> rep = qSharedPointerCast<QRemoteObjectReplicaImplementation>(replicas.value(rxName).toStrongRef());
+ if (rep) {
+ qROPrivDebug() << "Received InvokeReplyPacket ack'ing serial id:" << ackedSerialId;
+ rep->notifyAboutReply(ackedSerialId, rxValue);
+ } else { //replica has been deleted, remove from list
+ replicas.remove(rxName);
+ }
+ break;
+ }
+ case QRemoteObjectPacketTypeEnum::AddObject:
+ case QRemoteObjectPacketTypeEnum::Invalid:
+ case QRemoteObjectPacketTypeEnum::Ping:
+ qROPrivWarning() << "Unexpected packet received";
+ }
+ } while (connection->bytesAvailable()); // have bytes left over, so do another iteration
+}
+
+/*!
+ \class QRemoteObjectNode
+ \inmodule QtRemoteObjects
+ \brief A node on a Qt Remote Objects network.
+
+ The QRemoteObjectNode class provides an entry point to a QtRemoteObjects
+ network. A network can be as simple as two nodes, or an arbitrarily complex
+ set of processes and devices.
+
+ A QRemoteObjectNode does not have a url that other nodes can connect to,
+ and thus is able to acquire replicas only. It is not able to share source
+ objects (only QRemoteObjectHost and QRemoteObjectRegistryHost Nodes can
+ share).
+
+ Nodes may connect to each other directly using \l connectToNode, or
+ they can use the QRemoteObjectRegistry to simplify connections.
+
+ The QRemoteObjectRegistry is a special replica available to every node that
+ connects to the Registry Url. It knows how to connect to every
+ QRemoteObjectSource object on the network.
+
+ \sa QRemoteObjectHost, QRemoteObjectRegistryHost
+*/
+
+/*!
+ \class QRemoteObjectHostBase
+ \inmodule QtRemoteObjects
+ \brief The QRemoteObjectHostBase class provides base functionality common to \l
+ {QRemoteObjectHost} {Host} and \l {QRemoteObjectRegistryHost} {RegistryHost} classes.
+
+ QRemoteObjectHostBase is a base class that cannot be instantiated directly.
+ It provides the enableRemoting and disableRemoting functionality shared by
+ all host nodes (\l {QRemoteObjectHost} {Host} and \l
+ {QRemoteObjectRegistryHost} {RegistryHost}) as well as the logic required
+ to expose \l {Source} objects on the Remote Objects network.
+*/
+
+/*!
+ \class QRemoteObjectHost
+ \inmodule QtRemoteObjects
+ \brief A (Host) Node on a Qt Remote Objects network.
+
+ The QRemoteObjectHost class provides an entry point to a QtRemoteObjects
+ network. A network can be as simple as two nodes, or an arbitrarily complex
+ set of processes and devices.
+
+ QRemoteObjectHosts have the same capabilities as QRemoteObjectNodes, but
+ they can also be connected to and can share source objects on the network.
+
+ Nodes may connect to each other directly using \l connectToNode, or they
+ can use the QRemoteObjectRegistry to simplify connections.
+
+ The QRemoteObjectRegistry is a special replica available to every node that
+ connects to the registry Url. It knows how to connect to every
+ QRemoteObjectSource object on the network.
+
+ \sa QRemoteObjectNode, QRemoteObjectRegistryHost
+*/
+
+/*!
+ \class QRemoteObjectRegistryHost
+ \inmodule QtRemoteObjects
+ \brief A (Host/Registry) node on a Qt Remote Objects network.
+
+ The QRemoteObjectRegistryHost class provides an entry point to a QtRemoteObjects
+ network. A network can be as simple as two Nodes, or an arbitrarily complex
+ set of processes and devices.
+
+ A QRemoteObjectRegistryHost has the same capability that a
+ QRemoteObjectHost has (which includes everything a QRemoteObjectNode
+ supports), and in addition is the owner of the Registry. Any
+ QRemoteObjectHost node that connects to this Node will have all of their
+ Source objects made available by the Registry.
+
+ Nodes only support connection to one \l registry, calling \l
+ QRemoteObjectNode::setRegistryUrl when a Registry is already set is
+ considered an error. For something like a secure and insecure network
+ (where different Registries would be applicable), the recommendation is to
+ create separate Nodes to connect to each, in effect creating two
+ independent Qt Remote Objects networks.
+
+ Nodes may connect to each other directly using \l connectToNode, or they
+ can use the QRemoteObjectRegistry to simplify connections.
+
+ The QRemoteObjectRegistry is a special Replica available to every Node that
+ connects to the Registry Url. It knows how to connect to every
+ QRemoteObjectSource object on the network.
+
+ \sa QRemoteObjectNode, QRemoteObjectHost
+*/
+
+/*!
+ \enum QRemoteObjectNode::ErrorCode
+
+ This enum type specifies the various error codes associated with QRemoteObjectNode errors:
+
+ \value NoError No error.
+ \value RegistryNotAcquired The registry could not be acquired.
+ \value RegistryAlreadyHosted The registry is already defined and hosting Sources.
+ \value NodeIsNoServer The given QRemoteObjectNode is not a host node.
+ \value ServerAlreadyCreated The host node has already been initialized.
+ \value UnintendedRegistryHosting An attempt was made to create a host QRemoteObjectNode and connect to itself as the registry.
+ \value OperationNotValidOnClientNode The attempted operation is not valid on a client QRemoteObjectNode.
+ \value SourceNotRegistered The given QRemoteObjectSource is not registered on this node.
+ \value MissingObjectName The given QObject does not have objectName() set.
+ \value HostUrlInvalid The given url has an invalid or unrecognized scheme.
+ \value ProtocolMismatch The client and the server have different protocol versions.
+ \value ListenFailed Can't listen on the specified host port.
+*/
+
+/*!
+ \enum QRemoteObjectHostBase::AllowedSchemas
+
+ This enum is used to specify whether a Node will accept a url with an
+ unrecognized schema for the hostUrl. By default only urls with known
+ schemas are accepted, but using \c AllowExternalRegistration will enable
+ the \l Registry to pass your external (to QtRO) url to client Nodes.
+
+ \value BuiltInSchemasOnly Only allow the hostUrl to be set to a QtRO
+ supported schema. This is the default value, and causes a Node error to be
+ set if an unrecognized schema is provided.
+ \value AllowExternalRegistration The provided schema is registered as an
+ \l {External Schemas}{External Schema}
+
+ \sa QRemoteObjectHost
+*/
+
+/*!
+ \fn ObjectType *QRemoteObjectNode::acquire(const QString &name)
+
+ Returns a pointer to a Replica of type ObjectType (which is a template
+ parameter and must inherit from \l QRemoteObjectReplica). That is, the
+ template parameter must be a \l {repc} generated type. The \a name
+ parameter can be used to specify the \a name given to the object
+ during the QRemoteObjectHost::enableRemoting() call.
+*/
+
+void QRemoteObjectNodePrivate::initialize()
+{
+ qRegisterMetaType<QRemoteObjectNode *>();
+ qRegisterMetaType<QRemoteObjectNode::ErrorCode>();
+ qRegisterMetaType<QAbstractSocket::SocketError>(); //For queued qnx error()
+ qRegisterMetaType<QRemoteObjectPackets::QRO_>();
+ qRegisterMetaType<QRemoteObjectPackets::QSQ_>();
+ qRegisterMetaType<QRemoteObjectPackets::QAS_>();
+ qRegisterMetaType<QtROSequentialContainer>();
+ qRegisterMetaType<QtROAssociativeContainer>();
+ // To support dynamic MODELs, we need to make sure the types are registered
+ QAbstractItemModelSourceAdapter::registerTypes();
+}
+
+bool QRemoteObjectNodePrivate::checkSignatures(const QByteArray &a, const QByteArray &b)
+{
+ // if any of a or b is empty it means it's a dynamic ojects or an item model
+ if (a.isEmpty() || b.isEmpty())
+ return true;
+ return a == b;
+}
+
+
+void QRemoteObjectNode::persistProperties(const QString &repName, const QByteArray &repSig, const QVariantList &props)
+{
+ Q_D(QRemoteObjectNode);
+ if (d->persistedStore) {
+ d->persistedStore->saveProperties(repName, repSig, props);
+ } else {
+ qCWarning(QT_REMOTEOBJECT) << qPrintable(objectName()) << "Unable to store persisted properties for" << repName;
+ qCWarning(QT_REMOTEOBJECT) << " No persisted store set.";
+ }
+}
+
+QVariantList QRemoteObjectNode::retrieveProperties(const QString &repName, const QByteArray &repSig)
+{
+ Q_D(QRemoteObjectNode);
+ if (d->persistedStore) {
+ return d->persistedStore->restoreProperties(repName, repSig);
+ }
+ qCWarning(QT_REMOTEOBJECT) << qPrintable(objectName()) << "Unable to retrieve persisted properties for" << repName;
+ qCWarning(QT_REMOTEOBJECT) << " No persisted store set.";
+ return QVariantList();
+}
+
+/*!
+ Default constructor for QRemoteObjectNode with the given \a parent. A Node
+ constructed in this manner can not be connected to, and thus can not expose
+ Source objects on the network. It also will not include a \l
+ QRemoteObjectRegistry, unless set manually using setRegistryUrl.
+
+ \sa connectToNode, setRegistryUrl
+*/
+QRemoteObjectNode::QRemoteObjectNode(QObject *parent)
+ : QObject(*new QRemoteObjectNodePrivate, parent)
+{
+ Q_D(QRemoteObjectNode);
+ d->initialize();
+}
+
+/*!
+ QRemoteObjectNode connected to a {QRemoteObjectRegistry} {Registry}. A Node
+ constructed in this manner can not be connected to, and thus can not expose
+ Source objects on the network. Finding and connecting to other (Host) Nodes
+ is handled by the QRemoteObjectRegistry specified by \a registryAddress.
+
+ \sa connectToNode, setRegistryUrl, QRemoteObjectHost, QRemoteObjectRegistryHost
+*/
+QRemoteObjectNode::QRemoteObjectNode(const QUrl ®istryAddress, QObject *parent)
+ : QObject(*new QRemoteObjectNodePrivate, parent)
+{
+ Q_D(QRemoteObjectNode);
+ d->initialize();
+ d->setRegistryUrlNodeImpl(registryAddress);
+}
+
+QRemoteObjectNode::QRemoteObjectNode(QRemoteObjectNodePrivate &dptr, QObject *parent)
+ : QObject(dptr, parent)
+{
+ Q_D(QRemoteObjectNode);
+ d->initialize();
+}
+
+/*!
+ \qmltype Host
+ \instantiates QRemoteObjectHost
+ \inqmlmodule QtRemoteObjects
+ \brief A host node on a Qt Remote Objects network.
+
+ The Host type provides an entry point to a Qt Remote Objects network. A network
+ can be as simple as two nodes, or an arbitrarily complex set of processes and devices.
+
+ Hosts have the same capabilities as Nodes, but they can also be connected to and can
+ share source objects on the network.
+*/
+
+/*!
+ \internal This is a base class for both QRemoteObjectHost and
+ QRemoteObjectRegistryHost to provide the shared features/functions for
+ sharing \l Source objects.
+*/
+QRemoteObjectHostBase::QRemoteObjectHostBase(QRemoteObjectHostBasePrivate &d, QObject *parent)
+ : QRemoteObjectNode(d, parent)
+{ }
+
+/*!
+ Constructs a new QRemoteObjectHost Node (i.e., a Node that supports
+ exposing \l Source objects on the QtRO network) with the given \a parent.
+ This constructor is meant specific to support QML in the future as it will
+ not be available to connect to until \l {QRemoteObjectHost::}{setHostUrl} is called.
+
+ \sa setHostUrl(), setRegistryUrl()
+*/
+QRemoteObjectHost::QRemoteObjectHost(QObject *parent)
+ : QRemoteObjectHostBase(*new QRemoteObjectHostPrivate, parent)
+{ }
+
+/*!
+ Constructs a new QRemoteObjectHost Node (i.e., a Node that supports
+ exposing \l Source objects on the QtRO network) with address \a address. If
+ set, \a registryAddress will be used to connect to the \l
+ QRemoteObjectRegistry at the provided address. The \a allowedSchemas
+ parameter is only needed (and should be set to \l
+ {QRemoteObjectHostBase::AllowExternalRegistration}
+ {AllowExternalRegistration}) if the schema of the url should be used as an
+ \l {External Schemas} {External Schema} by the registry.
+
+ \sa setHostUrl(), setRegistryUrl()
+*/
+QRemoteObjectHost::QRemoteObjectHost(const QUrl &address, const QUrl ®istryAddress,
+ AllowedSchemas allowedSchemas, QObject *parent)
+ : QRemoteObjectHostBase(*new QRemoteObjectHostPrivate, parent)
+{
+ if (!address.isEmpty()) {
+ if (!d_func()->setHostUrlBaseImpl(address, allowedSchemas))
+ return;
+ }
+
+ if (!registryAddress.isEmpty())
+ d_func()->setRegistryUrlNodeImpl(registryAddress);
+}
+
+/*!
+ Constructs a new QRemoteObjectHost Node (i.e., a Node that supports
+ exposing \l Source objects on the QtRO network) with a url of \a
+ address and the given \a parent. This overload is provided as a convenience for specifying a
+ QObject parent without providing a registry address.
+
+ \sa setHostUrl(), setRegistryUrl()
+*/
+QRemoteObjectHost::QRemoteObjectHost(const QUrl &address, QObject *parent)
+ : QRemoteObjectHostBase(*new QRemoteObjectHostPrivate, parent)
+{
+ if (!address.isEmpty())
+ d_func()->setHostUrlBaseImpl(address);
+}
+
+/*!
+ \internal QRemoteObjectHost::QRemoteObjectHost
+*/
+QRemoteObjectHost::QRemoteObjectHost(QRemoteObjectHostPrivate &d, QObject *parent)
+ : QRemoteObjectHostBase(d, parent)
+{ }
+
+QRemoteObjectHost::~QRemoteObjectHost() {}
+
+/*!
+ Constructs a new QRemoteObjectRegistryHost Node with the given \a parent. RegistryHost Nodes have
+ the same functionality as \l QRemoteObjectHost Nodes, except rather than
+ being able to connect to a \l QRemoteObjectRegistry, the provided Host QUrl
+ (\a registryAddress) becomes the address of the registry for other Nodes to
+ connect to.
+*/
+QRemoteObjectRegistryHost::QRemoteObjectRegistryHost(const QUrl ®istryAddress, QObject *parent)
+ : QRemoteObjectHostBase(*new QRemoteObjectRegistryHostPrivate, parent)
+{
+ if (registryAddress.isEmpty())
+ return;
+
+ d_func()->setRegistryUrlRegistryHostImpl(registryAddress);
+}
+
+/*!
+ \internal
+*/
+QRemoteObjectRegistryHost::QRemoteObjectRegistryHost(QRemoteObjectRegistryHostPrivate &d, QObject *parent)
+ : QRemoteObjectHostBase(d, parent)
+{ }
+
+QRemoteObjectRegistryHost::~QRemoteObjectRegistryHost() {}
+
+QRemoteObjectNode::~QRemoteObjectNode()
+{ }
+
+QRemoteObjectHostBase::~QRemoteObjectHostBase()
+{ }
+
+/*!
+ Sets \a name as the internal name for this Node. This
+ is then output as part of the logging (if enabled).
+ This is primarily useful if you merge log data from multiple nodes.
+*/
+void QRemoteObjectNode::setName(const QString &name)
+{
+ setObjectName(name);
+}
+
+/*!
+ Similar to QObject::setObjectName() (which this method calls), but this
+ version also applies the \a name to internal classes as well, which are
+ used in some of the debugging output.
+*/
+void QRemoteObjectHostBase::setName(const QString &name)
+{
+ Q_D(QRemoteObjectHostBase);
+ setObjectName(name);
+ if (d->remoteObjectIo)
+ d->remoteObjectIo->setObjectName(name);
+}
+
+/*!
+ \internal The HostBase version of this method is protected so the method
+ isn't exposed on RegistryHost nodes.
+*/
+QUrl QRemoteObjectHostBase::hostUrl() const
+{
+ Q_D(const QRemoteObjectHostBase);
+ if (d->remoteObjectIo)
+ return d->remoteObjectIo->serverAddress();
+ return QUrl();
+}
+
+/*!
+ \internal The HostBase version of this method is protected so the method
+ isn't exposed on RegistryHost nodes.
+*/
+bool QRemoteObjectHostBase::setHostUrl(const QUrl &hostAddress, AllowedSchemas allowedSchemas)
+{
+ return d_func()->setHostUrlBaseImpl(hostAddress, allowedSchemas);
+}
+
+bool QRemoteObjectHostBasePrivate::setHostUrlBaseImpl(
+ const QUrl &hostAddress, QRemoteObjectHostBase::AllowedSchemas allowedSchemas)
+{
+ Q_Q(QRemoteObjectHostBase);
+ if (remoteObjectIo) {
+ setLastError(QRemoteObjectHostBase::ServerAlreadyCreated);
+ return false;
+ }
+
+ if (allowedSchemas == QRemoteObjectHostBase::AllowedSchemas::BuiltInSchemasOnly && !QtROServerFactory::instance()->isValid(hostAddress)) {
+ setLastError(QRemoteObjectHostBase::HostUrlInvalid);
+ return false;
+ }
+
+ if (allowedSchemas == QRemoteObjectHostBase::AllowedSchemas::AllowExternalRegistration && QtROServerFactory::instance()->isValid(hostAddress)) {
+ qWarning() << qPrintable(q->objectName()) << "Overriding a valid QtRO url (" << hostAddress << ") with AllowExternalRegistration is not allowed.";
+ setLastError(QRemoteObjectHostBase::HostUrlInvalid);
+ return false;
+ }
+ remoteObjectIo = new QRemoteObjectSourceIo(hostAddress, q);
+
+ if (allowedSchemas == QRemoteObjectHostBase::AllowedSchemas::BuiltInSchemasOnly && !remoteObjectIo->startListening()) {
+ setLastError(QRemoteObjectHostBase::ListenFailed);
+ delete remoteObjectIo;
+ remoteObjectIo = nullptr;
+ return false;
+ }
+
+ //If we've given a name to the node, set it on the sourceIo as well
+ if (!q->objectName().isEmpty())
+ remoteObjectIo->setObjectName(q->objectName());
+ //Since we don't know whether setHostUrl or setRegistryUrl/setRegistryHost will be called first,
+ //break it into two pieces. setHostUrl connects the RemoteObjectSourceIo->[add/remove]RemoteObjectSource to QRemoteObjectReplicaNode->[add/remove]RemoteObjectSource
+ //setRegistry* calls appropriately connect RemoteObjecSourcetIo->[add/remove]RemoteObjectSource to the registry when it is created
+ QObject::connect(remoteObjectIo, &QRemoteObjectSourceIo::remoteObjectAdded, q, &QRemoteObjectHostBase::remoteObjectAdded);
+ QObject::connect(remoteObjectIo, &QRemoteObjectSourceIo::remoteObjectRemoved, q, &QRemoteObjectHostBase::remoteObjectRemoved);
+
+ return true;
+}
+
+/*!
+ \qmlproperty url Host::hostUrl
+
+ The host address for the node.
+
+ This is the address where source objects remoted by this node will reside.
+*/
+
+/*!
+ \property QRemoteObjectHost::hostUrl
+ \brief The host address for the node.
+
+ This is the address where source objects remoted by this node will reside.
+*/
+
+/*!
+ Returns the host address for the QRemoteObjectNode as a QUrl. If the Node
+ is not a Host node, returns an empty QUrl.
+
+ \sa setHostUrl()
+*/
+QUrl QRemoteObjectHost::hostUrl() const
+{
+ return QRemoteObjectHostBase::hostUrl();
+}
+
+/*!
+ Sets the \a hostAddress for a host QRemoteObjectNode.
+
+ Returns \c true if the Host address is set, otherwise \c false.
+
+ The \a allowedSchemas parameter is only needed (and should be set to \l
+ {QRemoteObjectHostBase::AllowExternalRegistration}
+ {AllowExternalRegistration}) if the schema of the url should be used as an
+ \l {External Schemas} {External Schema} by the registry.
+*/
+bool QRemoteObjectHost::setHostUrl(const QUrl &hostAddress, AllowedSchemas allowedSchemas)
+{
+ return d_func()->setHostUrlHostImpl(hostAddress, allowedSchemas);
+}
+
+bool QRemoteObjectHostPrivate::setHostUrlHostImpl(
+ const QUrl &hostAddress, QRemoteObjectHostBase::AllowedSchemas allowedSchemas)
+{
+ bool success = setHostUrlBaseImpl(hostAddress, allowedSchemas);
+ if (success)
+ q_func()->hostUrlChanged();
+ return success;
+}
+
+/*!
+ This method can be used to set the address of this Node to \a registryUrl
+ (used for other Nodes to connect to this one), if the QUrl isn't set in the
+ constructor. Since this Node becomes the Registry, calling this setter
+ method causes this Node to use the url as the host address. All other
+ Node's use the \l {QRemoteObjectNode::setRegistryUrl} method initiate a
+ connection to the Registry.
+
+ Returns \c true if the registry address is set, otherwise \c false.
+
+ \sa QRemoteObjectRegistryHost(), QRemoteObjectNode::setRegistryUrl
+*/
+bool QRemoteObjectRegistryHost::setRegistryUrl(const QUrl ®istryUrl)
+{
+ return d_func()->setRegistryUrlRegistryHostImpl(registryUrl);
+}
+
+bool QRemoteObjectRegistryHostPrivate::setRegistryUrlRegistryHostImpl(const QUrl ®istryUrl)
+{
+ Q_Q(QRemoteObjectRegistryHost);
+ if (setHostUrlBaseImpl(registryUrl)) {
+ if (!remoteObjectIo) {
+ setLastError(QRemoteObjectNode::ServerAlreadyCreated);
+ return false;
+ } else if (registry) {
+ setLastError(QRemoteObjectNode::RegistryAlreadyHosted);
+ return false;
+ }
+
+ QRegistrySource *remoteObject = new QRegistrySource(q);
+ q->enableRemoting(remoteObject);
+ registryAddress = remoteObjectIo->serverAddress();
+ registrySource = remoteObject;
+ //Connect RemoteObjectSourceIo->remoteObject[Added/Removde] to the registry Slot
+ QObject::connect(q, &QRemoteObjectRegistryHost::remoteObjectAdded, registrySource, &QRegistrySource::addSource);
+ QObject::connect(q, &QRemoteObjectRegistryHost::remoteObjectRemoved, registrySource, &QRegistrySource::removeSource);
+ QObject::connect(remoteObjectIo, &QRemoteObjectSourceIo::serverRemoved, registrySource, &QRegistrySource::removeServer);
+ //onAdd/Remove update the known remoteObjects list in the RegistrySource, so no need to connect to the RegistrySource remoteObjectAdded/Removed signals
+ setRegistry(q->acquire<QRemoteObjectRegistry>());
+ return true;
+ }
+ return false;
+}
+
+/*!
+ Returns the last error set.
+*/
+QRemoteObjectNode::ErrorCode QRemoteObjectNode::lastError() const
+{
+ Q_D(const QRemoteObjectNode);
+ return d->lastError;
+}
+
+/*!
+ \qmlproperty url Node::registryUrl
+
+ The address of the \l {QRemoteObjectRegistry} {Registry} used by this node.
+
+ This is an empty QUrl if there is no registry in use.
+*/
+
+/*!
+ \property QRemoteObjectNode::registryUrl
+ \brief The address of the \l {QRemoteObjectRegistry} {Registry} used by this node.
+
+ This is an empty QUrl if there is no registry in use.
+*/
+QUrl QRemoteObjectNode::registryUrl() const
+{
+ Q_D(const QRemoteObjectNode);
+ return d->registryAddress;
+}
+
+bool QRemoteObjectNode::setRegistryUrl(const QUrl ®istryAddress)
+{
+ Q_D(QRemoteObjectNode);
+ return d->setRegistryUrlNodeImpl(registryAddress);
+}
+
+bool QRemoteObjectNodePrivate::setRegistryUrlNodeImpl(const QUrl ®istryAddr)
+{
+ Q_Q(QRemoteObjectNode);
+ if (registry) {
+ setLastError(QRemoteObjectNode::RegistryAlreadyHosted);
+ return false;
+ }
+
+ registryAddress = registryAddr;
+ setRegistry(q->acquire<QRemoteObjectRegistry>());
+ //Connect remoteObject[Added/Removed] to the registry Slot
+ QObject::connect(q, &QRemoteObjectNode::remoteObjectAdded, registry, &QRemoteObjectRegistry::addSource);
+ QObject::connect(q, &QRemoteObjectNode::remoteObjectRemoved, registry, &QRemoteObjectRegistry::removeSource);
+ q->connectToNode(registryAddress);
+ return true;
+}
+
+void QRemoteObjectNodePrivate::setRegistry(QRemoteObjectRegistry *reg)
+{
+ Q_Q(QRemoteObjectNode);
+ registry = reg;
+ reg->setParent(q);
+ //Make sure when we get the registry initialized, we update our replicas
+ QObject::connect(reg, &QRemoteObjectRegistry::initialized, q, [this]() {
+ onRegistryInitialized();
+ });
+ //Make sure we handle new RemoteObjectSources on Registry...
+ QObject::connect(reg, &QRemoteObjectRegistry::remoteObjectAdded,
+ q, [this](const QRemoteObjectSourceLocation &location) {
+ onRemoteObjectSourceAdded(location);
+ });
+ QObject::connect(reg, &QRemoteObjectRegistry::remoteObjectRemoved,
+ q, [this](const QRemoteObjectSourceLocation &location) {
+ onRemoteObjectSourceRemoved(location);
+ });
+}
+
+QVariant QRemoteObjectNodePrivate::handlePointerToQObjectProperty(QConnectedReplicaImplementation *rep, int index, const QVariant &property)
+{
+ Q_Q(QRemoteObjectNode);
+ using namespace QRemoteObjectPackets;
+
+ QVariant retval;
+
+ Q_ASSERT(property.canConvert<QRO_>());
+ QRO_ childInfo = property.value<QRO_>();
+ qROPrivDebug() << "QRO_:" << childInfo.name << replicas.contains(childInfo.name) << replicas.keys();
+ if (childInfo.isNull) {
+ // Either the source has changed the pointer and we need to update it, or the source pointer is a nullptr
+ if (replicas.contains(childInfo.name))
+ replicas.remove(childInfo.name);
+ if (childInfo.type == ObjectType::CLASS)
+ retval = QVariant::fromValue<QRemoteObjectDynamicReplica*>(nullptr);
+ else
+ retval = QVariant::fromValue<QAbstractItemModelReplica*>(nullptr);
+ return retval;
+ }
+
+ const bool newReplica = !replicas.contains(childInfo.name) || rep->isInitialized();
+ if (newReplica) {
+ if (rep->isInitialized()) {
+ auto childRep = qSharedPointerCast<QConnectedReplicaImplementation>(replicas.take(childInfo.name));
+ if (childRep && !childRep->isShortCircuit()) {
+ qCDebug(QT_REMOTEOBJECT) << "Checking if dynamic type should be added to dynamicTypeManager (type =" << childRep->m_metaObject->className() << ")";
+ dynamicTypeManager.addFromMetaObject(childRep->m_metaObject);
+ }
+ }
+ if (childInfo.type == ObjectType::CLASS)
+ retval = QVariant::fromValue(q->acquireDynamic(childInfo.name));
+ else
+ retval = QVariant::fromValue(q->acquireModel(childInfo.name));
+ } else //We are receiving the initial data for the QObject
+ retval = rep->getProperty(index); //Use existing value so changed signal isn't emitted
+
+ QSharedPointer<QConnectedReplicaImplementation> childRep = qSharedPointerCast<QConnectedReplicaImplementation>(replicas.value(childInfo.name).toStrongRef());
+ if (childRep->connectionToSource.isNull())
+ childRep->connectionToSource = rep->connectionToSource;
+ QVariantList parameters;
+ QDataStream ds(childInfo.parameters);
+ if (childRep->needsDynamicInitialization()) {
+ if (childInfo.classDefinition.isEmpty()) {
+ auto typeName = childInfo.typeName;
+ if (typeName == QLatin1String("QObject")) {
+ // The sender would have included the class name if needed
+ // So the acquire must have been templated, and we have the typeName
+ typeName = QString::fromLatin1(rep->getProperty(index).typeName());
+ if (typeName.endsWith(QLatin1String("Replica*")))
+ typeName.chop(8);
+ }
+ childRep->setDynamicMetaObject(dynamicTypeManager.metaObjectForType(typeName));
+ } else {
+ QDataStream in(childInfo.classDefinition);
+ childRep->setDynamicMetaObject(dynamicTypeManager.addDynamicType(rep->connectionToSource, in));
+ }
+ if (!childInfo.parameters.isEmpty())
+ ds >> parameters;
+ handlePointerToQObjectProperties(childRep.data(), parameters);
+ childRep->setDynamicProperties(std::move(parameters));
+ } else {
+ if (!childInfo.parameters.isEmpty())
+ ds >> parameters;
+ handlePointerToQObjectProperties(childRep.data(), parameters);
+ childRep->initialize(std::move(parameters));
+ }
+
+ return retval;
+}
+
+void QRemoteObjectNodePrivate::handlePointerToQObjectProperties(QConnectedReplicaImplementation *rep, QVariantList &properties)
+{
+ for (const int index : rep->childIndices())
+ properties[index] = handlePointerToQObjectProperty(rep, index, properties.at(index));
+}
+
+/*!
+ Blocks until this Node's \l Registry is initialized or \a timeout (in
+ milliseconds) expires. Returns \c true if the \l Registry is successfully
+ initialized upon return, or \c false otherwise.
+*/
+bool QRemoteObjectNode::waitForRegistry(int timeout)
+{
+ Q_D(QRemoteObjectNode);
+ if (!d->registry) {
+ qCWarning(QT_REMOTEOBJECT) << qPrintable(objectName()) << "waitForRegistry() error: No valid registry url set";
+ return false;
+ }
+
+ return d->registry->waitForSource(timeout);
+}
+
+/*!
+ Connects a client node to the host node at \a address.
+
+ Connections will remain valid until the host node is deleted or no longer
+ accessible over a network.
+
+ Once a client is connected to a host, valid Replicas can then be acquired
+ if the corresponding Source is being remoted.
+
+ Return \c true on success, \c false otherwise (usually an unrecognized url,
+ or connecting to already connected address).
+*/
+bool QRemoteObjectNode::connectToNode(const QUrl &address)
+{
+ Q_D(QRemoteObjectNode);
+ if (!d->initConnection(address)) {
+ d->setLastError(RegistryNotAcquired);
+ return false;
+ }
+ return true;
+}
+
+/*!
+ \since 5.12
+
+ In order to \l QRemoteObjectNode::acquire() \l Replica objects over \l
+ {External QIODevices}, Qt Remote Objects needs access to the communications
+ channel (a \l QIODevice) between the respective nodes. It is the
+ addClientSideConnection() call that enables this, taking the \a ioDevice as
+ input. Any acquire() call made without calling addClientSideConnection will
+ still work, but the Node will not be able to initialize the \l Replica
+ without being provided the connection to the Host node.
+
+ \sa {QRemoteObjectHostBase::addHostSideConnection}
+*/
+void QRemoteObjectNode::addClientSideConnection(QIODevice *ioDevice)
+{
+ Q_D(QRemoteObjectNode);
+ if (!ioDevice || !ioDevice->isOpen()) {
+ qWarning() << "A null or closed QIODevice was passed to addClientSideConnection(). Ignoring.";
+ return;
+ }
+ QtROExternalIoDevice *device = new QtROExternalIoDevice(ioDevice, this);
+ connect(device, &QtROIoDeviceBase::readyRead, this, [d, device]() {
+ d->onClientRead(device);
+ });
+ if (device->bytesAvailable())
+ d->onClientRead(device);
+}
+
+/*!
+ \fn void QRemoteObjectNode::remoteObjectAdded(const QRemoteObjectSourceLocation &loc)
+
+ This signal is emitted whenever a new \l {Source} object is added to
+ the Registry. The signal will not be emitted if there is no Registry set
+ (i.e., Sources over connections made via connectToNode directly). The \a
+ loc parameter contains the information about the added Source, including
+ name, type and the QUrl of the hosting Node.
+
+ \sa remoteObjectRemoved(), instances()
+*/
+
+/*!
+ \fn void QRemoteObjectNode::remoteObjectRemoved(const QRemoteObjectSourceLocation &loc)
+
+ This signal is emitted whenever a known \l {Source} object is
+ removed from the Registry. The signal will not be emitted if there is no
+ Registry set (i.e., Sources over connections made via connectToNode
+ directly). The \a loc parameter contains the information about the removed
+ Source, including name, type and the QUrl of the hosting Node.
+
+ \sa remoteObjectAdded, instances
+*/
+
+/*!
+ \fn QStringList QRemoteObjectNode::instances() const
+
+ This templated function (taking a \l repc generated type as the template parameter) will
+ return the list of names of every instance of that type on the Remote
+ Objects network. For example, if you have a Shape class defined in a .rep file,
+ and Circle and Square classes inherit from the Source definition, they can
+ be shared on the Remote Objects network using \l {QRemoteObjectHostBase::enableRemoting} {enableRemoting}.
+ \code
+ Square square;
+ Circle circle;
+ myHost.enableRemoting(&square, "Square");
+ myHost.enableRemoting(&circle, "Circle");
+ \endcode
+ Then instance can be used to find the available instances of Shape.
+ \code
+ QStringList instances = clientNode.instances<Shape>();
+ // will return a QStringList containing "Circle" and "Square"
+ auto instance1 = clientNode.acquire<Shape>("Circle");
+ auto instance2 = clientNode.acquire<Shape>("Square");
+ ...
+ \endcode
+*/
+
+/*!
+ \overload instances()
+
+ This convenience function provides the same result as the templated
+ version, but takes the name of the \l {Source} class as a parameter (\a
+ typeName) rather than deriving it from the class type.
+*/
+QStringList QRemoteObjectNode::instances(QStringView typeName) const
+{
+ Q_D(const QRemoteObjectNode);
+ QStringList names;
+ for (auto it = d->connectedSources.cbegin(), end = d->connectedSources.cend(); it != end; ++it) {
+ if (it.value().typeName == typeName) {
+ names << it.key();
+ }
+ }
+ return names;
+}
+
+/*!
+ \keyword dynamic acquire
+ Returns a QRemoteObjectDynamicReplica of the Source \a name.
+*/
+QRemoteObjectDynamicReplica *QRemoteObjectNode::acquireDynamic(const QString &name)
+{
+ return new QRemoteObjectDynamicReplica(this, name);
+}
+
+/*!
+ \qmlmethod bool Host::enableRemoting(object object, string name)
+ Enables a host node to dynamically provide remote access to the QObject \a
+ object. Client nodes connected to the node hosting this object may obtain
+ Replicas of this Source.
+
+ The optional \a name defines the lookup-name under which the QObject can be acquired
+ using \l QRemoteObjectNode::acquire() . If not explicitly set then the name
+ given in the QCLASSINFO_REMOTEOBJECT_TYPE will be used. If no such macro
+ was defined for the QObject then the \l QObject::objectName() is used.
+
+ Returns \c false if the current node is a client node, or if the QObject is already
+ registered to be remoted, and \c true if remoting is successfully enabled
+ for the dynamic QObject.
+
+ \sa disableRemoting()
+*/
+
+/*!
+ Enables a host node to dynamically provide remote access to the QObject \a
+ object. Client nodes connected to the node
+ hosting this object may obtain Replicas of this Source.
+
+ The optional \a name defines the lookup-name under which the QObject can be acquired
+ using \l QRemoteObjectNode::acquire() . If not explicitly set then the name
+ given in the QCLASSINFO_REMOTEOBJECT_TYPE will be used. If no such macro
+ was defined for the QObject then the \l QObject::objectName() is used.
+
+ Returns \c false if the current node is a client node, or if the QObject is already
+ registered to be remoted, and \c true if remoting is successfully enabled
+ for the dynamic QObject.
+
+ \sa disableRemoting()
+*/
+bool QRemoteObjectHostBase::enableRemoting(QObject *object, const QString &name)
+{
+ Q_D(QRemoteObjectHostBase);
+ if (!d->remoteObjectIo) {
+ d->setLastError(OperationNotValidOnClientNode);
+ return false;
+ }
+
+ const QMetaObject *meta = object->metaObject();
+ QString _name = name;
+ QString typeName = getTypeNameAndMetaobjectFromClassInfo(meta);
+ if (typeName.isEmpty()) { //This is a passed in QObject, use its API
+ if (_name.isEmpty()) {
+ _name = object->objectName();
+ if (_name.isEmpty()) {
+ d->setLastError(MissingObjectName);
+ qCWarning(QT_REMOTEOBJECT) << qPrintable(objectName()) << "enableRemoting() Error: Unable to Replicate an object that does not have objectName() set.";
+ return false;
+ }
+ }
+ } else if (_name.isEmpty())
+ _name = typeName;
+ return d->remoteObjectIo->enableRemoting(object, meta, _name, typeName);
+}
+
+/*!
+ This overload of enableRemoting() is specific to \l QAbstractItemModel types
+ (or any type derived from \l QAbstractItemModel). This is useful if you want
+ to have a model and the HMI for the model in different processes.
+
+ The three required parameters are the \a model itself, the \a name by which
+ to lookup the model, and the \a roles that should be exposed on the Replica
+ side. If you want to synchronize selection between \l Source and \l
+ Replica, the optional \a selectionModel parameter can be used. This is only
+ recommended when using a single Replica.
+
+ Behind the scenes, Qt Remote Objects batches data() lookups and prefetches
+ data when possible to make the model interaction as responsive as possible.
+
+ Returns \c false if the current node is a client node, or if the QObject is already
+ registered to be remoted, and \c true if remoting is successfully enabled
+ for the QAbstractItemModel.
+
+ \sa disableRemoting()
+ */
+bool QRemoteObjectHostBase::enableRemoting(QAbstractItemModel *model, const QString &name, const QList<int> roles, QItemSelectionModel *selectionModel)
+{
+ //This looks complicated, but hopefully there is a way to have an adapter be a template
+ //parameter and this makes sure that is supported.
+ QObject *adapter = QAbstractItemModelSourceAdapter::staticMetaObject.newInstance(Q_ARG(QAbstractItemModel*, model),
+ Q_ARG(QItemSelectionModel*, selectionModel),
+ Q_ARG(QList<int>, roles));
+ QAbstractItemAdapterSourceAPI<QAbstractItemModel, QAbstractItemModelSourceAdapter> *api =
+ new QAbstractItemAdapterSourceAPI<QAbstractItemModel, QAbstractItemModelSourceAdapter>(name);
+ if (!this->objectName().isEmpty())
+ adapter->setObjectName(this->objectName().append(QLatin1String("Adapter")));
+ return enableRemoting(model, api, adapter);
+}
+
+/*!
+ \fn template <template <typename> class ApiDefinition, typename ObjectType> bool QRemoteObjectHostBase::enableRemoting(ObjectType *object)
+
+ This templated function overload enables a host node to provide remote
+ access to a QObject \a object with a specified (and compile-time checked)
+ interface. Client nodes connected to the node hosting this object may
+ obtain Replicas of this Source.
+
+ This is best illustrated by example:
+ \code
+ #include "rep_TimeModel_source.h"
+ MinuteTimer timer;
+ hostNode.enableRemoting<MinuteTimerSourceAPI>(&timer);
+ \endcode
+
+ Here the MinuteTimerSourceAPI is the set of Signals/Slots/Properties
+ defined by the TimeModel.rep file. Compile time checks are made to verify
+ the input QObject can expose the requested API, it will fail to compile
+ otherwise. This allows a subset of \a object 's interface to be exposed,
+ and allows the types of conversions supported by Signal/Slot connections.
+
+ Returns \c false if the current node is a client node, or if the QObject is
+ already registered to be remoted, and \c true if remoting is successfully
+ enabled for the QObject.
+
+ \sa disableRemoting()
+*/
+
+/*!
+ \internal
+ Enables a host node to provide remote access to a QObject \a object
+ with the API defined by \a api. Client nodes connected to the node
+ hosting this object may obtain Replicas of this Source.
+
+ Returns \c false if the current node is a client node, or if the QObject is
+ already registered to be remoted, and \c true if remoting is successfully
+ enabled for the QObject.
+
+ \sa disableRemoting()
+*/
+bool QRemoteObjectHostBase::enableRemoting(QObject *object, const SourceApiMap *api, QObject *adapter)
+{
+ Q_D(QRemoteObjectHostBase);
+ return d->remoteObjectIo->enableRemoting(object, api, adapter);
+}
+
+/*!
+ \qmlmethod bool Host::disableRemoting(object remoteObject)
+ Disables remote access for the QObject \a remoteObject. Returns \c false if
+ the current node is a client node or if the \a remoteObject is not
+ registered, and returns \c true if remoting is successfully disabled for
+ the Source object.
+
+ \warning Replicas of this object will no longer be valid after calling this method.
+
+ \sa enableRemoting()
+*/
+
+/*!
+ Disables remote access for the QObject \a remoteObject. Returns \c false if
+ the current node is a client node or if the \a remoteObject is not
+ registered, and returns \c true if remoting is successfully disabled for
+ the Source object.
+
+ \warning Replicas of this object will no longer be valid after calling this method.
+
+ \sa enableRemoting()
+*/
+bool QRemoteObjectHostBase::disableRemoting(QObject *remoteObject)
+{
+ Q_D(QRemoteObjectHostBase);
+ if (!d->remoteObjectIo) {
+ d->setLastError(OperationNotValidOnClientNode);
+ return false;
+ }
+
+ if (!d->remoteObjectIo->disableRemoting(remoteObject)) {
+ d->setLastError(SourceNotRegistered);
+ return false;
+ }
+
+ return true;
+}
+
+/*!
+ \since 5.12
+
+ In order to \l QRemoteObjectHost::enableRemoting() \l Source objects over
+ \l {External QIODevices}, Qt Remote Objects needs access to the
+ communications channel (a \l QIODevice) between the respective nodes. It is
+ the addHostSideConnection() call that enables this on the \l Source side,
+ taking the \a ioDevice as input. Any enableRemoting() call will still work
+ without calling addHostSideConnection, but the Node will not be able to
+ share the \l Source objects without being provided the connection to
+ the Replica node. Before calling this function you must call
+ \l {QRemoteObjectHost::}{setHostUrl}() with a unique URL and
+ \l {QRemoteObjectHost::}{AllowExternalRegistration}.
+
+ \sa addClientSideConnection
+*/
+void QRemoteObjectHostBase::addHostSideConnection(QIODevice *ioDevice)
+{
+ Q_D(QRemoteObjectHostBase);
+ if (!ioDevice || !ioDevice->isOpen()) {
+ qWarning() << "A null or closed QIODevice was passed to addHostSideConnection(). Ignoring.";
+ return;
+ }
+ if (!d->remoteObjectIo)
+ d->remoteObjectIo = new QRemoteObjectSourceIo(this);
+ QtROExternalIoDevice *device = new QtROExternalIoDevice(ioDevice, this);
+ return d->remoteObjectIo->newConnection(device);
+}
+
+/*!
+ Returns a pointer to a \l Replica which is specifically derived from \l
+ QAbstractItemModel. The \a name provided must match the name used with the
+ matching \l {QRemoteObjectHostBase::}{enableRemoting} that put
+ the \l Model on the network. \a action specifies whether the model should
+ fetch data before the \l {QRemoteObjectReplica::}{initialized} signal is
+ emitted. If it's set to QtRemoteObjects::PrefetchData, then the data for
+ roles in the \a rolesHint will be prefetched. If \a rolesHint is empty, then
+ the data for all the roles exposed by \l Source will be prefetched.
+
+ The returned model will be empty until it is initialized with the \l Source.
+*/
+QAbstractItemModelReplica *QRemoteObjectNode::acquireModel(const QString &name, QtRemoteObjects::InitialAction action, const QList<int> &rolesHint)
+{
+ QAbstractItemModelReplicaImplementation *rep = acquire<QAbstractItemModelReplicaImplementation>(name);
+ return new QAbstractItemModelReplica(rep, action, rolesHint);
+}
+
+QRemoteObjectHostBasePrivate::QRemoteObjectHostBasePrivate()
+ : QRemoteObjectNodePrivate()
+ , remoteObjectIo(nullptr)
+{ }
+
+QRemoteObjectHostBasePrivate::~QRemoteObjectHostBasePrivate()
+{ }
+
+QRemoteObjectHostPrivate::QRemoteObjectHostPrivate()
+ : QRemoteObjectHostBasePrivate()
+{ }
+
+QRemoteObjectHostPrivate::~QRemoteObjectHostPrivate()
+{ }
+
+QRemoteObjectRegistryHostPrivate::QRemoteObjectRegistryHostPrivate()
+ : QRemoteObjectHostBasePrivate()
+ , registrySource(nullptr)
+{ }
+
+QRemoteObjectRegistryHostPrivate::~QRemoteObjectRegistryHostPrivate()
+{ }
+
+ProxyInfo::ProxyInfo(QRemoteObjectNode *node, QRemoteObjectHostBase *parent,
+ QRemoteObjectHostBase::RemoteObjectNameFilter filter)
+ : QObject(parent)
+ , proxyNode(node)
+ , parentNode(parent)
+ , proxyFilter(filter)
+{
+ const auto registry = node->registry();
+ proxyNode->setObjectName(QString::fromLatin1("_ProxyNode"));
+
+ connect(registry, &QRemoteObjectRegistry::remoteObjectAdded, this,
+ [this](const QRemoteObjectSourceLocation &entry)
+ {
+ this->proxyObject(entry, ProxyDirection::Forward);
+ });
+ connect(registry, &QRemoteObjectRegistry::remoteObjectRemoved, this,
+ &ProxyInfo::unproxyObject);
+ connect(registry, &QRemoteObjectRegistry::initialized, this, [registry, this]() {
+ QRemoteObjectSourceLocations locations = registry->sourceLocations();
+ QRemoteObjectSourceLocations::const_iterator i = locations.constBegin();
+ while (i != locations.constEnd()) {
+ proxyObject(QRemoteObjectSourceLocation(i.key(), i.value()));
+ ++i;
+ }
+ });
+
+ connect(registry, &QRemoteObjectRegistry::stateChanged, this,
+ [this](QRemoteObjectRegistry::State state, QRemoteObjectRegistry::State /*oldState*/) {
+ if (state != QRemoteObjectRegistry::Suspect)
+ return;
+ // unproxy all objects
+ for (ProxyReplicaInfo* info : proxiedReplicas)
+ disableAndDeleteObject(info);
+ proxiedReplicas.clear();
+ });
+}
+
+ProxyInfo::~ProxyInfo() {
+ for (ProxyReplicaInfo* info : proxiedReplicas)
+ delete info;
+ delete proxyNode;
+}
+
+bool ProxyInfo::setReverseProxy(QRemoteObjectHostBase::RemoteObjectNameFilter filter)
+{
+ if (qobject_cast<QRemoteObjectRegistryHost *>(parentNode) == nullptr) {
+ qWarning() << "Setting up reverseProxy() can only be done on a Registry node.";
+ return false;
+ }
+ const auto registry = parentNode->registry();
+ this->reverseFilter = filter;
+
+ connect(registry, &QRemoteObjectRegistry::remoteObjectAdded, this,
+ [this](const QRemoteObjectSourceLocation &entry)
+ {
+ this->proxyObject(entry, ProxyDirection::Reverse);
+ });
+ connect(registry, &QRemoteObjectRegistry::remoteObjectRemoved, this,
+ &ProxyInfo::unproxyObject);
+ connect(registry, &QRemoteObjectRegistry::initialized, this, [registry, this]() {
+ QRemoteObjectSourceLocations locations = registry->sourceLocations();
+ QRemoteObjectSourceLocations::const_iterator i = locations.constBegin();
+ while (i != locations.constEnd()) {
+ proxyObject(QRemoteObjectSourceLocation(i.key(), i.value()), ProxyDirection::Reverse);
+ ++i;
+ }
+ });
+
+ return true;
+}
+
+void ProxyInfo::proxyObject(const QRemoteObjectSourceLocation &entry, ProxyDirection direction)
+{
+ const QString name = entry.first;
+ const QString typeName = entry.second.typeName;
+
+ if (direction == ProxyDirection::Forward) {
+ // If we are using the reverse proxy, this can be called when reverse proxy objects are added
+ // Don't try to proxy those back. We can detect this because the hosting node will be our proxyNode.
+ auto host = qobject_cast<QRemoteObjectHost *>(proxyNode);
+ if (host && entry.second.hostUrl == host->hostUrl())
+ return;
+ if (!proxyFilter(name, typeName))
+ return;
+ Q_ASSERT(!proxiedReplicas.contains(name));
+
+ qCDebug(QT_REMOTEOBJECT) << "Starting proxy for" << name << "from" << entry.second.hostUrl;
+
+ if (entry.second.typeName == QAIMADAPTER()) {
+ QAbstractItemModelReplica *rep = proxyNode->acquireModel(name);
+ proxiedReplicas.insert(name, new ProxyReplicaInfo{rep, direction});
+ connect(rep, &QAbstractItemModelReplica::initialized, this,
+ [rep, name, this]() { this->parentNode->enableRemoting(rep, name, QList<int>()); });
+ } else {
+ QRemoteObjectDynamicReplica *rep = proxyNode->acquireDynamic(name);
+ proxiedReplicas.insert(name, new ProxyReplicaInfo{rep, direction});
+ connect(rep, &QRemoteObjectDynamicReplica::initialized, this,
+ [rep, name, this]() { this->parentNode->enableRemoting(rep, name); });
+ }
+ } else {
+ // If we are using the reverse proxy, this can be called when proxy objects are added
+ // Don't try to proxy those back. We can detect this because the hosting node will be the parentNode.
+ // Since we know the parentNode has to be a RegistryNode for reverse proxy to work, we compare against
+ // the registryUrl().
+ if (entry.second.hostUrl == parentNode->registryUrl())
+ return;
+ if (!reverseFilter(name, typeName))
+ return;
+ Q_ASSERT(!proxiedReplicas.contains(name));
+
+ qCDebug(QT_REMOTEOBJECT) << "Starting reverse proxy for" << name << "from" << entry.second.hostUrl;
+
+ if (entry.second.typeName == QAIMADAPTER()) {
+ QAbstractItemModelReplica *rep = this->parentNode->acquireModel(name);
+ proxiedReplicas.insert(name, new ProxyReplicaInfo{rep, direction});
+ connect(rep, &QAbstractItemModelReplica::initialized, this,
+ [rep, name, this]()
+ {
+ QRemoteObjectHostBase *host = qobject_cast<QRemoteObjectHostBase *>(this->proxyNode);
+ Q_ASSERT(host);
+ host->enableRemoting(rep, name, QList<int>());
+ });
+ } else {
+ QRemoteObjectDynamicReplica *rep = this->parentNode->acquireDynamic(name);
+ proxiedReplicas.insert(name, new ProxyReplicaInfo{rep, direction});
+ connect(rep, &QRemoteObjectDynamicReplica::initialized, this,
+ [rep, name, this]()
+ {
+ QRemoteObjectHostBase *host = qobject_cast<QRemoteObjectHostBase *>(this->proxyNode);
+ Q_ASSERT(host);
+ host->enableRemoting(rep, name);
+ });
+ }
+ }
+
+}
+
+void ProxyInfo::unproxyObject(const QRemoteObjectSourceLocation &entry)
+{
+ const QString name = entry.first;
+
+ if (proxiedReplicas.contains(name)) {
+ qCDebug(QT_REMOTEOBJECT) << "Stopping proxy for" << name;
+ auto const info = proxiedReplicas.take(name);
+ disableAndDeleteObject(info);
+ }
+}
+
+void ProxyInfo::disableAndDeleteObject(ProxyReplicaInfo* info)
+{
+ if (info->direction == ProxyDirection::Forward)
+ this->parentNode->disableRemoting(info->replica);
+ else {
+ QRemoteObjectHostBase *host = qobject_cast<QRemoteObjectHostBase *>(this->proxyNode);
+ Q_ASSERT(host);
+ host->disableRemoting(info->replica);
+ }
+ delete info;
+}
+
+
+QT_END_NAMESPACE
+
+#include "moc_qremoteobjectnode.cpp"
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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.LGPL3 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QREMOTEOBJECTNODE_H
+#define QREMOTEOBJECTNODE_H
+
+#include <QtCore/qsharedpointer.h>
+#include <QtCore/qmetaobject.h>
+#include <QtRemoteObjects/qtremoteobjectglobal.h>
+#include <QtRemoteObjects/qremoteobjectregistry.h>
+#include <QtRemoteObjects/qremoteobjectdynamicreplica.h>
+
+#include <functional>
+
+QT_BEGIN_NAMESPACE
+
+class QRemoteObjectReplica;
+class SourceApiMap;
+class QAbstractItemModel;
+class QAbstractItemModelReplica;
+class QItemSelectionModel;
+class QRemoteObjectAbstractPersistedStorePrivate;
+class QRemoteObjectNodePrivate;
+class QRemoteObjectHostBasePrivate;
+class QRemoteObjectHostPrivate;
+class QRemoteObjectRegistryHostPrivate;
+
+class Q_REMOTEOBJECTS_EXPORT QRemoteObjectAbstractPersistedStore : public QObject
+{
+ Q_OBJECT
+
+public:
+ QRemoteObjectAbstractPersistedStore (QObject *parent = nullptr);
+ virtual ~QRemoteObjectAbstractPersistedStore();
+
+ virtual void saveProperties(const QString &repName, const QByteArray &repSig, const QVariantList &values) = 0;
+ virtual QVariantList restoreProperties(const QString &repName, const QByteArray &repSig) = 0;
+
+protected:
+ QRemoteObjectAbstractPersistedStore(QRemoteObjectAbstractPersistedStorePrivate &, QObject *parent);
+ Q_DECLARE_PRIVATE(QRemoteObjectAbstractPersistedStore)
+};
+
+class Q_REMOTEOBJECTS_EXPORT QRemoteObjectNode : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QUrl registryUrl READ registryUrl WRITE setRegistryUrl)
+ Q_PROPERTY(QRemoteObjectAbstractPersistedStore* persistedStore READ persistedStore WRITE setPersistedStore)
+ Q_PROPERTY(int heartbeatInterval READ heartbeatInterval WRITE setHeartbeatInterval NOTIFY heartbeatIntervalChanged)
+
+public:
+ enum ErrorCode{
+ NoError,
+ RegistryNotAcquired,
+ RegistryAlreadyHosted,
+ NodeIsNoServer,
+ ServerAlreadyCreated,
+ UnintendedRegistryHosting,
+ OperationNotValidOnClientNode,
+ SourceNotRegistered,
+ MissingObjectName,
+ HostUrlInvalid,
+ ProtocolMismatch,
+ ListenFailed
+ };
+ Q_ENUM(ErrorCode)
+
+ QRemoteObjectNode(QObject *parent = nullptr);
+ QRemoteObjectNode(const QUrl ®istryAddress, QObject *parent = nullptr);
+ ~QRemoteObjectNode() override;
+
+ Q_INVOKABLE bool connectToNode(const QUrl &address);
+ void addClientSideConnection(QIODevice *ioDevice);
+ virtual void setName(const QString &name);
+ template < class ObjectType >
+ ObjectType *acquire(const QString &name = QString())
+ {
+ return new ObjectType(this, name);
+ }
+
+ template<typename T>
+ QStringList instances() const
+ {
+ const QMetaObject *mobj = &T::staticMetaObject;
+ const int index = mobj->indexOfClassInfo(QCLASSINFO_REMOTEOBJECT_TYPE);
+ if (index == -1)
+ return QStringList();
+
+ const QString typeName = QString::fromLatin1(mobj->classInfo(index).value());
+ return instances(typeName);
+ }
+ QStringList instances(QStringView typeName) const;
+
+ QRemoteObjectDynamicReplica *acquireDynamic(const QString &name);
+ QAbstractItemModelReplica *acquireModel(const QString &name, QtRemoteObjects::InitialAction action = QtRemoteObjects::FetchRootSize, const QList<int> &rolesHint = {});
+ QUrl registryUrl() const;
+ virtual bool setRegistryUrl(const QUrl ®istryAddress);
+ bool waitForRegistry(int timeout = 30000);
+ const QRemoteObjectRegistry *registry() const;
+
+ QRemoteObjectAbstractPersistedStore *persistedStore() const;
+ void setPersistedStore(QRemoteObjectAbstractPersistedStore *persistedStore);
+
+ ErrorCode lastError() const;
+
+ int heartbeatInterval() const;
+ void setHeartbeatInterval(int interval);
+
+ typedef std::function<void (QUrl)> RemoteObjectSchemaHandler;
+ void registerExternalSchema(const QString &schema, RemoteObjectSchemaHandler handler);
+
+Q_SIGNALS:
+ void remoteObjectAdded(const QRemoteObjectSourceLocation &);
+ void remoteObjectRemoved(const QRemoteObjectSourceLocation &);
+
+ void error(QRemoteObjectNode::ErrorCode errorCode);
+ void heartbeatIntervalChanged(int heartbeatInterval);
+
+protected:
+ QRemoteObjectNode(QRemoteObjectNodePrivate &, QObject *parent);
+
+ void timerEvent(QTimerEvent*) override;
+
+private:
+ void initializeReplica(QRemoteObjectReplica *instance, const QString &name = QString());
+ void persistProperties(const QString &repName, const QByteArray &repSig, const QVariantList &props);
+ QVariantList retrieveProperties(const QString &repName, const QByteArray &repSig);
+
+ Q_DECLARE_PRIVATE(QRemoteObjectNode)
+ friend class QRemoteObjectReplica;
+ friend class QConnectedReplicaImplementation;
+};
+
+class Q_REMOTEOBJECTS_EXPORT QRemoteObjectHostBase : public QRemoteObjectNode
+{
+ Q_OBJECT
+public:
+ enum AllowedSchemas { BuiltInSchemasOnly, AllowExternalRegistration };
+ Q_ENUM(AllowedSchemas)
+ ~QRemoteObjectHostBase() override;
+ void setName(const QString &name) override;
+
+ template <template <typename> class ApiDefinition, typename ObjectType>
+ bool enableRemoting(ObjectType *object)
+ {
+ ApiDefinition<ObjectType> *api = new ApiDefinition<ObjectType>(object);
+ return enableRemoting(object, api);
+ }
+ Q_INVOKABLE bool enableRemoting(QObject *object, const QString &name = QString());
+ bool enableRemoting(QAbstractItemModel *model, const QString &name, const QList<int> roles, QItemSelectionModel *selectionModel = nullptr);
+ Q_INVOKABLE bool disableRemoting(QObject *remoteObject);
+ void addHostSideConnection(QIODevice *ioDevice);
+
+ typedef std::function<bool(QStringView, QStringView)> RemoteObjectNameFilter;
+ bool proxy(const QUrl ®istryUrl, const QUrl &hostUrl={},
+ RemoteObjectNameFilter filter=[](QStringView, QStringView) {return true; });
+ // TODO: Currently the reverse aspect requires the registry, so this is supported only for
+ // QRemoteObjectRegistryHost for now. Consider enabling it also for QRemoteObjectHost.
+ bool reverseProxy(RemoteObjectNameFilter filter=[](QStringView, QStringView) {return true; });
+
+protected:
+ virtual QUrl hostUrl() const;
+ virtual bool setHostUrl(const QUrl &hostAddress, AllowedSchemas allowedSchemas=BuiltInSchemasOnly);
+ QRemoteObjectHostBase(QRemoteObjectHostBasePrivate &, QObject *);
+
+private:
+ bool enableRemoting(QObject *object, const SourceApiMap *, QObject *adapter = nullptr);
+ Q_DECLARE_PRIVATE(QRemoteObjectHostBase)
+};
+
+class Q_REMOTEOBJECTS_EXPORT QRemoteObjectHost : public QRemoteObjectHostBase
+{
+ Q_OBJECT
+ Q_PROPERTY(QUrl hostUrl READ hostUrl WRITE setHostUrl NOTIFY hostUrlChanged)
+
+public:
+ QRemoteObjectHost(QObject *parent = nullptr);
+ QRemoteObjectHost(const QUrl &address, const QUrl ®istryAddress = QUrl(),
+ AllowedSchemas allowedSchemas=BuiltInSchemasOnly, QObject *parent = nullptr);
+ QRemoteObjectHost(const QUrl &address, QObject *parent);
+ ~QRemoteObjectHost() override;
+ QUrl hostUrl() const override;
+ bool setHostUrl(const QUrl &hostAddress, AllowedSchemas allowedSchemas=BuiltInSchemasOnly) override;
+
+Q_SIGNALS:
+ void hostUrlChanged();
+
+protected:
+ QRemoteObjectHost(QRemoteObjectHostPrivate &, QObject *);
+
+private:
+ Q_DECLARE_PRIVATE(QRemoteObjectHost)
+};
+
+class Q_REMOTEOBJECTS_EXPORT QRemoteObjectRegistryHost : public QRemoteObjectHostBase
+{
+ Q_OBJECT
+public:
+ QRemoteObjectRegistryHost(const QUrl ®istryAddress = QUrl(), QObject *parent = nullptr);
+ ~QRemoteObjectRegistryHost() override;
+ bool setRegistryUrl(const QUrl ®istryUrl) override;
+
+protected:
+ QRemoteObjectRegistryHost(QRemoteObjectRegistryHostPrivate &, QObject *);
+
+private:
+ Q_DECLARE_PRIVATE(QRemoteObjectRegistryHost)
+};
+
+QT_END_NAMESPACE
+
+#endif
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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.LGPL3 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QREMOTEOBJECTNODE_P_H
+#define QREMOTEOBJECTNODE_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/private/qobject_p.h>
+#include "qremoteobjectsourceio_p.h"
+#include "qremoteobjectreplica.h"
+#include "qremoteobjectnode.h"
+
+#include <QtCore/qbasictimer.h>
+#include <QtCore/qmutex.h>
+
+QT_BEGIN_NAMESPACE
+
+#define qRODebug(x) qCDebug(QT_REMOTEOBJECT) << qPrintable(QtPrivate::deref_for_methodcall(x).objectName())
+#define qROWarning(x) qCWarning(QT_REMOTEOBJECT) << qPrintable(QtPrivate::deref_for_methodcall(x).objectName())
+#define qROCritical(x) qCCritical(QT_REMOTEOBJECT) << qPrintable(QtPrivate::deref_for_methodcall(x).objectName())
+#define qROFatal(x) qCFatal(QT_REMOTEOBJECT) << qPrintable(QtPrivate::deref_for_methodcall(x).objectName())
+#define qROPrivDebug() qCDebug(QT_REMOTEOBJECT) << qPrintable(q_ptr->objectName())
+#define qROPrivWarning() qCWarning(QT_REMOTEOBJECT) << qPrintable(q_ptr->objectName())
+#define qROPrivCritical() qCCritical(QT_REMOTEOBJECT) << qPrintable(q_ptr->objectName())
+#define qROPrivFatal() qCFatal(QT_REMOTEOBJECT) << qPrintable(q_ptr->objectName())
+
+class QRemoteObjectRegistry;
+class QRegistrySource;
+class QConnectedReplicaImplementation;
+
+class QRemoteObjectAbstractPersistedStorePrivate : public QObjectPrivate
+{
+public:
+ QRemoteObjectAbstractPersistedStorePrivate();
+ virtual ~QRemoteObjectAbstractPersistedStorePrivate();
+
+ Q_DECLARE_PUBLIC(QRemoteObjectAbstractPersistedStore)
+};
+
+class QRemoteObjectMetaObjectManager
+{
+public:
+ QRemoteObjectMetaObjectManager() {}
+ ~QRemoteObjectMetaObjectManager();
+
+ const QMetaObject *metaObjectForType(const QString &type);
+ QMetaObject *addDynamicType(QtROIoDeviceBase* connection, QDataStream &in);
+ void addFromMetaObject(const QMetaObject *);
+
+private:
+ QHash<QString, QMetaObject*> dynamicTypes;
+ QHash<QString, const QMetaObject*> staticTypes;
+ QHash<QtPrivate::QMetaTypeInterface *, QMetaType> enumsToBeAssignedMetaObject;
+ QHash<QMetaObject *, QList<QMetaType>> enumTypes;
+};
+
+struct ProxyReplicaInfo;
+class ProxyInfo : public QObject
+{
+ Q_OBJECT
+public:
+ ProxyInfo(QRemoteObjectNode *node, QRemoteObjectHostBase *parent, QRemoteObjectHostBase::RemoteObjectNameFilter filter);
+ ~ProxyInfo() override;
+ enum class ProxyDirection { Forward, Reverse };
+
+ bool setReverseProxy(QRemoteObjectHostBase::RemoteObjectNameFilter filter);
+ void proxyObject(const QRemoteObjectSourceLocation &entry, ProxyDirection direction = ProxyDirection::Forward);
+ void unproxyObject(const QRemoteObjectSourceLocation &entry);
+
+ QRemoteObjectNode *proxyNode;
+ QRemoteObjectHostBase *parentNode;
+ QRemoteObjectHostBase::RemoteObjectNameFilter proxyFilter;
+ QRemoteObjectHostBase::RemoteObjectNameFilter reverseFilter;
+ QHash<QString, ProxyReplicaInfo*> proxiedReplicas;
+
+private:
+ void disableAndDeleteObject(ProxyReplicaInfo* info);
+};
+
+struct ProxyReplicaInfo
+{
+ // We need QObject, so we can hold Dynamic Replicas and QAIM Adapters
+ QObject* replica;
+ ProxyInfo::ProxyDirection direction;
+ ~ProxyReplicaInfo() { delete replica; }
+};
+
+class QRemoteObjectNodePrivate : public QObjectPrivate
+{
+public:
+ QRemoteObjectNodePrivate();
+ ~QRemoteObjectNodePrivate() override;
+
+ virtual QRemoteObjectSourceLocations remoteObjectAddresses() const;
+
+ void setReplicaImplementation(const QMetaObject *, QRemoteObjectReplica *, const QString &);
+
+ void setLastError(QRemoteObjectNode::ErrorCode errorCode);
+
+ void connectReplica(QObject *object, QRemoteObjectReplica *instance);
+ void openConnectionIfNeeded(const QString &name);
+
+ bool initConnection(const QUrl &address);
+ bool hasInstance(const QString &name);
+ void setRegistry(QRemoteObjectRegistry *);
+ QVariant handlePointerToQObjectProperty(QConnectedReplicaImplementation *rep, int index, const QVariant &property);
+ void handlePointerToQObjectProperties(QConnectedReplicaImplementation *rep, QVariantList &properties);
+
+ void onClientRead(QObject *obj);
+ void onRemoteObjectSourceAdded(const QRemoteObjectSourceLocation &entry);
+ void onRemoteObjectSourceRemoved(const QRemoteObjectSourceLocation &entry);
+ void onRegistryInitialized();
+ void onShouldReconnect(QtROClientIoDevice *ioDevice);
+
+ virtual QReplicaImplementationInterface *handleNewAcquire(const QMetaObject *meta, QRemoteObjectReplica *instance, const QString &name);
+ void handleReplicaConnection(const QString &name);
+ void handleReplicaConnection(const QByteArray &sourceSignature, QConnectedReplicaImplementation *rep, QtROIoDeviceBase *connection);
+ void initialize();
+ bool setRegistryUrlNodeImpl(const QUrl ®istryAddr);
+
+private:
+ bool checkSignatures(const QByteArray &a, const QByteArray &b);
+
+public:
+ struct SourceInfo
+ {
+ QtROIoDeviceBase* device;
+ QString typeName;
+ QByteArray objectSignature;
+ };
+
+ QMutex mutex;
+ QUrl registryAddress;
+ QHash<QString, QWeakPointer<QReplicaImplementationInterface> > replicas;
+ QMap<QString, SourceInfo> connectedSources;
+ QMap<QString, QRemoteObjectNode::RemoteObjectSchemaHandler> schemaHandlers;
+ QSet<QtROClientIoDevice*> pendingReconnect;
+ QSet<QUrl> requestedUrls;
+ QRemoteObjectRegistry *registry;
+ int retryInterval;
+ QBasicTimer reconnectTimer;
+ QRemoteObjectNode::ErrorCode lastError;
+ QString rxName;
+ QRemoteObjectPackets::ObjectInfoList rxObjects;
+ QVariantList rxArgs;
+ QVariant rxValue;
+ QRemoteObjectAbstractPersistedStore *persistedStore;
+ int m_heartbeatInterval = 0;
+ QRemoteObjectMetaObjectManager dynamicTypeManager;
+ Q_DECLARE_PUBLIC(QRemoteObjectNode)
+};
+
+class QRemoteObjectHostBasePrivate : public QRemoteObjectNodePrivate
+{
+public:
+ QRemoteObjectHostBasePrivate();
+ ~QRemoteObjectHostBasePrivate() override;
+ QReplicaImplementationInterface *handleNewAcquire(const QMetaObject *meta, QRemoteObjectReplica *instance, const QString &name) override;
+
+ bool setHostUrlBaseImpl(const QUrl &hostAddress,
+ QRemoteObjectHostBase::AllowedSchemas allowedSchemas =
+ QRemoteObjectHostBase::BuiltInSchemasOnly);
+
+public:
+ QRemoteObjectSourceIo *remoteObjectIo;
+ ProxyInfo *proxyInfo = nullptr;
+ Q_DECLARE_PUBLIC(QRemoteObjectHostBase);
+};
+
+class QRemoteObjectHostPrivate : public QRemoteObjectHostBasePrivate
+{
+public:
+ QRemoteObjectHostPrivate();
+ ~QRemoteObjectHostPrivate() override;
+
+ bool setHostUrlHostImpl(const QUrl &hostAddress,
+ QRemoteObjectHostBase::AllowedSchemas allowedSchemas =
+ QRemoteObjectHostBase::BuiltInSchemasOnly);
+
+ Q_DECLARE_PUBLIC(QRemoteObjectHost);
+};
+
+class QRemoteObjectRegistryHostPrivate : public QRemoteObjectHostBasePrivate
+{
+public:
+ QRemoteObjectRegistryHostPrivate();
+ ~QRemoteObjectRegistryHostPrivate() override;
+ QRemoteObjectSourceLocations remoteObjectAddresses() const override;
+ QRegistrySource *registrySource;
+
+ bool setRegistryUrlRegistryHostImpl(const QUrl ®istryUrl);
+
+ Q_DECLARE_PUBLIC(QRemoteObjectRegistryHost);
+};
+
+QT_END_NAMESPACE
+
+#endif
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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.LGPL3 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtCore/qabstractitemmodel.h>
+#include <QtCore/qbytearrayview.h>
+
+#include "qremoteobjectcontainers_p.h"
+#include "qremoteobjectpendingcall.h"
+#include "qremoteobjectsource.h"
+#include "qremoteobjectsource_p.h"
+#include "qremoteobjectpacket_p.h"
+#include "qconnectionfactories.h"
+#include "qconnectionfactories_p.h"
+#include <cstring>
+
+//#define QTRO_VERBOSE_PROTOCOL
+QT_BEGIN_NAMESPACE
+
+
+// Add methods so we can use QMetaEnum in a set
+// Note for both functions we are skipping string comparisons/hashes. Since the
+// metaObjects are the same, we can just use the address of the string.
+inline bool operator==(const QMetaEnum e1, const QMetaEnum e2)
+{
+ return e1.enclosingMetaObject() == e2.enclosingMetaObject()
+ && e1.name() == e2.name()
+ && e1.enumName() == e2.enumName()
+ && e1.scope() == e2.scope();
+}
+
+inline size_t qHash(const QMetaEnum &key, size_t seed=0) Q_DECL_NOTHROW
+{
+ return qHash(key.enclosingMetaObject(), seed) ^ qHash(static_cast<const void *>(key.name()), seed)
+ ^ qHash(static_cast<const void *>(key.enumName()), seed) ^ qHash(static_cast<const void *>(key.scope()), seed);
+}
+
+static bool isSequentialGadgetType(QMetaType metaType)
+{
+ if (QMetaType::canConvert(metaType, QMetaType::fromType<QSequentialIterable>())) {
+ static QHash<int, bool> lookup;
+ if (!lookup.contains(metaType.id())) {
+ auto stubVariant = QVariant(metaType, nullptr);
+ auto asIterable = stubVariant.value<QSequentialIterable>();
+ auto valueMetaType = asIterable.metaContainer().valueMetaType();
+ lookup[metaType.id()] = valueMetaType.flags().testFlag(QMetaType::IsGadget);
+ }
+ return lookup[metaType.id()];
+ }
+ return false;
+}
+
+static bool isAssociativeGadgetType(QMetaType metaType)
+{
+ if (QMetaType::canConvert(metaType, QMetaType::fromType<QAssociativeIterable>())) {
+ static QHash<int, bool> lookup;
+ if (!lookup.contains(metaType.id())) {
+ auto stubVariant = QVariant(metaType, nullptr);
+ auto asIterable = stubVariant.value<QAssociativeIterable>();
+ auto valueMetaType = asIterable.metaContainer().mappedMetaType();
+ lookup[metaType.id()] = valueMetaType.flags().testFlag(QMetaType::IsGadget);
+ }
+ return lookup[metaType.id()];
+ }
+ return false;
+}
+
+using namespace QtRemoteObjects;
+
+namespace QRemoteObjectPackets {
+
+QMetaType transferTypeForEnum(QMetaType enumType)
+{
+ const auto size = enumType.sizeOf();
+ switch (size) {
+ case 1: return QMetaType::fromType<qint8>();
+ case 2: return QMetaType::fromType<qint16>();
+ case 4: return QMetaType::fromType<qint32>();
+ // Qt currently only supports enum values of 4 or less bytes (QMetaEnum value(index) returns int)
+// case 8: args.push_back(QVariant(QMetaType::Int, argv[i + 1])); break;
+ default:
+ qCWarning(QT_REMOTEOBJECT_IO) << "Invalid enum detected (Dynamic Replica)" << enumType.name() << "with size" << size;
+ return QMetaType::fromType<qint32>();
+ }
+}
+
+// QDataStream sends QVariants of custom types by sending their typename, allowing decode
+// on the receiving side. For QtRO and enums, this won't work, as the enums have different
+// scopes. E.g., the examples have ParentClassSource::MyEnum and ParentClassReplica::MyEnum.
+// Dynamic types will be created as ParentClass::MyEnum. So instead, we change the variants
+// to integers (encodeVariant) when sending them. On the receive side, the we know the
+// types of properties and the signatures for methods, so we can use that information to
+// decode the integer variant into an enum variant (via decodeVariant).
+QVariant encodeVariant(const QVariant &value)
+{
+ const auto metaType = value.metaType();
+ if (metaType.flags().testFlag(QMetaType::IsEnumeration)) {
+ auto converted = QVariant(value);
+ auto transferType = transferTypeForEnum(metaType);
+ converted.convert(transferType);
+#ifdef QTRO_VERBOSE_PROTOCOL
+ qDebug() << "Converting from enum to integer type" << transferType.sizeOf() << converted << value;
+#endif
+ return converted;
+ }
+ if (isSequentialGadgetType(metaType)) { // Doesn't include QtROSequentialContainer
+ // TODO Way to create the QVariant without copying the QSQ_?
+ QSQ_ sequence(value);
+#ifdef QTRO_VERBOSE_PROTOCOL
+ qDebug() << "Encoding sequential container" << metaType.name() << "to QSQ_ to transmit";
+#endif
+ return QVariant::fromValue<QSQ_>(sequence);
+ }
+ if (metaType == QMetaType::fromType<QtROSequentialContainer>()) {
+ QSQ_ sequence(value);
+#ifdef QTRO_VERBOSE_PROTOCOL
+ qDebug() << "Encoding QtROSequentialContainer container to QSQ_ to transmit";
+#endif
+ return QVariant::fromValue<QSQ_>(sequence);
+ }
+ if (isAssociativeGadgetType(metaType)) { // Doesn't include QtROAssociativeContainer
+ QAS_ map(value);
+#ifdef QTRO_VERBOSE_PROTOCOL
+ qDebug() << "Encoding associative container" << metaType.name() << "to QAS_ to transmit";
+#endif
+ return QVariant::fromValue<QAS_>(map);
+ }
+ if (metaType == QMetaType::fromType<QtROAssociativeContainer>()) {
+ QAS_ map(value);
+#ifdef QTRO_VERBOSE_PROTOCOL
+ qDebug() << "Encoding QtROAssociativeContainer container to QAS_ to transmit";
+#endif
+ return QVariant::fromValue<QAS_>(map);
+ }
+ return value;
+}
+
+QVariant decodeVariant(QVariant &&value, QMetaType metaType)
+{
+ if (metaType.flags().testFlag(QMetaType::IsEnumeration)) {
+#ifdef QTRO_VERBOSE_PROTOCOL
+ QVariant encoded(value);
+#endif
+ value.convert(metaType);
+#ifdef QTRO_VERBOSE_PROTOCOL
+ qDebug() << "Converting to enum from integer type" << value << encoded;
+#endif
+ } else if (value.metaType() == QMetaType::fromType<QRemoteObjectPackets::QSQ_>()) {
+ const auto *qsq_ = static_cast<const QRemoteObjectPackets::QSQ_ *>(value.constData());
+ QDataStream in(qsq_->values);
+ auto containerType = QMetaType::fromName(qsq_->typeName.constData());
+ bool isRegistered = containerType.isRegistered();
+ if (isRegistered) {
+ QVariant seq{containerType, nullptr};
+ if (!seq.canView<QSequentialIterable>()) {
+ qWarning() << "Unsupported container" << qsq_->typeName.constData()
+ << "(not viewable)";
+ return QVariant();
+ }
+ QSequentialIterable seqIter = seq.view<QSequentialIterable>();
+ if (!seqIter.metaContainer().canAddValue()) {
+ qWarning() << "Unsupported container" << qsq_->typeName.constData()
+ << "(Unable to add values)";
+ return QVariant();
+ }
+ QByteArray valueTypeName;
+ quint32 count;
+ in >> valueTypeName;
+ in >> count;
+ QMetaType valueType = QMetaType::fromName(valueTypeName.constData());
+ QVariant tmp{valueType, nullptr};
+ for (quint32 i = 0; i < count; i++) {
+ if (!valueType.load(in, tmp.data())) {
+ if (seqIter.metaContainer().canRemoveValue() || i == 0) {
+ for (quint32 ii = 0; ii < i; ii++)
+ seqIter.removeValue();
+ qWarning("QSQ_: unable to load type '%s', returning an empty list.", valueTypeName.constData());
+ } else {
+ qWarning("QSQ_: unable to load type '%s', returning a partial list.", valueTypeName.constData());
+ }
+ break;
+ }
+ seqIter.addValue(tmp);
+ }
+ value = seq;
+#ifdef QTRO_VERBOSE_PROTOCOL
+ qDebug() << "Decoding QSQ_ to sequential container" << containerType.name()
+ << valueTypeName;
+#endif
+ } else {
+ QtROSequentialContainer container{};
+ in >> container;
+ container.m_typeName = qsq_->typeName;
+ value = QVariant(QMetaType::fromType<QtROSequentialContainer>(), &container);
+#ifdef QTRO_VERBOSE_PROTOCOL
+ qDebug() << "Decoding QSQ_ to QtROSequentialContainer of"
+ << container.m_valueTypeName;
+#endif
+ }
+ } else if (value.metaType() == QMetaType::fromType<QRemoteObjectPackets::QAS_>()) {
+ const auto *qas_ = static_cast<const QRemoteObjectPackets::QAS_ *>(value.constData());
+ QDataStream in(qas_->values);
+ auto containerType = QMetaType::fromName(qas_->typeName.constData());
+ bool isRegistered = containerType.isRegistered();
+ if (isRegistered) {
+ QVariant map{containerType, nullptr};
+ if (!map.canView<QAssociativeIterable>()) {
+ qWarning() << "Unsupported container" << qas_->typeName.constData()
+ << "(not viewable)";
+ return QVariant();
+ }
+ QAssociativeIterable mapIter = map.view<QAssociativeIterable>();
+ if (!mapIter.metaContainer().canSetMappedAtKey()) {
+ qWarning() << "Unsupported container" << qas_->typeName.constData()
+ << "(Unable to insert values)";
+ return QVariant();
+ }
+ QByteArray keyTypeName, valueTypeName;
+ quint32 count;
+ in >> keyTypeName;
+ QMetaType keyType = QMetaType::fromName(keyTypeName.constData());
+ if (!keyType.isValid()) {
+ // This happens for class enums, where the passed keyType is <ClassName>::<enum>
+ // For a compiled replica, the keyType is <ClassName>Replica::<enum>
+ // Since the full typename is registered, we can pull the keyType from there
+ keyType = mapIter.metaContainer().keyMetaType();
+ }
+ QMetaType transferType = keyType;
+ if (keyType.flags().testFlag(QMetaType::IsEnumeration))
+ transferType = transferTypeForEnum(keyType);
+ QVariant key{transferType, nullptr};
+ in >> valueTypeName;
+ QMetaType valueType = QMetaType::fromName(valueTypeName.constData());
+ QVariant val{valueType, nullptr};
+ in >> count;
+ for (quint32 i = 0; i < count; i++) {
+ if (!transferType.load(in, key.data())) {
+ map = QVariant{containerType, nullptr};
+ qWarning("QAS_: unable to load key of type '%s', returning an empty map.",
+ keyTypeName.constData());
+ break;
+ }
+ if (!valueType.load(in, val.data())) {
+ map = QVariant{containerType, nullptr};
+ qWarning("QAS_: unable to load value of type '%s', returning an empty map.",
+ valueTypeName.constData());
+ break;
+ }
+ if (transferType != keyType) {
+ QVariant enumKey(key);
+ enumKey.convert(keyType);
+ mapIter.setValue(enumKey, val);
+ } else {
+ mapIter.setValue(key, val);
+ }
+ }
+ value = map;
+#ifdef QTRO_VERBOSE_PROTOCOL
+ qDebug() << "Decoding QAS_ to associative container" << containerType.name()
+ << valueTypeName << keyTypeName << count << mapIter.size() << map;
+#endif
+ } else {
+ QtROAssociativeContainer container{};
+ in >> container;
+ container.m_typeName = qas_->typeName;
+ value = QVariant(QMetaType::fromType<QtROAssociativeContainer>(), &container);
+#ifdef QTRO_VERBOSE_PROTOCOL
+ qDebug() << "Decoding QAS_ to QtROAssociativeContainer of"
+ << container.m_valueTypeName;
+#endif
+ }
+ }
+ return std::move(value);
+}
+
+void QDataStreamCodec::serializeProperty(const QRemoteObjectSourceBase *source, int internalIndex)
+{
+ serializeProperty(m_packet, source, internalIndex);
+}
+
+void QDataStreamCodec::serializeProperty(QDataStream &ds, const QRemoteObjectSourceBase *source, int internalIndex)
+{
+ const int propertyIndex = source->m_api->sourcePropertyIndex(internalIndex);
+ Q_ASSERT (propertyIndex >= 0);
+ const auto target = source->m_api->isAdapterProperty(internalIndex) ? source->m_adapter : source->m_object;
+ const auto property = target->metaObject()->property(propertyIndex);
+ const QVariant value = property.read(target);
+ if (property.metaType().flags().testFlag(QMetaType::PointerToQObject)) {
+ auto const childSource = source->m_children.value(internalIndex);
+ auto valueAsPointerToQObject = qvariant_cast<QObject *>(value);
+ if (childSource->m_object != valueAsPointerToQObject)
+ childSource->resetObject(valueAsPointerToQObject);
+ QRO_ qro(childSource);
+ if (source->d->isDynamic && qro.type == ObjectType::CLASS && childSource->m_object && !source->d->sentTypes.contains(qro.typeName)) {
+ QDataStream classDef(&qro.classDefinition, QIODevice::WriteOnly);
+ serializeDefinition(classDef, childSource);
+ source->d->sentTypes.insert(qro.typeName);
+ }
+ ds << QVariant::fromValue<QRO_>(qro);
+ if (qro.isNull)
+ return;
+ const int propertyCount = childSource->m_api->propertyCount();
+ // Put the properties in a buffer, the receiver may not know how to
+ // interpret the types until it registers new ones.
+ QDataStream params(&qro.parameters, QIODevice::WriteOnly);
+ params << propertyCount;
+ for (int internalIndex = 0; internalIndex < propertyCount; ++internalIndex)
+ serializeProperty(params, childSource, internalIndex);
+ ds << qro.parameters;
+ return;
+ }
+ if (source->d->isDynamic && property.userType() == QMetaType::QVariant
+ && value.metaType().flags().testFlag(QMetaType::IsGadget)) {
+ const auto typeName = QString::fromLatin1(value.metaType().name());
+ if (!source->d->sentTypes.contains(typeName)) {
+ QRO_ qro(value);
+ ds << QVariant::fromValue<QRO_>(qro);
+ ds << qro.parameters;
+ source->d->sentTypes.insert(typeName);
+ return;
+ }
+ }
+ ds << encodeVariant(value);
+}
+
+void QDataStreamCodec::serializeHandshakePacket()
+{
+ m_packet.setId(Handshake);
+ m_packet << QString(protocolVersion);
+ m_packet.finishPacket();
+}
+
+void QDataStreamCodec::serializeInitPacket(const QRemoteObjectRootSource *source)
+{
+ m_packet.setId(InitPacket);
+ m_packet << source->name();
+ serializeProperties(source);
+ m_packet.finishPacket();
+}
+
+void QDataStreamCodec::serializeProperties(const QRemoteObjectSourceBase *source)
+{
+ const SourceApiMap *api = source->m_api;
+
+ //Now copy the property data
+ const int numProperties = api->propertyCount();
+ m_packet << quint32(numProperties); //Number of properties
+
+ for (int internalIndex = 0; internalIndex < numProperties; ++internalIndex)
+ serializeProperty(source, internalIndex);
+}
+
+bool deserializeQVariantList(QDataStream &s, QList<QVariant> &l)
+{
+ // note: optimized version of: QDataStream operator>>(QDataStream& s, QList<T>& l)
+ quint32 c;
+ s >> c;
+
+ const qsizetype count = static_cast<qsizetype>(c);
+ const qsizetype listSize = l.size();
+ if (listSize < count)
+ l.reserve(count);
+ else if (listSize > count)
+ l.resize(count);
+
+ for (int i = 0; i < l.size(); ++i)
+ {
+ if (s.atEnd())
+ return false;
+ s >> l[i];
+ }
+ for (auto i = l.size(); i < count; ++i)
+ {
+ if (s.atEnd())
+ return false;
+ s >> l.emplace_back();
+ }
+ return true;
+}
+
+void QDataStreamCodec::deserializeInitPacket(QDataStream &in, QVariantList &values)
+{
+ const bool success = deserializeQVariantList(in, values);
+ Q_ASSERT(success);
+ Q_UNUSED(success)
+}
+
+void QDataStreamCodec::serializeInitDynamicPacket(const QRemoteObjectRootSource *source)
+{
+ m_packet.setId(InitDynamicPacket);
+ m_packet << source->name();
+ serializeDefinition(m_packet, source);
+ serializeProperties(source);
+ m_packet.finishPacket();
+}
+
+static ObjectType getObjectType(const QString &typeName)
+{
+ if (typeName == QLatin1String("QAbstractItemModelAdapter"))
+ return ObjectType::MODEL;
+ auto tid = QMetaType::fromName(typeName.toUtf8()).id();
+ if (tid == QMetaType::UnknownType)
+ return ObjectType::CLASS;
+ QMetaType type(tid);
+ auto mo = type.metaObject();
+ if (mo && mo->inherits(&QAbstractItemModel::staticMetaObject))
+ return ObjectType::MODEL;
+ return ObjectType::CLASS;
+}
+
+static QByteArrayView resolveEnumName(QMetaType t, bool &isFlag)
+{
+ // Takes types like `MyPOD::Position` or `QFlags<MyPOD::Position>` and returns 'Position`
+ QByteArrayView enumName(t.name());
+ isFlag = enumName.startsWith("QFlags<");
+ auto lastColon = enumName.lastIndexOf(':');
+ if (lastColon >= 0)
+ enumName = QByteArrayView(t.name() + lastColon + 1);
+ if (isFlag)
+ enumName.chop(1);
+ return enumName;
+}
+
+static QMetaEnum metaEnumFromType(QMetaType t)
+{
+ if (t.flags().testFlag(QMetaType::IsEnumeration)) {
+ if (const QMetaObject *m = t.metaObject()) {
+ bool isFlag;
+ auto enumName = resolveEnumName(t, isFlag);
+ if (isFlag) {
+ for (int i = m->enumeratorOffset(); i < m->enumeratorCount(); i++) {
+ auto testType = m->enumerator(i);
+ if (testType.isFlag() &&
+ enumName.compare(QByteArrayView(testType.enumName())) == 0)
+ return testType;
+ }
+ }
+ return m->enumerator(m->indexOfEnumerator(enumName.data()));
+ }
+ }
+ return QMetaEnum();
+}
+
+static bool checkEnum(QMetaType metaType, QSet<QMetaEnum> &enums)
+{
+ if (metaType.flags().testFlag(QMetaType::IsEnumeration)) {
+ QMetaEnum meta = metaEnumFromType(metaType);
+ enums.insert(meta);
+ return true;
+ }
+ return false;
+}
+
+static void recurseMetaobject(const QMetaObject *mo, QSet<const QMetaObject *> &gadgets, QSet<QMetaEnum> &enums)
+{
+ if (!mo || gadgets.contains(mo))
+ return;
+ gadgets.insert(mo);
+ const int numProperties = mo->propertyCount();
+ for (int i = 0; i < numProperties; ++i) {
+ const auto property = mo->property(i);
+ if (checkEnum(property.metaType(), enums))
+ continue;
+ if (property.metaType().flags().testFlag(QMetaType::IsGadget))
+ recurseMetaobject(property.metaType().metaObject(), gadgets, enums);
+ }
+}
+
+// A Source may only use a subset of the metaobjects properties/signals/slots, so we only search
+// the ones in the API. For nested pointer types, we will have another api to limit the search.
+// For nested PODs/enums, we search the entire qobject (using the recurseMetaobject call()).
+void recurseForGadgets(QSet<const QMetaObject *> &gadgets, QSet<QMetaEnum> &enums, const QRemoteObjectSourceBase *source)
+{
+ const SourceApiMap *api = source->m_api;
+
+ const int numSignals = api->signalCount();
+ const int numMethods = api->methodCount();
+ const int numProperties = api->propertyCount();
+
+ for (int si = 0; si < numSignals; ++si) {
+ const int params = api->signalParameterCount(si);
+ for (int pi = 0; pi < params; ++pi) {
+ const int type = api->signalParameterType(si, pi);
+ const auto metaType = QMetaType(type);
+ if (checkEnum(metaType, enums))
+ continue;
+ if (!metaType.flags().testFlag(QMetaType::IsGadget))
+ continue;
+ const auto mo = metaType.metaObject();
+ if (source->d->sentTypes.contains(QLatin1String(mo->className())))
+ continue;
+ recurseMetaobject(mo, gadgets, enums);
+ source->d->sentTypes.insert(QLatin1String(mo->className()));
+ }
+ }
+
+ for (int mi = 0; mi < numMethods; ++mi) {
+ const int params = api->methodParameterCount(mi);
+ for (int pi = 0; pi < params; ++pi) {
+ const int type = api->methodParameterType(mi, pi);
+ const auto metaType = QMetaType(type);
+ if (checkEnum(metaType, enums))
+ continue;
+ if (!metaType.flags().testFlag(QMetaType::IsGadget))
+ continue;
+ const auto mo = metaType.metaObject();
+ if (source->d->sentTypes.contains(QLatin1String(mo->className())))
+ continue;
+ recurseMetaobject(mo, gadgets, enums);
+ source->d->sentTypes.insert(QLatin1String(mo->className()));
+ }
+ }
+ for (int pi = 0; pi < numProperties; ++pi) {
+ const int index = api->sourcePropertyIndex(pi);
+ Q_ASSERT(index >= 0);
+ const auto target = api->isAdapterProperty(pi) ? source->m_adapter : source->m_object;
+ const auto metaProperty = target->metaObject()->property(index);
+ const auto metaType = metaProperty.metaType();
+ if (checkEnum(metaType, enums))
+ continue;
+ if (metaType.flags().testFlag(QMetaType::PointerToQObject)) {
+ auto const objectType = getObjectType(QString::fromLatin1(metaProperty.typeName()));
+ if (objectType == ObjectType::CLASS) {
+ auto const childSource = source->m_children.value(pi);
+ if (childSource->m_object)
+ recurseForGadgets(gadgets, enums, childSource);
+ }
+ }
+ if (!metaType.flags().testFlag(QMetaType::IsGadget))
+ continue;
+ const auto mo = metaType.metaObject();
+ if (source->d->sentTypes.contains(QLatin1String(mo->className())))
+ continue;
+ recurseMetaobject(mo, gadgets, enums);
+ source->d->sentTypes.insert(QLatin1String(mo->className()));
+ }
+}
+
+static bool checkForEnumsInSource(const QMetaObject *meta, const QRemoteObjectSourceBase *source)
+{
+ if (source->m_object->inherits(meta->className()))
+ return true;
+ for (const auto &child : source->m_children) {
+ if (child->m_object && checkForEnumsInSource(meta, child))
+ return true;
+ }
+ return false;
+}
+
+static void serializeEnum(QDataStream &ds, const QMetaEnum &enumerator)
+{
+ ds << QByteArray::fromRawData(enumerator.name(), qsizetype(qstrlen(enumerator.name())));
+ ds << enumerator.isFlag();
+ ds << enumerator.isScoped();
+ const auto typeName = QByteArray(enumerator.scope()).append("::").append(enumerator.name());
+ const quint32 size = quint32(QMetaType::fromName(typeName.constData()).sizeOf());
+ ds << size;
+#ifdef QTRO_VERBOSE_PROTOCOL
+ qDebug(" Enum (name = %s, size = %d, isFlag = %s, isScoped = %s):", enumerator.name(), size, enumerator.isFlag() ? "true" : "false", enumerator.isScoped() ? "true" : "false");
+#endif
+ const int keyCount = enumerator.keyCount();
+ ds << keyCount;
+ for (int k = 0; k < keyCount; ++k) {
+ ds << QByteArray::fromRawData(enumerator.key(k), qsizetype(qstrlen(enumerator.key(k))));
+ ds << enumerator.value(k);
+#ifdef QTRO_VERBOSE_PROTOCOL
+ qDebug(" Key %d (name = %s, value = %d):", k, enumerator.key(k), enumerator.value(k));
+#endif
+ }
+}
+
+static void serializeGadgets(QDataStream &ds, const QSet<const QMetaObject *> &gadgets, const QSet<QMetaEnum> &enums, const QRemoteObjectSourceBase *source=nullptr)
+{
+ // Determine how to handle the enums found
+ QSet<QMetaEnum> qtEnums;
+ QSet<const QMetaObject *> dynamicEnumMetaObjects;
+ for (const auto &metaEnum : enums) {
+ auto const metaObject = metaEnum.enclosingMetaObject();
+ if (gadgets.contains(metaObject)) // Part of a gadget will we serialize
+ continue;
+ // This checks if the enum is defined in our object heirarchy, in which case it will
+ // already have been serialized.
+ if (source && checkForEnumsInSource(metaObject, source->d->root))
+ continue;
+ // qtEnums are enumerations already known by Qt, so we only need register them.
+ // We don't need to send all of the key/value data.
+ if (metaObject == &Qt::staticMetaObject) // Are the other Qt metaclasses for enums?
+ qtEnums.insert(metaEnum);
+ else
+ dynamicEnumMetaObjects.insert(metaEnum.enclosingMetaObject());
+ }
+ ds << quint32(qtEnums.size());
+ for (const auto &metaEnum : qtEnums) {
+ QByteArray enumName(metaEnum.scope());
+ enumName.append("::", 2).append(metaEnum.name());
+ ds << enumName;
+ }
+ const auto allMetaObjects = gadgets + dynamicEnumMetaObjects;
+ ds << quint32(allMetaObjects.size());
+#ifdef QTRO_VERBOSE_PROTOCOL
+ qDebug() << " Found" << gadgets.size() << "gadget/pod and" << (allMetaObjects.size() - gadgets.size()) << "enum types";
+ int i = 0;
+#endif
+ // There isn't an easy way to update a metaobject incrementally, so we
+ // send all of the metaobject's enums, but no properties, when an external
+ // enum is requested.
+ for (auto const meta : allMetaObjects) {
+ ds << QByteArray::fromRawData(meta->className(), qsizetype(qstrlen(meta->className())));
+ int propertyCount = gadgets.contains(meta) ? meta->propertyCount() : 0;
+ ds << quint32(propertyCount);
+#ifdef QTRO_VERBOSE_PROTOCOL
+ qDebug(" Gadget %d (name = %s, # properties = %d, # enums = %d):", i++, meta->className(), propertyCount, meta->enumeratorCount() - meta->enumeratorOffset());
+#endif
+ for (int j = 0; j < propertyCount; j++) {
+ auto prop = meta->property(j);
+#ifdef QTRO_VERBOSE_PROTOCOL
+ qDebug(" Data member %d (name = %s, type = %s):", j, prop.name(), prop.typeName());
+#endif
+ ds << QByteArray::fromRawData(prop.name(), qsizetype(qstrlen(prop.name())));
+ ds << QByteArray::fromRawData(prop.typeName(), qsizetype(qstrlen(prop.typeName())));
+ }
+ int enumCount = meta->enumeratorCount() - meta->enumeratorOffset();
+ ds << quint32(enumCount);
+ for (int j = meta->enumeratorOffset(); j < meta->enumeratorCount(); j++) {
+ auto const enumMeta = meta->enumerator(j);
+ serializeEnum(ds, enumMeta);
+ }
+ }
+}
+
+void QDataStreamCodec::serializeDefinition(QDataStream &ds, const QRemoteObjectSourceBase *source)
+{
+ const SourceApiMap *api = source->m_api;
+ const QByteArray desiredClassName(api->typeName().toLatin1());
+ const QByteArray originalClassName = api->className();
+ // The dynamic class will be called typeName on the receiving side of this definition
+ // However, there are types like enums that have the QObject's class name. Replace()
+ // will convert a parameter such as "ParentClassSource::MyEnum" to "ParentClass::MyEnum"
+ // so the type can be properly resolved and registered.
+ auto replace = [&originalClassName, &desiredClassName](QByteArray &name) {
+ name.replace(originalClassName, desiredClassName);
+ };
+
+ ds << source->m_api->typeName();
+#ifdef QTRO_VERBOSE_PROTOCOL
+ qDebug() << "Serializing definition for" << source->m_api->typeName();
+#endif
+
+ //Now copy the property data
+ const int numEnums = api->enumCount();
+ const auto metaObject = source->m_object->metaObject();
+ ds << quint32(numEnums); //Number of Enums
+#ifdef QTRO_VERBOSE_PROTOCOL
+ qDebug() << " Found" << numEnums << "enumeration types";
+#endif
+ for (int i = 0; i < numEnums; ++i) {
+ auto enumerator = metaObject->enumerator(api->sourceEnumIndex(i));
+ Q_ASSERT(enumerator.isValid());
+ serializeEnum(ds, enumerator);
+ }
+
+ QSet<const QMetaObject *> gadgets;
+ QSet<QMetaEnum> enums;
+ recurseForGadgets(gadgets, enums, source);
+ serializeGadgets(ds, gadgets, enums, source);
+
+ const int numSignals = api->signalCount();
+ ds << quint32(numSignals); //Number of signals
+ for (int i = 0; i < numSignals; ++i) {
+ const int index = api->sourceSignalIndex(i);
+ Q_ASSERT(index >= 0);
+ auto signature = api->signalSignature(i);
+ replace(signature);
+ const int count = api->signalParameterCount(i);
+ for (int pi = 0; pi < count; ++pi) {
+ const auto metaType = QMetaType(api->signalParameterType(i, pi));
+ if (isSequentialGadgetType(metaType))
+ signature.replace(metaType.name(), "QtROSequentialContainer");
+ else if (isAssociativeGadgetType(metaType))
+ signature.replace(metaType.name(), "QtROAssociativeContainer");
+ }
+#ifdef QTRO_VERBOSE_PROTOCOL
+ qDebug() << " Signal" << i << "(signature =" << signature << "parameter names =" << api->signalParameterNames(i) << ")";
+#endif
+ ds << signature;
+ ds << api->signalParameterNames(i);
+ }
+
+ const int numMethods = api->methodCount();
+ ds << quint32(numMethods); //Number of methods
+ for (int i = 0; i < numMethods; ++i) {
+ const int index = api->sourceMethodIndex(i);
+ Q_ASSERT(index >= 0);
+ auto signature = api->methodSignature(i);
+ replace(signature);
+ const int count = api->methodParameterCount(i);
+ for (int pi = 0; pi < count; ++pi) {
+ const auto metaType = QMetaType(api->methodParameterType(i, pi));
+ if (isSequentialGadgetType(metaType))
+ signature.replace(metaType.name(), "QtROSequentialContainer");
+ else if (isAssociativeGadgetType(metaType))
+ signature.replace(metaType.name(), "QtROAssociativeContainer");
+ }
+ auto typeName = api->typeName(i);
+ replace(typeName);
+#ifdef QTRO_VERBOSE_PROTOCOL
+ qDebug() << " Slot" << i << "(signature =" << signature << "parameter names =" << api->methodParameterNames(i) << "return type =" << typeName << ")";
+#endif
+ ds << signature;
+ ds << typeName;
+ ds << api->methodParameterNames(i);
+ }
+
+ const int numProperties = api->propertyCount();
+ ds << quint32(numProperties); //Number of properties
+ for (int i = 0; i < numProperties; ++i) {
+ const int index = api->sourcePropertyIndex(i);
+ Q_ASSERT(index >= 0);
+
+ const auto target = api->isAdapterProperty(i) ? source->m_adapter : source->m_object;
+ const auto metaProperty = target->metaObject()->property(index);
+ ds << metaProperty.name();
+#ifdef QTRO_VERBOSE_PROTOCOL
+ qDebug() << " Property" << i << "name =" << metaProperty.name();
+#endif
+ if (metaProperty.metaType().flags().testFlag(QMetaType::PointerToQObject)) {
+ auto objectType = getObjectType(QLatin1String(metaProperty.typeName()));
+ ds << (objectType == ObjectType::CLASS ? "QObject*" : "QAbstractItemModel*");
+#ifdef QTRO_VERBOSE_PROTOCOL
+ qDebug() << " Type:" << (objectType == ObjectType::CLASS ? "QObject*" : "QAbstractItemModel*");
+#endif
+ } else {
+ if (isSequentialGadgetType(metaProperty.metaType())) {
+ ds << "QtROSequentialContainer";
+#ifdef QTRO_VERBOSE_PROTOCOL
+ qDebug() << " Type:" << "QtROSequentialContainer";
+#endif
+ } else if (isAssociativeGadgetType(metaProperty.metaType())) {
+ ds << "QtROAssociativeContainer";
+#ifdef QTRO_VERBOSE_PROTOCOL
+ qDebug() << " Type:" << "QtROAssociativeContainer";
+#endif
+ } else {
+ ds << metaProperty.typeName();
+#ifdef QTRO_VERBOSE_PROTOCOL
+ qDebug() << " Type:" << metaProperty.typeName();
+#endif
+ }
+ }
+ if (metaProperty.notifySignalIndex() == -1) {
+ ds << QByteArray();
+#ifdef QTRO_VERBOSE_PROTOCOL
+ qDebug() << " Notification signal: None";
+#endif
+ } else {
+ auto signature = metaProperty.notifySignal().methodSignature();
+ replace(signature);
+ ds << signature;
+#ifdef QTRO_VERBOSE_PROTOCOL
+ qDebug() << " Notification signal:" << signature;
+#endif
+ }
+ }
+}
+
+void QDataStreamCodec::serializeAddObjectPacket(const QString &name, bool isDynamic)
+{
+ m_packet.setId(AddObject);
+ m_packet << name;
+ m_packet << isDynamic;
+ m_packet.finishPacket();
+}
+
+void QDataStreamCodec::deserializeAddObjectPacket(QDataStream &ds, bool &isDynamic)
+{
+ ds >> isDynamic;
+}
+
+void QDataStreamCodec::serializeRemoveObjectPacket(const QString &name)
+{
+ m_packet.setId(RemoveObject);
+ m_packet << name;
+ m_packet.finishPacket();
+}
+//There is no deserializeRemoveObjectPacket - no parameters other than id and name
+
+void QDataStreamCodec::serializeInvokePacket(const QString &name, int call, int index, const QVariantList &args, int serialId, int propertyIndex)
+{
+ m_packet.setId(InvokePacket);
+ m_packet << name;
+ m_packet << call;
+ m_packet << index;
+
+ m_packet << quint32(args.size());
+ for (const auto &arg : args)
+ m_packet << encodeVariant(arg);
+
+ m_packet << serialId;
+ m_packet << propertyIndex;
+ m_packet.finishPacket();
+}
+
+void QDataStreamCodec::deserializeInvokePacket(QDataStream& in, int &call, int &index, QVariantList &args, int &serialId, int &propertyIndex)
+{
+ in >> call;
+ in >> index;
+ const bool success = deserializeQVariantList(in, args);
+ Q_ASSERT(success);
+ Q_UNUSED(success)
+ in >> serialId;
+ in >> propertyIndex;
+}
+
+void QDataStreamCodec::serializeInvokeReplyPacket(const QString &name, int ackedSerialId, const QVariant &value)
+{
+ m_packet.setId(InvokeReplyPacket);
+ m_packet << name;
+ m_packet << ackedSerialId;
+ m_packet << value;
+ m_packet.finishPacket();
+}
+
+void QDataStreamCodec::deserializeInvokeReplyPacket(QDataStream& in, int &ackedSerialId, QVariant &value){
+ in >> ackedSerialId;
+ in >> value;
+}
+
+void QDataStreamCodec::serializePropertyChangePacket(QRemoteObjectSourceBase *source, int signalIndex)
+{
+ int internalIndex = source->m_api->propertyRawIndexFromSignal(signalIndex);
+ m_packet.setId(PropertyChangePacket);
+ m_packet << source->name();
+ m_packet << internalIndex;
+ serializeProperty(source, internalIndex);
+ m_packet.finishPacket();
+}
+
+void QDataStreamCodec::deserializePropertyChangePacket(QDataStream& in, int &index, QVariant &value)
+{
+ in >> index;
+ in >> value;
+}
+
+void QDataStreamCodec::serializeObjectListPacket(const ObjectInfoList &objects)
+{
+ m_packet.setId(ObjectList);
+ m_packet << objects;
+ m_packet.finishPacket();
+}
+
+void QDataStreamCodec::deserializeObjectListPacket(QDataStream &in, ObjectInfoList &objects)
+{
+ in >> objects;
+}
+
+void QDataStreamCodec::serializePingPacket(const QString &name)
+{
+ m_packet.setId(Ping);
+ m_packet << name;
+ m_packet.finishPacket();
+}
+
+void QDataStreamCodec::serializePongPacket(const QString &name)
+{
+ m_packet.setId(Pong);
+ m_packet << name;
+ m_packet.finishPacket();
+}
+
+QRO_::QRO_(QRemoteObjectSourceBase *source)
+ : name(source->name())
+ , typeName(source->m_api->typeName())
+ , type(source->m_adapter ? ObjectType::MODEL : getObjectType(typeName))
+ , isNull(source->m_object == nullptr)
+ , classDefinition()
+ , parameters()
+{}
+
+QRO_::QRO_(const QVariant &value)
+ : type(ObjectType::GADGET)
+ , isNull(false)
+{
+ const auto metaType = value.metaType();
+ auto meta = metaType.metaObject();
+ QDataStream out(&classDefinition, QIODevice::WriteOnly);
+ const int numProperties = meta->propertyCount();
+ const auto name = metaType.name();
+ const auto typeName = QByteArray::fromRawData(name, qsizetype(qstrlen(name)));
+ out << quint32(0) << quint32(1);
+ out << typeName;
+ out << numProperties;
+#ifdef QTRO_VERBOSE_PROTOCOL
+ qDebug("Serializing POD definition to QRO_ (name = %s)", typeName.constData());
+#endif
+ for (int i = 0; i < numProperties; ++i) {
+ const auto property = meta->property(i);
+#ifdef QTRO_VERBOSE_PROTOCOL
+ qDebug(" Data member %d (name = %s, type = %s):", i, property.name(), property.typeName());
+#endif
+ out << QByteArray::fromRawData(property.name(), qsizetype(qstrlen(property.name())));
+ out << QByteArray::fromRawData(property.typeName(), qsizetype(qstrlen(property.typeName())));
+ }
+ int enumCount = meta->enumeratorCount() - meta->enumeratorOffset();
+ out << quint32(enumCount);
+ for (int j = meta->enumeratorOffset(); j < meta->enumeratorCount(); j++) {
+ auto const enumMeta = meta->enumerator(j);
+ serializeEnum(out, enumMeta);
+ }
+ QDataStream ds(¶meters, QIODevice::WriteOnly);
+ ds << value;
+#ifdef QTRO_VERBOSE_PROTOCOL
+ qDebug() << " Value:" << value;
+#endif
+}
+
+QDataStream &operator<<(QDataStream &stream, const QRO_ &info)
+{
+ stream << info.name << info.typeName << quint8(info.type) << info.classDefinition << info.isNull;
+ qCDebug(QT_REMOTEOBJECT) << "Serializing " << info;
+ // info.parameters will be filled in by serializeProperty
+ return stream;
+}
+
+QDataStream &operator>>(QDataStream &stream, QRO_ &info)
+{
+ quint8 tmpType;
+ stream >> info.name >> info.typeName >> tmpType >> info.classDefinition >> info.isNull;
+ info.type = static_cast<ObjectType>(tmpType);
+ qCDebug(QT_REMOTEOBJECT) << "Deserializing " << info;
+ if (!info.isNull)
+ stream >> info.parameters;
+ return stream;
+}
+
+QSQ_::QSQ_(const QVariant &variant)
+{
+ QSequentialIterable sequence;
+ QMetaType valueType;
+ if (variant.metaType() == QMetaType::fromType<QtROSequentialContainer>()) {
+ auto container = static_cast<const QtROSequentialContainer *>(variant.constData());
+ typeName = container->m_typeName;
+ valueType = container->m_valueType;
+ valueTypeName = container->m_valueTypeName;
+ sequence = QSequentialIterable(reinterpret_cast<const QVariantList *>(variant.constData()));
+ } else {
+ sequence = variant.value<QSequentialIterable>();
+ typeName = QByteArray(variant.metaType().name());
+ valueType = sequence.metaContainer().valueMetaType();
+ valueTypeName = QByteArray(valueType.name());
+ }
+#ifdef QTRO_VERBOSE_PROTOCOL
+ qDebug("Serializing POD sequence to QSQ_ (type = %s, valueType = %s) with size = %lld",
+ typeName.constData(), valueTypeName.constData(), sequence.size());
+#endif
+ QDataStream ds(&values, QIODevice::WriteOnly);
+ ds << valueTypeName;
+ auto pos = ds.device()->pos();
+ ds << quint32(sequence.size());
+ for (const auto &v : sequence) {
+ if (!valueType.save(ds, v.data())) {
+ ds.device()->seek(pos);
+ ds.resetStatus();
+ ds << quint32(0);
+ values.resize(ds.device()->pos());
+ qWarning("QSQ_: unable to save type '%s', sending empty list.", valueType.name());
+ break;
+ }
+ }
+}
+
+QDataStream &operator<<(QDataStream &stream, const QSQ_ &sequence)
+{
+ stream << sequence.typeName << sequence.valueTypeName << sequence.values;
+ qCDebug(QT_REMOTEOBJECT) << "Serializing " << sequence;
+ return stream;
+}
+
+QDataStream &operator>>(QDataStream &stream, QSQ_ &sequence)
+{
+ stream >> sequence.typeName >> sequence.valueTypeName >> sequence.values;
+ qCDebug(QT_REMOTEOBJECT) << "Deserializing " << sequence;
+ return stream;
+}
+
+QAS_::QAS_(const QVariant &variant)
+{
+ QAssociativeIterable map;
+ QMetaType keyType, transferType, valueType;
+ const QtROAssociativeContainer *container = nullptr;
+ if (variant.metaType() == QMetaType::fromType<QtROAssociativeContainer>()) {
+ container = static_cast<const QtROAssociativeContainer *>(variant.constData());
+ typeName = container->m_typeName;
+ keyType = container->m_keyType;
+ keyTypeName = container->m_keyTypeName;
+ valueType = container->m_valueType;
+ valueTypeName = container->m_valueTypeName;
+ map = QAssociativeIterable(reinterpret_cast<const QVariantMap *>(variant.constData()));
+ } else {
+ map = variant.value<QAssociativeIterable>();
+ typeName = QByteArray(variant.metaType().name());
+ keyType = map.metaContainer().keyMetaType();
+ keyTypeName = QByteArray(keyType.name());
+ valueType = map.metaContainer().mappedMetaType();
+ valueTypeName = QByteArray(valueType.name());
+ }
+ // Special handling for enums...
+ transferType = keyType;
+ if (keyType.flags().testFlag(QMetaType::IsEnumeration)) {
+ transferType = transferTypeForEnum(keyType);
+ auto meta = keyType.metaObject();
+ // If we are the source, make sure the typeName is converted for any downstream replicas
+ // the `meta` variable will be non-null when the enum is a class enum
+ if (meta && !container) {
+ const int ind = meta->indexOfClassInfo(QCLASSINFO_REMOTEOBJECT_TYPE);
+ if (ind >= 0) {
+ bool isFlag = keyTypeName.startsWith("QFlags<");
+ if (isFlag || keyTypeName.startsWith(meta->className())) {
+#ifdef QTRO_VERBOSE_PROTOCOL
+ QByteArray orig(keyTypeName);
+#endif
+ if (isFlag) {
+ // Q_DECLARE_FLAGS(Flags, Enum) -> `typedef QFlags<Enum> Flags;`
+ // We know we have an enum for `Flags` because we sent the enums
+ // from the source, so we just need to look up the alias.
+ keyTypeName = keyTypeName.mid(7);
+ keyTypeName.chop(1); // Remove trailing '>'
+ int index = keyTypeName.lastIndexOf(':');
+ for (int i = meta->enumeratorOffset(); i < meta->enumeratorCount(); i++) {
+ auto en = meta->enumerator(i);
+ auto name = keyTypeName.data() + index + 1;
+ if (en.isFlag() && qstrcmp(en.enumName(), name) == 0)
+ keyTypeName.replace(index + 1, qstrlen(en.enumName()), en.name());
+ }
+ }
+ keyTypeName.replace(meta->className(), meta->classInfo(ind).value());
+ QByteArray repName(meta->classInfo(ind).value());
+ repName.append("Replica");
+ typeName.replace(meta->className(), repName);
+#ifdef QTRO_VERBOSE_PROTOCOL
+ qDebug() << "Converted map key typename from" << orig << "to" << keyTypeName;
+#endif
+ }
+ }
+ }
+ }
+
+#ifdef QTRO_VERBOSE_PROTOCOL
+ qDebug("Serializing POD map to QAS_ (type = %s, keyType = %s, valueType = %s), size = %lld",
+ typeName.constData(), keyTypeName.constData(), valueTypeName.constData(),
+ map.size());
+#endif
+ QDataStream ds(&values, QIODevice::WriteOnly);
+ ds << keyTypeName;
+ ds << valueTypeName;
+ auto pos = ds.device()->pos();
+ ds << quint32(map.size());
+ QAssociativeIterable::const_iterator iter = map.begin();
+ for (int i = 0; i < map.size(); i++) {
+ QVariant key(container ? container->m_keys.at(i) : iter.key());
+ if (transferType != keyType)
+ key.convert(transferType);
+ if (!transferType.save(ds, key.data())) {
+ ds.device()->seek(pos);
+ ds.resetStatus();
+ ds << quint32(0);
+ values.resize(ds.device()->pos());
+ qWarning("QAS_: unable to save key '%s', sending empty map.", keyType.name());
+ break;
+ }
+ if (!valueType.save(ds, iter.value().data())) {
+ ds.device()->seek(pos);
+ ds.resetStatus();
+ ds << quint32(0);
+ values.resize(ds.device()->pos());
+ qWarning("QAS_: unable to save value '%s', sending empty map.", valueType.name());
+ break;
+ }
+ iter++;
+ }
+}
+
+QDataStream &operator<<(QDataStream &stream, const QAS_ &map)
+{
+ stream << map.typeName << map.keyTypeName << map.valueTypeName << map.values;
+ qCDebug(QT_REMOTEOBJECT) << "Serializing " << map;
+ return stream;
+}
+
+QDataStream &operator>>(QDataStream &stream, QAS_ &map)
+{
+ stream >> map.typeName >> map.keyTypeName >> map.valueTypeName >> map.values;
+ qCDebug(QT_REMOTEOBJECT) << "Deserializing " << map;
+ return stream;
+}
+
+DataStreamPacket::DataStreamPacket(quint16 id)
+ : QDataStream(&array, QIODevice::WriteOnly), baseAddress(0), size(0)
+{
+ this->setVersion(QtRemoteObjects::dataStreamVersion);
+ this->setByteOrder(QDataStream::LittleEndian);
+ *this << quint32(0);
+ *this << id;
+}
+
+void CodecBase::send(const QSet<QtROIoDeviceBase *> &connections)
+{
+ const auto bytearray = getPayload();
+ for (auto conn : connections)
+ conn->write(bytearray);
+ reset();
+}
+
+void CodecBase::send(const QList<QtROIoDeviceBase *> &connections)
+{
+ const auto bytearray = getPayload();
+ for (auto conn : connections)
+ conn->write(bytearray);
+ reset();
+}
+
+void CodecBase::send(QtROIoDeviceBase *connection)
+{
+ const auto bytearray = getPayload();
+ connection->write(bytearray);
+ reset();
+}
+
+} // namespace QRemoteObjectPackets
+
+QT_END_NAMESPACE
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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.LGPL3 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QTREMOTEOBJECTPACKET_P_H
+#define QTREMOTEOBJECTPACKET_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qtremoteobjectglobal.h"
+#include "qremoteobjectsource.h"
+#include "qconnectionfactories.h"
+
+#include <QtCore/qassociativeiterable.h>
+#include <QtCore/qhash.h>
+#include <QtCore/qmap.h>
+#include <QtCore/qpair.h>
+#include <QtCore/qsequentialiterable.h>
+#include <QtCore/qurl.h>
+#include <QtCore/qvariant.h>
+#include <QtCore/qloggingcategory.h>
+#include <QtCore/qdatastream.h>
+
+#include <cstdlib>
+
+QT_BEGIN_NAMESPACE
+
+class QMetaObjectBuilder;
+class QRemoteObjectSourceBase;
+class QRemoteObjectRootSource;
+
+namespace QRemoteObjectPackets {
+
+Q_NAMESPACE
+
+class DataStreamPacket;
+
+struct ObjectInfo
+{
+ QString name;
+ QString typeName;
+ QByteArray signature;
+};
+
+inline QDebug operator<<(QDebug dbg, const ObjectInfo &info)
+{
+ dbg.nospace() << "ObjectInfo(" << info.name << ", " << info.typeName << ", " << info.signature <<")";
+ return dbg.space();
+}
+
+inline QDataStream& operator<<(QDataStream &stream, const ObjectInfo &info)
+{
+ return stream << info.name << info.typeName << info.signature;
+}
+
+inline QDataStream& operator>>(QDataStream &stream, ObjectInfo &info)
+{
+ return stream >> info.name >> info.typeName >> info.signature;
+}
+
+using ObjectInfoList = QList<ObjectInfo>;
+
+enum class ObjectType : quint8 { CLASS, MODEL, GADGET };
+Q_ENUM_NS(ObjectType)
+
+// Use a short name, as QVariant::save writes the name every time a qvariant of
+// this type is serialized
+class QRO_
+{
+public:
+ QRO_() : type(ObjectType::CLASS), isNull(true) {}
+ explicit QRO_(QRemoteObjectSourceBase *source);
+ explicit QRO_(const QVariant &value);
+ QString name, typeName;
+ ObjectType type;
+ bool isNull;
+ QByteArray classDefinition;
+ QByteArray parameters;
+};
+
+inline QDebug operator<<(QDebug dbg, const QRO_ &info)
+{
+ dbg.nospace() << "QRO_(name: " << info.name << ", typeName: " << info.typeName << ", type: " << info.type
+ << ", valid: " << (info.isNull ? "true" : "false") << ", paremeters: {" << info.parameters <<")"
+ << (info.classDefinition.isEmpty() ? " no definitions)" : " with definitions)");
+ return dbg.space();
+}
+
+QDataStream& operator<<(QDataStream &stream, const QRO_ &info);
+
+QDataStream& operator>>(QDataStream &stream, QRO_ &info);
+
+// Class for transmitting sequence data. Needed because containers for custom
+// types (and even primitive types in Qt5) are not registered with the metaObject
+// system. This wrapper allows us to create the desired container if it is
+// registered, or a QtROSequentialContainer if it is not. QtROSequentialContainer
+// is derived from QVariantList, so it can be used from QML similar to the API
+// type.
+class QSQ_
+{
+public:
+ QSQ_() {}
+ explicit QSQ_(const QVariant &lst);
+ QByteArray typeName, valueTypeName;
+ QByteArray values;
+};
+
+inline QDebug operator<<(QDebug dbg, const QSQ_ &seq)
+{
+ dbg.nospace() << "QSQ_(typeName: " << seq.typeName << ", valueType: " << seq.valueTypeName
+ << ", values: {" << seq.values <<")";
+ return dbg.space();
+}
+
+QDataStream& operator<<(QDataStream &stream, const QSQ_ &info);
+
+QDataStream& operator>>(QDataStream &stream, QSQ_ &info);
+
+// Class for transmitting associative containers. Needed because containers for
+// custom types (and even primitive types in Qt5) are not registered with the
+// metaObject system. This wrapper allows us to create the desired container if
+// it is registered, or a QtROAssociativeContainer if it is not.
+// QtROAssociativeContainer is derived from QVariantMap, so it can be used from
+// QML similar to the API type.
+class QAS_
+{
+public:
+ QAS_() {}
+ explicit QAS_(const QVariant &lst);
+ QByteArray typeName, keyTypeName, valueTypeName;
+ QByteArray values;
+};
+
+inline QDebug operator<<(QDebug dbg, const QAS_ &seq)
+{
+ dbg.nospace() << "QAS_(typeName: " << seq.typeName << ", keyType: " << seq.keyTypeName
+ << ", valueType: " << seq.valueTypeName << ", values: {" << seq.values <<")";
+ return dbg.space();
+}
+
+QDataStream& operator<<(QDataStream &stream, const QAS_ &info);
+
+QDataStream& operator>>(QDataStream &stream, QAS_ &info);
+
+//Helper class for creating a QByteArray from a QRemoteObjectPacket
+class DataStreamPacket : public QDataStream
+{
+public:
+ DataStreamPacket(quint16 id = QtRemoteObjects::InvokePacket);
+
+ void setId(quint16 id)
+ {
+ device()->seek(baseAddress);
+ *this << quint32(0);
+ *this << id;
+ }
+
+ void finishPacket()
+ {
+ size = device()->pos();
+ device()->seek(baseAddress);
+ *this << quint32(size - baseAddress - sizeof(quint32));
+ baseAddress = size; // Allow appending until reset() is called
+ }
+
+ const QByteArray &payload()
+ {
+ array.resize(size);
+ return array;
+ }
+
+ void reset()
+ {
+ baseAddress = 0;
+ size = 0;
+ array.clear();
+ }
+
+private:
+ QByteArray array;
+ int baseAddress;
+ int size;
+
+ Q_DISABLE_COPY(DataStreamPacket)
+};
+
+class CodecBase
+{
+public:
+ CodecBase() = default;
+ CodecBase(const CodecBase &) = default;
+ CodecBase(CodecBase &&) = default;
+ CodecBase &operator=(const CodecBase &) = default;
+ CodecBase &operator=(CodecBase &&) = default;
+ virtual ~CodecBase() = default;
+
+ virtual void serializeObjectListPacket(const ObjectInfoList &) = 0;
+ virtual void deserializeObjectListPacket(QDataStream &in, ObjectInfoList &) = 0;
+ virtual void serializeInitPacket(const QRemoteObjectRootSource *) = 0;
+ virtual void serializeInitDynamicPacket(const QRemoteObjectRootSource *) = 0;
+ virtual void serializePropertyChangePacket(QRemoteObjectSourceBase *source,
+ int signalIndex) = 0;
+ virtual void deserializePropertyChangePacket(QDataStream &in, int &index, QVariant &value) = 0;
+ virtual void serializeProperty(const QRemoteObjectSourceBase *source, int internalIndex) = 0;
+ // Heartbeat packets
+ virtual void serializePingPacket(const QString &name) = 0;
+ virtual void serializePongPacket(const QString &name) = 0;
+ virtual void serializeInvokePacket(const QString &name, int call, int index,
+ const QVariantList &args, int serialId = -1,
+ int propertyIndex = -1) = 0;
+ virtual void deserializeInvokePacket(QDataStream &in, int &call, int &index, QVariantList &args,
+ int &serialId, int &propertyIndex) = 0;
+ virtual void serializeInvokeReplyPacket(const QString &name, int ackedSerialId,
+ const QVariant &value) = 0;
+ virtual void serializeHandshakePacket() = 0;
+ virtual void serializeRemoveObjectPacket(const QString &name) = 0;
+ //There is no deserializeRemoveObjectPacket - no parameters other than id and name
+ virtual void serializeAddObjectPacket(const QString &name, bool isDynamic) = 0;
+ virtual void deserializeAddObjectPacket(QDataStream &, bool &isDynamic) = 0;
+ virtual void deserializeInitPacket(QDataStream &, QVariantList &) = 0;
+ virtual void deserializeInvokeReplyPacket(QDataStream &in, int &ackedSerialId,
+ QVariant &value) = 0;
+ void send(const QSet<QtROIoDeviceBase *> &connections);
+ void send(const QVector<QtROIoDeviceBase *> &connections);
+ void send(QtROIoDeviceBase *connection);
+
+protected:
+ // A payload can consist of one or more packets
+ virtual const QByteArray &getPayload() = 0;
+ virtual void reset() {}
+};
+
+class QDataStreamCodec : public CodecBase
+{
+public:
+ void serializeObjectListPacket(const ObjectInfoList &) override;
+ void deserializeObjectListPacket(QDataStream &in, ObjectInfoList &) override;
+ void serializeInitPacket(const QRemoteObjectRootSource *) override;
+ void serializeInitDynamicPacket(const QRemoteObjectRootSource*) override;
+ void serializePropertyChangePacket(QRemoteObjectSourceBase *source, int signalIndex) override;
+ void deserializePropertyChangePacket(QDataStream &in, int &index, QVariant &value) override;
+ void serializeProperty(const QRemoteObjectSourceBase *source, int internalIndex) override;
+ void serializePingPacket(const QString &name) override;
+ void serializePongPacket(const QString &name) override;
+ void serializeInvokePacket(const QString &name, int call, int index, const QVariantList &args,
+ int serialId = -1, int propertyIndex = -1) override;
+ void deserializeInvokePacket(QDataStream &in, int &call, int &index, QVariantList &args,
+ int &serialId, int &propertyIndex) override;
+ void serializeInvokeReplyPacket(const QString &name, int ackedSerialId,
+ const QVariant &value) override;
+ void serializeHandshakePacket() override;
+ void serializeRemoveObjectPacket(const QString &name) override;
+ void serializeAddObjectPacket(const QString &name, bool isDynamic) override;
+ void deserializeAddObjectPacket(QDataStream &, bool &isDynamic) override;
+ void deserializeInitPacket(QDataStream &, QVariantList &) override;
+ void deserializeInvokeReplyPacket(QDataStream &in, int &ackedSerialId,
+ QVariant &value) override;
+
+protected:
+ const QByteArray &getPayload() override {
+ return m_packet.payload();
+ }
+ void reset() override {
+ m_packet.reset();
+ }
+private:
+ void serializeDefinition(QDataStream &, const QRemoteObjectSourceBase *);
+ void serializeProperty(QDataStream &ds, const QRemoteObjectSourceBase *source, int internalIndex);
+ void serializeProperties(const QRemoteObjectSourceBase *source);
+ DataStreamPacket m_packet;
+};
+
+QMetaType transferTypeForEnum(QMetaType enumType);
+QVariant encodeVariant(const QVariant &value);
+QVariant decodeVariant(QVariant &&value, QMetaType metaType);
+
+} // namespace QRemoteObjectPackets
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(QRemoteObjectPackets::QRO_)
+
+#endif
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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.LGPL3 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qremoteobjectpendingcall.h"
+#include "qremoteobjectpendingcall_p.h"
+
+#include "qremoteobjectreplica_p.h"
+
+#include <QtCore/qcoreapplication.h>
+
+#include <private/qobject_p.h>
+
+QT_BEGIN_NAMESPACE
+
+QRemoteObjectPendingCallData::QRemoteObjectPendingCallData(int serialId, QRemoteObjectReplicaImplementation *replica)
+ : replica(replica)
+ , serialId(serialId)
+ , error(QRemoteObjectPendingCall::InvalidMessage)
+ , watcherHelper(nullptr)
+{
+}
+
+QRemoteObjectPendingCallData::~QRemoteObjectPendingCallData()
+{
+}
+
+void QRemoteObjectPendingCallWatcherHelper::add(QRemoteObjectPendingCallWatcher *watcher)
+{
+ connect(this, &QRemoteObjectPendingCallWatcherHelper::finished, watcher, [watcher]() {
+ emit watcher->finished(watcher);
+ }, Qt::QueuedConnection);
+}
+
+void QRemoteObjectPendingCallWatcherHelper::emitSignals()
+{
+ emit finished();
+}
+
+/*!
+ \class QRemoteObjectPendingCall
+ \inmodule QtRemoteObjects
+ \brief Encapsulates the result of an asynchronous method call.
+*/
+
+QRemoteObjectPendingCall::QRemoteObjectPendingCall()
+ : d(new QRemoteObjectPendingCallData)
+{
+}
+
+QRemoteObjectPendingCall::~QRemoteObjectPendingCall()
+{
+}
+
+QRemoteObjectPendingCall::QRemoteObjectPendingCall(const QRemoteObjectPendingCall& other)
+ : d(other.d)
+{
+}
+
+QRemoteObjectPendingCall::QRemoteObjectPendingCall(QRemoteObjectPendingCallData *dd)
+ : d(dd)
+{
+}
+
+QRemoteObjectPendingCall &QRemoteObjectPendingCall::operator=(const QRemoteObjectPendingCall &other)
+{
+ d = other.d;
+ return *this;
+}
+
+/*!
+ Returns the return value of the remote call.
+
+ returnValue will only be valid when the remote call has finished and there
+ are no \l {error}s.
+*/
+QVariant QRemoteObjectPendingCall::returnValue() const
+{
+ if (!d)
+ return QVariant();
+
+ QMutexLocker locker(&d->mutex);
+ return d->returnValue;
+}
+
+/*!
+ \enum QRemoteObjectPendingCall::Error
+
+ This enum type specifies the possible error values for a remote call:
+
+ \value NoError
+ No error occurred.
+ \value InvalidMessage
+ The default error state prior to the remote call finishing.
+*/
+
+/*!
+ Returns the error, if any, from the remote call.
+*/
+QRemoteObjectPendingCall::Error QRemoteObjectPendingCall::error() const
+{
+ if (!d)
+ return QRemoteObjectPendingCall::InvalidMessage;
+
+ QMutexLocker locker(&d->mutex);
+ return d->error;
+}
+
+/*!
+ Returns true if the remote call has finished, false otherwise.
+
+ A finished call will include a returnValue or \l error.
+*/
+bool QRemoteObjectPendingCall::isFinished() const
+{
+ if (!d)
+ return true; // considered finished
+
+ QMutexLocker locker(&d->mutex);
+ return d->error != InvalidMessage;
+}
+
+/*!
+ Blocks for up to \a timeout milliseconds, until the remote call has finished.
+
+ Returns \c true on success, \c false otherwise.
+*/
+bool QRemoteObjectPendingCall::waitForFinished(int timeout)
+{
+ if (!d)
+ return false;
+
+ if (d->error != QRemoteObjectPendingCall::InvalidMessage)
+ return true; // already finished
+
+ QMutexLocker locker(&d->mutex);
+ if (!d->replica)
+ return false;
+
+ return d->replica->waitForFinished(*this, timeout);
+}
+
+QRemoteObjectPendingCall QRemoteObjectPendingCall::fromCompletedCall(const QVariant &returnValue)
+{
+ QRemoteObjectPendingCallData *data = new QRemoteObjectPendingCallData;
+ data->returnValue = returnValue;
+ data->error = NoError;
+ return QRemoteObjectPendingCall(data);
+}
+
+class QRemoteObjectPendingCallWatcherPrivate: public QObjectPrivate
+{
+public:
+ Q_DECLARE_PUBLIC(QRemoteObjectPendingCallWatcher)
+};
+
+/*!
+ \class QRemoteObjectPendingCallWatcher
+ \inmodule QtRemoteObjects
+ \brief Provides a QObject-based API for watching a QRemoteObjectPendingCall.
+
+ QRemoteObjectPendingCallWatcher provides a signal indicating when a QRemoteObjectPendingCall
+ has finished, allowing for convenient, non-blocking handling of the call.
+*/
+
+QRemoteObjectPendingCallWatcher::QRemoteObjectPendingCallWatcher(const QRemoteObjectPendingCall &call, QObject *parent)
+ : QObject(*new QRemoteObjectPendingCallWatcherPrivate, parent)
+ , QRemoteObjectPendingCall(call)
+{
+ if (d) {
+ QMutexLocker locker(&d->mutex);
+ if (!d->watcherHelper) {
+ d->watcherHelper.reset(new QRemoteObjectPendingCallWatcherHelper);
+ if (d->error != QRemoteObjectPendingCall::InvalidMessage) {
+ // cause a signal emission anyways
+ QMetaObject::invokeMethod(d->watcherHelper.data(), "finished", Qt::QueuedConnection);
+ }
+ }
+ d->watcherHelper->add(this);
+ }
+}
+
+QRemoteObjectPendingCallWatcher::~QRemoteObjectPendingCallWatcher()
+{
+}
+
+/*!
+ Returns true if the remote call has finished, false otherwise.
+
+ A finished call will include a returnValue or error.
+*/
+bool QRemoteObjectPendingCallWatcher::isFinished() const
+{
+ if (!d)
+ return true; // considered finished
+
+ QMutexLocker locker(&d->mutex);
+ return d->error != QRemoteObjectPendingCall::InvalidMessage;
+}
+
+/*!
+ Blocks until the remote call has finished.
+*/
+void QRemoteObjectPendingCallWatcher::waitForFinished()
+{
+ if (d) {
+ QRemoteObjectPendingCall::waitForFinished();
+
+ // our signals were queued, so deliver them
+ QCoreApplication::sendPostedEvents(d->watcherHelper.data(), QEvent::MetaCall);
+ QCoreApplication::sendPostedEvents(this, QEvent::MetaCall);
+ }
+}
+
+/*!
+ \fn QRemoteObjectPendingCallWatcher::finished(QRemoteObjectPendingCallWatcher *self)
+
+ This signal is emitted when the remote call has finished. \a self is the pointer to
+ the watcher object that emitted the signal. A finished call will include a
+ returnValue or error.
+*/
+
+/*!
+ \class QRemoteObjectPendingReply
+ \inmodule QtRemoteObjects
+ \brief A templated version of QRemoteObjectPendingCall.
+*/
+
+/*! \fn template <typename T> T QRemoteObjectPendingReply<T>::returnValue() const
+
+ Returns a strongly typed version of the return value of the remote call.
+*/
+
+QT_END_NAMESPACE
+
+#include "moc_qremoteobjectpendingcall.cpp"
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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.LGPL3 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QREMOTEOBJECTPENDINGCALL_H
+#define QREMOTEOBJECTPENDINGCALL_H
+
+#include <QtRemoteObjects/qtremoteobjectglobal.h>
+
+#include <QtCore/qvariant.h>
+
+QT_BEGIN_NAMESPACE
+
+class QRemoteObjectPendingCallWatcherPrivate;
+class QRemoteObjectPendingCallData;
+
+class Q_REMOTEOBJECTS_EXPORT QRemoteObjectPendingCall
+{
+public:
+ enum Error {
+ NoError,
+ InvalidMessage
+ };
+
+ QRemoteObjectPendingCall();
+ QRemoteObjectPendingCall(const QRemoteObjectPendingCall &other);
+ ~QRemoteObjectPendingCall();
+
+ QRemoteObjectPendingCall &operator=(const QRemoteObjectPendingCall &other);
+
+ QVariant returnValue() const;
+ QRemoteObjectPendingCall::Error error() const;
+
+ bool isFinished() const;
+
+ bool waitForFinished(int timeout = 30000);
+
+ static QRemoteObjectPendingCall fromCompletedCall(const QVariant &returnValue);
+
+protected:
+ QRemoteObjectPendingCall(QRemoteObjectPendingCallData *dd);
+
+ /// Shared data, note: might be null
+ QExplicitlySharedDataPointer<QRemoteObjectPendingCallData> d;
+
+private:
+ friend class QConnectedReplicaImplementation;
+};
+
+QT_END_NAMESPACE
+Q_DECLARE_METATYPE(QRemoteObjectPendingCall)
+QT_BEGIN_NAMESPACE
+
+class Q_REMOTEOBJECTS_EXPORT QRemoteObjectPendingCallWatcher: public QObject, public QRemoteObjectPendingCall
+{
+ Q_OBJECT
+
+public:
+ QRemoteObjectPendingCallWatcher(const QRemoteObjectPendingCall &call, QObject *parent = nullptr);
+ ~QRemoteObjectPendingCallWatcher() override;
+
+ bool isFinished() const;
+
+ void waitForFinished();
+
+Q_SIGNALS:
+ void finished(QRemoteObjectPendingCallWatcher *self);
+
+private:
+ Q_DECLARE_PRIVATE(QRemoteObjectPendingCallWatcher)
+};
+
+template<typename T>
+class QRemoteObjectPendingReply : public QRemoteObjectPendingCall
+{
+public:
+ typedef T Type;
+
+ QRemoteObjectPendingReply() = default;
+ explicit QRemoteObjectPendingReply(const QRemoteObjectPendingCall &call)
+ : QRemoteObjectPendingCall(call)
+ {
+ }
+
+ QRemoteObjectPendingReply &operator=(const QRemoteObjectPendingCall &other)
+ {
+ QRemoteObjectPendingCall::operator=(other);
+ return *this;
+ }
+
+ Type returnValue() const
+ {
+ return qvariant_cast<Type>(QRemoteObjectPendingCall::returnValue());
+ }
+
+};
+
+QT_END_NAMESPACE
+
+#endif
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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.LGPL3 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QREMOTEOBJECTPENDINGCALL_P_H
+#define QREMOTEOBJECTPENDINGCALL_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qremoteobjectpendingcall.h"
+
+#include <QtCore/qmutex.h>
+
+QT_BEGIN_NAMESPACE
+
+class QRemoteObjectPendingCallWatcherHelper;
+class QRemoteObjectReplicaImplementation;
+
+class QRemoteObjectPendingCallData : public QSharedData
+{
+public:
+ typedef QExplicitlySharedDataPointer<QRemoteObjectPendingCallData> Ptr;
+
+ explicit QRemoteObjectPendingCallData(int serialId = -1, QRemoteObjectReplicaImplementation *replica = nullptr);
+ ~QRemoteObjectPendingCallData();
+
+ QRemoteObjectReplicaImplementation *replica;
+ int serialId;
+
+ QVariant returnValue;
+ QRemoteObjectPendingCall::Error error;
+
+ mutable QMutex mutex;
+
+ mutable QScopedPointer<QRemoteObjectPendingCallWatcherHelper> watcherHelper;
+};
+
+class QRemoteObjectPendingCallWatcherHelper: public QObject
+{
+ Q_OBJECT
+public:
+ void add(QRemoteObjectPendingCallWatcher *watcher);
+
+ void emitSignals();
+
+Q_SIGNALS:
+ void finished();
+};
+
+QT_END_NAMESPACE
+
+#endif
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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.LGPL3 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qremoteobjectregistry.h"
+#include "qremoteobjectreplica_p.h"
+
+#include <private/qobject_p.h>
+#include <QtCore/qset.h>
+#include <QtCore/qdatastream.h>
+
+QT_BEGIN_NAMESPACE
+
+class QRemoteObjectRegistryPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QRemoteObjectRegistry)
+
+ QRemoteObjectSourceLocations sourceLocationsActualCalculation() const
+ {
+ return q_func()->propAsVariant(0).value<QRemoteObjectSourceLocations>();
+ }
+ Q_OBJECT_COMPUTED_PROPERTY(QRemoteObjectRegistryPrivate, QRemoteObjectSourceLocations,
+ sourceLocations,
+ &QRemoteObjectRegistryPrivate::sourceLocationsActualCalculation)
+ QRemoteObjectSourceLocations hostedSources;
+};
+
+/*!
+ \class QRemoteObjectRegistry
+ \inmodule QtRemoteObjects
+ \brief A class holding information about \l {Source} objects available on the Qt Remote Objects network.
+
+ The Registry is a special Source/Replica pair held by a \l
+ {QRemoteObjectNode} {node} itself. It knows about all other \l {Source}s
+ available on the network, and simplifies the process of connecting to other
+ \l {QRemoteObjectNode} {node}s.
+*/
+QRemoteObjectRegistry::QRemoteObjectRegistry(QObject *parent)
+ : QRemoteObjectReplica(*new QRemoteObjectRegistryPrivate, parent)
+{
+ connect(this, &QRemoteObjectRegistry::stateChanged, this, &QRemoteObjectRegistry::pushToRegistryIfNeeded);
+}
+
+QRemoteObjectRegistry::QRemoteObjectRegistry(QRemoteObjectNode *node, const QString &name, QObject *parent)
+ : QRemoteObjectReplica(*new QRemoteObjectRegistryPrivate, parent)
+{
+ connect(this, &QRemoteObjectRegistry::stateChanged, this, &QRemoteObjectRegistry::pushToRegistryIfNeeded);
+ initializeNode(node, name);
+}
+
+/*!
+ \fn void QRemoteObjectRegistry::remoteObjectAdded(const QRemoteObjectSourceLocation &entry)
+
+ This signal is emitted whenever a new source location is added to the registry.
+
+ \a entry is a QRemoteObjectSourceLocation, a typedef for QPair<QString, QUrl>.
+
+ \sa remoteObjectRemoved()
+*/
+
+/*!
+ \fn void QRemoteObjectRegistry::remoteObjectRemoved(const QRemoteObjectSourceLocation &entry)
+
+ This signal is emitted whenever a Source location is removed from the Registry.
+
+ \a entry is a QRemoteObjectSourceLocation, a typedef for QPair<QString, QUrl>.
+
+ \sa remoteObjectAdded()
+*/
+
+/*!
+ \property QRemoteObjectRegistry::sourceLocations
+ \brief The set of sources known to the registry.
+
+ This property is a QRemoteObjectSourceLocations, which is a typedef for
+ QHash<QString, QUrl>. Each known \l Source is the QString key, while the
+ url for the host node is the corresponding value for that key in the hash.
+*/
+
+/*!
+ Destructor for QRemoteObjectRegistry.
+*/
+QRemoteObjectRegistry::~QRemoteObjectRegistry()
+{}
+
+void QRemoteObjectRegistry::registerMetatypes()
+{
+ static bool initialized = false;
+ if (initialized)
+ return;
+ initialized = true;
+ qRegisterMetaType<QRemoteObjectSourceLocation>();
+ qRegisterMetaType<QRemoteObjectSourceLocations>();
+}
+
+void QRemoteObjectRegistry::initialize()
+{
+ QRemoteObjectRegistry::registerMetatypes();
+ QVariantList properties;
+ properties.reserve(3);
+ properties << QVariant::fromValue(QRemoteObjectSourceLocations());
+ properties << QVariant::fromValue(QRemoteObjectSourceLocation());
+ properties << QVariant::fromValue(QRemoteObjectSourceLocation());
+ setProperties(std::move(properties));
+}
+
+void QRemoteObjectRegistry::notifySourceLocationsChanged()
+{
+ d_func()->sourceLocations.notify();
+}
+
+/*!
+ Returns a QRemoteObjectSourceLocations object, which includes the name
+ and additional information of all sources known to the registry.
+*/
+QRemoteObjectSourceLocations QRemoteObjectRegistry::sourceLocations() const
+{
+ return d_func()->sourceLocations.value();
+}
+
+QBindable<QRemoteObjectSourceLocations> QRemoteObjectRegistry::bindableSourceLocations() const
+{
+ return &d_func()->sourceLocations;
+}
+
+/*!
+ \internal
+*/
+void QRemoteObjectRegistry::addSource(const QRemoteObjectSourceLocation &entry)
+{
+ Q_D(QRemoteObjectRegistry);
+ if (d->hostedSources.contains(entry.first)) {
+ qCWarning(QT_REMOTEOBJECT) << "Node warning: ignoring source" << entry.first
+ << "as this node already has a source by that name.";
+ return;
+ }
+ d->hostedSources.insert(entry.first, entry.second);
+ if (state() != QRemoteObjectReplica::State::Valid)
+ return;
+
+ if (sourceLocations().contains(entry.first)) {
+ qCWarning(QT_REMOTEOBJECT) << "Node warning: ignoring source" << entry.first
+ << "as another source (" << sourceLocations().value(entry.first)
+ << ") has already registered that name.";
+ return;
+ }
+ qCDebug(QT_REMOTEOBJECT) << "An entry was added to the registry - Sending to source" << entry.first << entry.second;
+ // This does not set any data to avoid a coherency problem between client and server
+ static int index = QRemoteObjectRegistry::staticMetaObject.indexOfMethod("addSource(QRemoteObjectSourceLocation)");
+ QVariantList args;
+ args << QVariant::fromValue(entry);
+ send(QMetaObject::InvokeMetaMethod, index, args);
+}
+
+/*!
+ \internal
+*/
+void QRemoteObjectRegistry::removeSource(const QRemoteObjectSourceLocation &entry)
+{
+ Q_D(QRemoteObjectRegistry);
+ if (!d->hostedSources.contains(entry.first))
+ return;
+
+ d->hostedSources.remove(entry.first);
+ if (state() != QRemoteObjectReplica::State::Valid)
+ return;
+
+ qCDebug(QT_REMOTEOBJECT) << "An entry was removed from the registry - Sending to source" << entry.first << entry.second;
+ // This does not set any data to avoid a coherency problem between client and server
+ static int index = QRemoteObjectRegistry::staticMetaObject.indexOfMethod("removeSource(QRemoteObjectSourceLocation)");
+ QVariantList args;
+ args << QVariant::fromValue(entry);
+ send(QMetaObject::InvokeMetaMethod, index, args);
+}
+
+/*!
+ \internal
+ This internal function supports the edge case where the \l Registry
+ is connected after \l Source objects are added to this \l Node, or
+ the connection to the \l Registry is lost. When connected/reconnected, this
+ function synchronizes local \l Source objects with the \l Registry.
+*/
+void QRemoteObjectRegistry::pushToRegistryIfNeeded()
+{
+ Q_D(QRemoteObjectRegistry);
+ if (state() != QRemoteObjectReplica::State::Valid)
+ return;
+
+ if (d->hostedSources.isEmpty())
+ return;
+
+ const auto &sourceLocs = sourceLocations();
+ for (auto it = d->hostedSources.begin(); it != d->hostedSources.end(); ) {
+ const QString &loc = it.key();
+ const auto sourceLocsIt = sourceLocs.constFind(loc);
+ if (sourceLocsIt != sourceLocs.cend()) {
+ qCWarning(QT_REMOTEOBJECT) << "Node warning: Ignoring Source" << loc << "as another source ("
+ << sourceLocsIt.value() << ") has already registered that name.";
+ it = d->hostedSources.erase(it);
+ } else {
+ static const int index = QRemoteObjectRegistry::staticMetaObject.indexOfMethod("addSource(QRemoteObjectSourceLocation)");
+ QVariantList args{QVariant::fromValue(QRemoteObjectSourceLocation(loc, it.value()))};
+ send(QMetaObject::InvokeMetaMethod, index, args);
+ ++it;
+ }
+ }
+}
+
+QT_END_NAMESPACE
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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.LGPL3 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QREMOTEOBJECTREGISTRY_P_H
+#define QREMOTEOBJECTREGISTRY_P_H
+
+#include <QtRemoteObjects/qremoteobjectreplica.h>
+
+QT_BEGIN_NAMESPACE
+
+class QRemoteObjectRegistryPrivate;
+class QRemoteObjectNodePrivate;
+
+class Q_REMOTEOBJECTS_EXPORT QRemoteObjectRegistry : public QRemoteObjectReplica
+{
+ Q_OBJECT
+ Q_CLASSINFO(QCLASSINFO_REMOTEOBJECT_TYPE, "Registry")
+
+ Q_PROPERTY(QRemoteObjectSourceLocations sourceLocations READ sourceLocations STORED false
+ BINDABLE bindableSourceLocations)
+
+public:
+ ~QRemoteObjectRegistry() override;
+ static void registerMetatypes();
+
+ QRemoteObjectSourceLocations sourceLocations() const;
+ QBindable<QRemoteObjectSourceLocations> bindableSourceLocations() const;
+
+Q_SIGNALS:
+ void remoteObjectAdded(const QRemoteObjectSourceLocation &entry);
+ void remoteObjectRemoved(const QRemoteObjectSourceLocation &entry);
+
+protected Q_SLOTS:
+ void addSource(const QRemoteObjectSourceLocation &entry);
+ void removeSource(const QRemoteObjectSourceLocation &entry);
+ void pushToRegistryIfNeeded();
+
+private:
+ void initialize() override;
+ void notifySourceLocationsChanged();
+
+ explicit QRemoteObjectRegistry(QObject *parent = nullptr);
+ explicit QRemoteObjectRegistry(QRemoteObjectNode *node, const QString &name, QObject *parent = nullptr);
+
+ Q_DECLARE_PRIVATE(QRemoteObjectRegistry)
+ friend class QT_PREPEND_NAMESPACE(QRemoteObjectNode);
+ friend class QT_PREPEND_NAMESPACE(QRemoteObjectNodePrivate);
+};
+
+QT_END_NAMESPACE
+
+#endif
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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.LGPL3 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qremoteobjectregistrysource_p.h"
+#include <QtCore/qdatastream.h>
+
+QT_BEGIN_NAMESPACE
+
+QRegistrySource::QRegistrySource(QObject *parent)
+ : QObject(parent)
+{
+}
+
+QRegistrySource::~QRegistrySource()
+{
+}
+
+QRemoteObjectSourceLocations QRegistrySource::sourceLocations() const
+{
+ qCDebug(QT_REMOTEOBJECT) << "sourceLocations property requested on RegistrySource" << m_sourceLocations;
+ return m_sourceLocations;
+}
+
+void QRegistrySource::removeServer(const QUrl &url)
+{
+ for (auto it = m_sourceLocations.begin(), end = m_sourceLocations.end(); it != end; /* erasing */) {
+ if (it.value().hostUrl == url)
+ it = m_sourceLocations.erase(it);
+ else
+ ++it;
+ }
+}
+
+void QRegistrySource::addSource(const QRemoteObjectSourceLocation &entry)
+{
+ qCDebug(QT_REMOTEOBJECT) << "An entry was added to the RegistrySource" << entry;
+ if (m_sourceLocations.contains(entry.first)) {
+ if (m_sourceLocations[entry.first].hostUrl == entry.second.hostUrl)
+ qCWarning(QT_REMOTEOBJECT) << "Node warning: Ignoring Source" << entry.first
+ << "as this Node already has a Source by that name.";
+ else
+ qCWarning(QT_REMOTEOBJECT) << "Node warning: Ignoring Source" << entry.first
+ << "as another source (" << m_sourceLocations[entry.first]
+ << ") has already registered that name.";
+ return;
+ }
+ m_sourceLocations[entry.first] = entry.second;
+ emit remoteObjectAdded(entry);
+}
+
+void QRegistrySource::removeSource(const QRemoteObjectSourceLocation &entry)
+{
+ if (m_sourceLocations.contains(entry.first) && m_sourceLocations[entry.first].hostUrl == entry.second.hostUrl) {
+ m_sourceLocations.remove(entry.first);
+ emit remoteObjectRemoved(entry);
+ }
+}
+
+QT_END_NAMESPACE
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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.LGPL3 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QREGISTRYSOURCE_P_H
+#define QREGISTRYSOURCE_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qtremoteobjectglobal.h"
+
+QT_BEGIN_NAMESPACE
+
+class QRegistrySource : public QObject
+{
+ Q_OBJECT
+ Q_CLASSINFO(QCLASSINFO_REMOTEOBJECT_TYPE, "Registry")
+
+ Q_PROPERTY(QRemoteObjectSourceLocations sourceLocations READ sourceLocations)
+
+public:
+ explicit QRegistrySource(QObject *parent = nullptr);
+ ~QRegistrySource() override;
+
+ QRemoteObjectSourceLocations sourceLocations() const;
+
+Q_SIGNALS:
+ void remoteObjectAdded(const QRemoteObjectSourceLocation &entry);
+ void remoteObjectRemoved(const QRemoteObjectSourceLocation &entry);
+
+public Q_SLOTS:
+ void addSource(const QRemoteObjectSourceLocation &entry);
+ void removeSource(const QRemoteObjectSourceLocation &entry);
+ void removeServer(const QUrl &url);
+
+private:
+ QRemoteObjectSourceLocations m_sourceLocations;
+};
+
+QT_END_NAMESPACE
+
+#endif
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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.LGPL3 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qremoteobjectreplica.h"
+#include "qremoteobjectreplica_p.h"
+
+#include "qremoteobjectnode.h"
+#include "qremoteobjectnode_p.h"
+#include "qremoteobjectdynamicreplica.h"
+#include "qremoteobjectpacket_p.h"
+#include "qremoteobjectpendingcall_p.h"
+#include "qconnectionfactories_p.h"
+#include "qremoteobjectsource_p.h"
+
+#include <QtCore/qcoreapplication.h>
+#include <QtCore/qdatastream.h>
+#include <QtCore/qelapsedtimer.h>
+#include <QtCore/qvariant.h>
+#include <QtCore/qthread.h>
+
+#include <limits>
+
+QT_BEGIN_NAMESPACE
+
+using namespace QRemoteObjectPackets;
+
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_GCC("-Wtautological-compare")
+
+#if !defined(Q_OS_WIN) && !defined(Q_OS_INTEGRITY)
+Q_STATIC_ASSERT_X(&QRemoteObjectReplica::staticMetaObject == &QRemoteObjectDynamicReplica::staticMetaObject,
+ "m_signalOffset initializer expects QRemoteObjectDynamicReplica to not have a unique staticMetaObject");
+#endif
+
+QT_WARNING_POP
+
+// If QRemoteObjectDynamicReplica ever gets its own staticMetaObject, some commented out code will need to be
+// used. It was changed to avoid a Coverity complaint. We use the above static assert to detect if this changes
+// in the future. See FIX #1, #2, #3 in this file.
+
+QRemoteObjectReplicaImplementation::QRemoteObjectReplicaImplementation(const QString &name, const QMetaObject *meta, QRemoteObjectNode *_node)
+ : QObject(nullptr), m_objectName(name), m_metaObject(meta), m_numSignals(0), m_methodOffset(0)
+ // Uncomment the following two lines if QRemoteObjectDynamicReplica gets a unique staticMetaObject (FIX #1, #2)
+ //, m_signalOffset(meta ? QRemoteObjectReplica::staticMetaObject.methodCount() : QRemoteObjectDynamicReplica::staticMetaObject.methodCount())
+ //, m_propertyOffset(meta ? QRemoteObjectReplica::staticMetaObject.propertyCount() : QRemoteObjectDynamicReplica::staticMetaObject.propertyCount())
+ , m_signalOffset(QRemoteObjectReplica::staticMetaObject.methodCount())
+ , m_propertyOffset(QRemoteObjectReplica::staticMetaObject.propertyCount())
+ , m_node(_node)
+ , m_objectSignature(QtPrivate::qtro_classinfo_signature(m_metaObject))
+ , m_state(meta ? QRemoteObjectReplica::Default : QRemoteObjectReplica::Uninitialized)
+{
+}
+
+QRemoteObjectReplicaImplementation::~QRemoteObjectReplicaImplementation()
+{
+}
+
+QConnectedReplicaImplementation::QConnectedReplicaImplementation(const QString &name, const QMetaObject *meta, QRemoteObjectNode *node)
+ : QRemoteObjectReplicaImplementation(name, meta, node), connectionToSource(nullptr)
+{
+ m_heartbeatTimer.setTimerType(Qt::CoarseTimer);
+ m_heartbeatTimer.setSingleShot(true);
+ m_heartbeatTimer.setInterval(node->heartbeatInterval());
+
+ connect(node, &QRemoteObjectNode::heartbeatIntervalChanged, this, [this](int interval) {
+ m_heartbeatTimer.stop();
+ m_heartbeatTimer.setInterval(interval);
+ if (interval)
+ m_heartbeatTimer.start();
+ });
+ connect(&m_heartbeatTimer, &QTimer::timeout, this, [this] {
+ // TODO: Revisit if a baseclass method can be used to avoid specialized cast
+ // conditional logic.
+
+ if (m_pendingCalls.contains(0)) {
+ m_pendingCalls.take(0);
+ // The source didn't respond in time, disconnect the connection
+ if (connectionToSource) {
+ auto clientIo = qobject_cast<QtROClientIoDevice *>(connectionToSource);
+ if (clientIo)
+ clientIo->disconnectFromServer();
+ else
+ connectionToSource->close();
+ }
+ } else {
+ if (connectionToSource.isNull()) {
+ qCDebug(QT_REMOTEOBJECT) << "Ignoring heartbeat as there is no source connected.";
+ return;
+ }
+ connectionToSource->d_func()->m_codec->serializePingPacket(m_objectName);
+ if (sendCommandWithReply(0).d->serialId == -1) {
+ m_heartbeatTimer.stop();
+ auto clientIo = qobject_cast<QtROClientIoDevice *>(connectionToSource);
+ if (clientIo)
+ clientIo->disconnectFromServer();
+ else
+ connectionToSource->close();
+ }
+ }
+ });
+
+ if (!meta)
+ return;
+
+ auto offsetMeta = m_metaObject;
+ QtRemoteObjects::getTypeNameAndMetaobjectFromClassInfo(offsetMeta);
+ for (int index = offsetMeta->propertyOffset(); index < offsetMeta->propertyCount(); ++index) {
+ const QMetaProperty property = offsetMeta->property(index);
+ if (property.metaType().flags().testFlag(QMetaType::PointerToQObject))
+ m_childIndices << index - offsetMeta->propertyOffset();
+ }
+}
+
+QConnectedReplicaImplementation::~QConnectedReplicaImplementation()
+{
+ if (!connectionToSource.isNull()) {
+ qCDebug(QT_REMOTEOBJECT) << "Replica deleted: sending RemoveObject to RemoteObjectSource" << m_objectName;
+ connectionToSource->d_func()->m_codec->serializeRemoveObjectPacket(m_objectName);
+ sendCommand();
+ }
+ for (auto prop : m_propertyStorage) {
+ if (prop.canConvert<QObject*>())
+ prop.value<QObject *>()->deleteLater();
+ }
+}
+
+bool QRemoteObjectReplicaImplementation::needsDynamicInitialization() const
+{
+ return m_metaObject == nullptr;
+}
+
+void QRemoteObjectReplicaImplementation::setState(QRemoteObjectReplica::State state)
+{
+ if (m_state.loadAcquire() != QRemoteObjectReplica::Suspect && m_state.loadAcquire() >= state)
+ return;
+
+ int oldState = m_state.loadAcquire();
+ m_state.storeRelease(state);
+
+ // We should emit initialized before emitting any changed signals in case connections are made in a
+ // Slot responding to initialized/validChanged.
+ if (m_state.loadAcquire() == QRemoteObjectReplica::Valid) {
+ // we're initialized now, emit signal
+ emitInitialized();
+ }
+
+ const static int stateChangedIndex = QRemoteObjectReplica::staticMetaObject.indexOfMethod("stateChanged(State,State)");
+ Q_ASSERT(stateChangedIndex != -1);
+ void *args[] = {nullptr, &state, &oldState};
+ QMetaObject::activate(this, metaObject(), stateChangedIndex, args);
+}
+
+void QRemoteObjectReplicaImplementation::emitNotified()
+{
+ const static int notifiedIndex = QRemoteObjectReplica::staticMetaObject.indexOfMethod("notified()");
+ Q_ASSERT(notifiedIndex != -1);
+ void *args[] = {nullptr};
+ QMetaObject::activate(this, metaObject(), notifiedIndex, args);
+}
+
+bool QConnectedReplicaImplementation::sendCommand()
+{
+ Q_ASSERT(connectionToSource);
+ if (!connectionToSource->isOpen())
+ return false;
+
+ connectionToSource->d_func()->m_codec->send(connectionToSource);
+ if (m_heartbeatTimer.interval())
+ m_heartbeatTimer.start();
+ return true;
+}
+
+QList<int> QConnectedReplicaImplementation::childIndices() const
+{
+ return m_childIndices;
+}
+
+void QConnectedReplicaImplementation::initialize(QVariantList &&values)
+{
+ qCDebug(QT_REMOTEOBJECT) << "initialize()" << m_propertyStorage.size();
+ const int nParam = int(values.size());
+ QVarLengthArray<int> changedProperties(nParam);
+ const int offset = m_propertyOffset;
+ for (int i = 0; i < nParam; ++i) {
+ qCDebug(QT_REMOTEOBJECT) << " in loop" << i << m_propertyStorage.size();
+ changedProperties[i] = -1;
+ if (m_propertyStorage[i] != values.at(i)) {
+ const QMetaProperty property = m_metaObject->property(i+offset);
+ m_propertyStorage[i] = QRemoteObjectPackets::decodeVariant(std::move(values[i]), property.metaType());
+ changedProperties[i] = i;
+ }
+ qCDebug(QT_REMOTEOBJECT) << "SETPROPERTY" << i << m_metaObject->property(i+offset).name()
+ << m_propertyStorage[i].typeName()
+ << m_propertyStorage[i].toString();
+ }
+
+ Q_ASSERT(m_state.loadAcquire() < QRemoteObjectReplica::Valid || m_state.loadAcquire() == QRemoteObjectReplica::Suspect);
+ setState(QRemoteObjectReplica::Valid);
+
+ void *args[] = {nullptr, nullptr};
+ for (int i = 0; i < nParam; ++i) {
+ if (changedProperties[i] < 0)
+ continue;
+ const int notifyIndex = m_metaObject->property(changedProperties[i]+offset).notifySignalIndex();
+ if (notifyIndex < 0)
+ continue;
+ qCDebug(QT_REMOTEOBJECT) << " Before activate" << notifyIndex << m_metaObject->property(notifyIndex).name();
+ args[1] = m_propertyStorage[i].data();
+ QMetaObject::activate(this, metaObject(), notifyIndex, args);
+ }
+ emitNotified();
+
+ qCDebug(QT_REMOTEOBJECT) << "isSet = true for" << m_objectName;
+ if (node()->heartbeatInterval())
+ m_heartbeatTimer.start();
+}
+
+void QRemoteObjectReplicaImplementation::emitInitialized()
+{
+ const static int initializedIndex = QRemoteObjectReplica::staticMetaObject.indexOfMethod("initialized()");
+ Q_ASSERT(initializedIndex != -1);
+ void *noArgs[] = {nullptr};
+ QMetaObject::activate(this, metaObject(), initializedIndex, noArgs);
+}
+
+/*!
+ \internal
+*/
+void QRemoteObjectReplica::persistProperties(const QString &repName, const QByteArray &repSig, const QVariantList &props) const
+{
+ if (!node()) {
+ qWarning("Tried calling persistProperties on a replica (%s) that hasn't been initialized with a node", qPrintable(repName));
+ return;
+ }
+ node()->persistProperties(repName, repSig, props);
+}
+
+/*!
+ \internal
+*/
+QVariantList QRemoteObjectReplica::retrieveProperties(const QString &repName, const QByteArray &repSig) const
+{
+ if (!node()) {
+ qWarning("Tried calling retrieveProperties on a replica (%s) that hasn't been initialized with a node", qPrintable(repName));
+ return QVariantList();
+ }
+ return node()->retrieveProperties(repName, repSig);
+}
+
+void QRemoteObjectReplicaImplementation::setDynamicMetaObject(const QMetaObject *meta)
+{
+ Q_ASSERT(!m_metaObject);
+
+ m_metaObject = meta;
+}
+
+void QConnectedReplicaImplementation::setDynamicMetaObject(const QMetaObject *meta)
+{
+ QRemoteObjectReplicaImplementation::setDynamicMetaObject(meta);
+
+ for (int index = m_metaObject->propertyOffset(); index < m_metaObject->propertyCount(); ++index) {
+ const QMetaProperty property = m_metaObject->property(index);
+ if (property.metaType().flags().testFlag(QMetaType::PointerToQObject))
+ m_childIndices << index - m_metaObject->propertyOffset();
+ }
+}
+
+void QRemoteObjectReplicaImplementation::setDynamicProperties(QVariantList &&values)
+{
+ const int offset = m_propertyOffset;
+ int propertyIndex = -1;
+ for (auto &prop : values) {
+ propertyIndex++;
+ const QMetaProperty property = m_metaObject->property(propertyIndex+offset);
+ prop = QRemoteObjectPackets::decodeVariant(std::move(prop), property.metaType());
+ }
+ //rely on order of properties;
+ setProperties(std::move(values));
+}
+
+void QConnectedReplicaImplementation::setDynamicProperties(QVariantList &&values)
+{
+ QRemoteObjectReplicaImplementation::setDynamicProperties(std::move(values));
+ for (QRemoteObjectReplica *obj : qExchange(m_parentsNeedingConnect, {}))
+ configurePrivate(obj);
+
+ Q_ASSERT(m_state.loadAcquire() < QRemoteObjectReplica::Valid);
+ setState(QRemoteObjectReplica::Valid);
+
+ void *args[] = {nullptr, nullptr};
+ for (int index = m_metaObject->propertyOffset(); index < m_metaObject->propertyCount(); ++index) {
+ const QMetaProperty mp = m_metaObject->property(index);
+ if (mp.hasNotifySignal()) {
+ qCDebug(QT_REMOTEOBJECT) << " Before activate" << index << m_metaObject->property(index).name();
+ args[1] = this->m_propertyStorage[index-m_propertyOffset].data();
+ QMetaObject::activate(this, metaObject(), mp.notifySignalIndex(), args);
+ }
+ }
+ emitNotified();
+
+ qCDebug(QT_REMOTEOBJECT) << "isSet = true for" << m_objectName;
+}
+
+bool QConnectedReplicaImplementation::isInitialized() const
+{
+ return m_state.loadAcquire() > QRemoteObjectReplica::Default && m_state.loadAcquire() != QRemoteObjectReplica::SignatureMismatch;
+}
+
+bool QConnectedReplicaImplementation::waitForSource(int timeout)
+{
+ switch (state()) {
+ case QRemoteObjectReplica::State::Valid:
+ return true;
+ case QRemoteObjectReplica::State::SignatureMismatch:
+ return false;
+ default:
+ break;
+ }
+
+ const static int stateChangedIndex = QRemoteObjectReplica::staticMetaObject.indexOfMethod("stateChanged(State,State)");
+ Q_ASSERT(stateChangedIndex != -1);
+
+ QEventLoop loop;
+ QMetaObject::connect(this, stateChangedIndex,
+ &loop, QEventLoop::staticMetaObject.indexOfMethod("quit()"),
+ Qt::DirectConnection, nullptr);
+
+ QTimer t; // NB: Related to QTBUG-94570 - don't use QTimer::singleShot here.
+ if (timeout >= 0) {
+ t.setSingleShot(true);
+ connect(&t, &QTimer::timeout, &loop, &QEventLoop::quit);
+ t.start(timeout);
+ }
+
+ // enter the event loop and wait for a reply
+ loop.exec(QEventLoop::ExcludeUserInputEvents | QEventLoop::WaitForMoreEvents);
+
+ return state() == QRemoteObjectReplica::State::Valid;
+}
+
+void QConnectedReplicaImplementation::_q_send(QMetaObject::Call call, int index, const QVariantList &args)
+{
+ static const bool debugArgs = qEnvironmentVariableIsSet("QT_REMOTEOBJECT_DEBUG_ARGUMENTS");
+
+ Q_ASSERT(call == QMetaObject::InvokeMetaMethod || call == QMetaObject::WriteProperty);
+ if (connectionToSource.isNull()) {
+ qCWarning(QT_REMOTEOBJECT) << "connectionToSource is null";
+ return;
+ }
+
+ if (call == QMetaObject::InvokeMetaMethod) {
+ if (debugArgs) {
+ qCDebug(QT_REMOTEOBJECT) << "Send" << call << this->m_metaObject->method(index).name() << index << args << connectionToSource;
+ } else {
+ qCDebug(QT_REMOTEOBJECT) << "Send" << call << this->m_metaObject->method(index).name() << index << connectionToSource;
+ }
+ if (index < m_methodOffset) //index - m_methodOffset < 0 is invalid, and can't be resolved on the Source side
+ qCWarning(QT_REMOTEOBJECT) << "Skipping invalid method invocation. Index not found:" << index << "( offset =" << m_methodOffset << ") object:" << m_objectName << this->m_metaObject->method(index).name();
+ else {
+ connectionToSource->d_func()->m_codec->serializeInvokePacket(m_objectName, call, index - m_methodOffset, args);
+ sendCommand();
+ }
+ } else {
+ qCDebug(QT_REMOTEOBJECT) << "Send" << call << this->m_metaObject->property(index).name() << index << args << connectionToSource;
+ if (index < m_propertyOffset) //index - m_propertyOffset < 0 is invalid, and can't be resolved on the Source side
+ qCWarning(QT_REMOTEOBJECT) << "Skipping invalid property invocation. Index not found:" << index << "( offset =" << m_propertyOffset << ") object:" << m_objectName << this->m_metaObject->property(index).name();
+ else {
+ connectionToSource->d_func()->m_codec->serializeInvokePacket(m_objectName, call, index - m_propertyOffset, args);
+ sendCommand();
+ }
+ }
+}
+
+QRemoteObjectPendingCall QConnectedReplicaImplementation::_q_sendWithReply(QMetaObject::Call call, int index, const QVariantList &args)
+{
+ Q_ASSERT(call == QMetaObject::InvokeMetaMethod);
+ if (connectionToSource.isNull()) {
+ qCWarning(QT_REMOTEOBJECT) << "connectionToSource is null";
+ return QRemoteObjectPendingCall();
+ }
+
+ qCDebug(QT_REMOTEOBJECT) << "Send" << call << this->m_metaObject->method(index).name() << index << args << connectionToSource;
+ int serialId = (m_curSerialId == std::numeric_limits<int>::max() ? 1 : m_curSerialId++);
+ connectionToSource->d_func()->m_codec->serializeInvokePacket(m_objectName, call, index - m_methodOffset, args, serialId);
+ return sendCommandWithReply(serialId);
+}
+
+QRemoteObjectPendingCall QConnectedReplicaImplementation::sendCommandWithReply(int serialId)
+{
+ bool success = sendCommand();
+ if (!success) {
+ return QRemoteObjectPendingCall(); // invalid
+ }
+
+ qCDebug(QT_REMOTEOBJECT) << "Sent InvokePacket with serial id:" << serialId;
+ QRemoteObjectPendingCall pendingCall(new QRemoteObjectPendingCallData(serialId, this));
+ Q_ASSERT(!m_pendingCalls.contains(serialId));
+ m_pendingCalls[serialId] = pendingCall;
+ return pendingCall;
+}
+
+void QConnectedReplicaImplementation::notifyAboutReply(int ackedSerialId, const QVariant &value)
+{
+ QRemoteObjectPendingCall call = m_pendingCalls.take(ackedSerialId);
+ if (ackedSerialId == 0) {
+ m_heartbeatTimer.stop();
+ if (m_heartbeatTimer.interval())
+ m_heartbeatTimer.start();
+ return;
+ }
+
+ QMutexLocker mutex(&call.d->mutex);
+
+ // clear error flag
+ call.d->error = QRemoteObjectPendingCall::NoError;
+ call.d->returnValue = value;
+
+ // notify watchers if needed
+ if (call.d->watcherHelper)
+ call.d->watcherHelper->emitSignals();
+}
+
+bool QConnectedReplicaImplementation::waitForFinished(const QRemoteObjectPendingCall& call, int timeout)
+{
+ if (!call.d->watcherHelper)
+ call.d->watcherHelper.reset(new QRemoteObjectPendingCallWatcherHelper);
+
+ call.d->mutex.unlock();
+
+ QEventLoop loop;
+ loop.connect(call.d->watcherHelper.data(), &QRemoteObjectPendingCallWatcherHelper::finished,
+ &loop, &QEventLoop::quit);
+
+ QTimer t; // NB: Related to QTBUG-94570 - don't use QTimer::singleShot here.
+ if (timeout >= 0) {
+ t.setSingleShot(true);
+ connect(&t, &QTimer::timeout, &loop, &QEventLoop::quit);
+ t.start(timeout);
+ }
+
+ // enter the event loop and wait for a reply
+ loop.exec(QEventLoop::ExcludeUserInputEvents | QEventLoop::WaitForMoreEvents);
+
+ call.d->mutex.lock();
+
+ return call.d->error != QRemoteObjectPendingCall::InvalidMessage;
+}
+
+const QVariant QConnectedReplicaImplementation::getProperty(int i) const
+{
+ Q_ASSERT_X(i >= 0 && i < m_propertyStorage.size(), __FUNCTION__, qPrintable(QString(QLatin1String("0 <= %1 < %2")).arg(i).arg(m_propertyStorage.size())));
+ return m_propertyStorage[i];
+}
+
+void QConnectedReplicaImplementation::setProperties(QVariantList &&properties)
+{
+ Q_ASSERT(m_propertyStorage.isEmpty());
+ m_propertyStorage.reserve(properties.length());
+ m_propertyStorage = std::move(properties);
+}
+
+void QConnectedReplicaImplementation::setProperty(int i, const QVariant &prop)
+{
+ m_propertyStorage[i] = prop;
+}
+
+void QConnectedReplicaImplementation::setConnection(QtROIoDeviceBase *conn)
+{
+ if (connectionToSource.isNull()) {
+ connectionToSource = conn;
+ qCDebug(QT_REMOTEOBJECT) << "setConnection started" << conn << m_objectName;
+ }
+ requestRemoteObjectSource();
+}
+
+void QConnectedReplicaImplementation::setDisconnected()
+{
+ Q_ASSERT(connectionToSource);
+ connectionToSource.clear();
+ setState(QRemoteObjectReplica::State::Suspect);
+ for (const int index : childIndices()) {
+ auto pointerToQObject = qvariant_cast<QObject *>(getProperty(index));
+ auto child = qobject_cast<QRemoteObjectReplica *>(pointerToQObject);
+ if (child)
+ static_cast<QConnectedReplicaImplementation *>(child->d_impl.data())->setDisconnected();
+ }
+}
+
+void QConnectedReplicaImplementation::requestRemoteObjectSource()
+{
+ Q_ASSERT(connectionToSource);
+ connectionToSource->d_func()->m_codec->serializeAddObjectPacket(m_objectName, needsDynamicInitialization());
+ sendCommand();
+}
+
+void QRemoteObjectReplicaImplementation::configurePrivate(QRemoteObjectReplica *rep)
+{
+ qCDebug(QT_REMOTEOBJECT) << "configurePrivate starting for" << this->m_objectName;
+ //We need to connect the Replicant only signals too
+ // Uncomment the following two lines if QRemoteObjectDynamicReplica gets a unique staticMetaObject (FIX #3)
+ //const QMetaObject *m = rep->inherits("QRemoteObjectDynamicReplica") ?
+ // &QRemoteObjectDynamicReplica::staticMetaObject : &QRemoteObjectReplica::staticMetaObject;
+ const QMetaObject *m = &QRemoteObjectReplica::staticMetaObject;
+ for (int i = m->methodOffset(); i < m->methodCount(); ++i)
+ {
+ const QMetaMethod mm = m->method(i);
+ if (mm.methodType() == QMetaMethod::Signal) {
+ const bool res = QMetaObject::connect(this, i, rep, i, Qt::DirectConnection, nullptr);
+ qCDebug(QT_REMOTEOBJECT) << " Rep connect"<<i<<res<<mm.name();
+ Q_UNUSED(res)
+ }
+ }
+ if (m_methodOffset == 0) //We haven't initialized the offsets yet
+ {
+ const int index = m_metaObject->indexOfClassInfo(QCLASSINFO_REMOTEOBJECT_TYPE);
+ const QMetaObject *metaObject = m_metaObject;
+ if (index != -1) { //We have an object created from repc or at least with QCLASSINFO defined
+ while (true) {
+ Q_ASSERT(metaObject->superClass()); //This recurses to QObject, which doesn't have QCLASSINFO_REMOTEOBJECT_TYPE
+ if (index != metaObject->superClass()->indexOfClassInfo(QCLASSINFO_REMOTEOBJECT_TYPE)) //At the point we don't find the same QCLASSINFO_REMOTEOBJECT_TYPE,
+ //we have the metaobject we should work from
+ break;
+ metaObject = metaObject->superClass();
+ }
+ }
+
+ for (int i = m_signalOffset; i < metaObject->methodCount(); ++i) {
+ const QMetaMethod mm = metaObject->method(i);
+ if (mm.methodType() == QMetaMethod::Signal) {
+ ++m_numSignals;
+ const bool res = QMetaObject::connect(this, i, rep, i, Qt::DirectConnection, nullptr);
+ qCDebug(QT_REMOTEOBJECT) << " Connect"<<i<<res<<mm.name();
+ Q_UNUSED(res)
+ }
+ }
+ m_methodOffset = m_signalOffset + m_numSignals;
+ qCDebug(QT_REMOTEOBJECT) << QStringLiteral("configurePrivate finished, signalOffset = %1, methodOffset = %2, #Signals = %3").arg(m_signalOffset).arg(m_methodOffset).arg(m_numSignals);
+ } else { //We have initialized offsets, this is an additional Replica attaching
+ for (int i = m_signalOffset; i < m_methodOffset; ++i) {
+ const bool res = QMetaObject::connect(this, i, rep, i, Qt::DirectConnection, nullptr);
+ qCDebug(QT_REMOTEOBJECT) << " Connect"<<i<<res<<m_metaObject->method(i).name();
+ Q_UNUSED(res)
+ }
+ if (isInitialized()) {
+ qCDebug(QT_REMOTEOBJECT) << QStringLiteral("ReplicaImplementation initialized, emitting signal on replica");
+ emit rep->initialized(); //Emit from new replica only
+ }
+ if (state() != QRemoteObjectReplica::Valid) {
+ qCDebug(QT_REMOTEOBJECT) << QStringLiteral("ReplicaImplementation not currently valid, emitting signal on replica");
+ emit rep->stateChanged(state(), m_metaObject ? QRemoteObjectReplica::Default : QRemoteObjectReplica::Uninitialized);
+ }
+
+ qCDebug(QT_REMOTEOBJECT) << QStringLiteral("configurePrivate finished, added replica to existing ReplicaImplementation");
+ }
+}
+
+void QConnectedReplicaImplementation::configurePrivate(QRemoteObjectReplica *rep)
+{
+ if (m_metaObject) {
+ // see QRemoteObjectReplicaImplementation::configurePrivate
+ const bool firstReplicaInstance = (m_methodOffset == 0);
+
+ QRemoteObjectReplicaImplementation::configurePrivate(rep);
+
+ // ensure that notify signals are emitted for the new replica, when
+ // we are initializing an nth replica of the same type
+ if (!firstReplicaInstance) {
+ const int offset = m_propertyOffset;
+ const int nParam = int(m_propertyStorage.count());
+ void *args[] = {nullptr, nullptr};
+ for (int i = 0; i < nParam; ++i) {
+ const int notifyIndex = m_metaObject->property(i+offset).notifySignalIndex();
+ if (notifyIndex < 0)
+ continue;
+ qCDebug(QT_REMOTEOBJECT) << " Before activate" << notifyIndex << m_metaObject->property(i+offset).name();
+ args[1] = m_propertyStorage[i].data();
+ // NOTE: this over-emits (assumes all values have changed)
+ QMetaObject::activate(rep, rep->metaObject(), notifyIndex - m_signalOffset, args);
+ }
+ }
+ } else
+ m_parentsNeedingConnect.append(rep);
+}
+
+/*!
+ \class QRemoteObjectReplica
+ \inmodule QtRemoteObjects
+ \brief A class interacting with (but not implementing) a Qt API on the Remote Object network.
+
+ A Remote Object Replica is a QObject proxy for another QObject (called the
+ \l {Source} object). Once initialized, a replica can be considered a
+ "latent copy" of the \l {Source} object. That is, every change to a
+ Q_PROPERTY on the \l {Source}, or signal emitted by the \l {Source} will be
+ updated/emitted by all \l {Replica} objects. Latency
+ is introduced by process scheduling by any OSes involved and network
+ communication latency. As long as the replica has been initialized and the
+ communication is not disrupted, receipt and order of changes is guaranteed.
+
+ The \l {isInitialized} and \l {state} properties (and corresponding
+ \l {initialized()}/\l {stateChanged()} signals) allow the state of a
+ \l {Replica} to be determined.
+
+ While Qt Remote Objects (QtRO) handles the initialization and
+ synchronization of \l {Replica} objects, there are numerous steps happening
+ behind the scenes which can fail and that aren't encountered in single
+ process Qt applications. See \l {Troubleshooting} for advice on how to
+ handle such issues when using a remote objects network.
+*/
+
+/*!
+ \enum QRemoteObjectReplica::State
+
+ This enum type specifies the various state codes associated with QRemoteObjectReplica states:
+
+ \value Uninitialized Initial value of DynamicReplica, where nothing is
+ known about the replica before connection to source.
+
+ \value Default Initial value of static replica, where any defaults set in
+ the .rep file are available so it can be used if necessary.
+
+ \value Valid Indicates the replica is connected, has good property values
+ and can be interacted with.
+
+ \value Suspect Error state that occurs if the connection to the source is
+ lost after it is initialized.
+
+ \value SignatureMismatch Error state that occurs if a connection to the
+ source is made, but the source and replica are not derived from the same
+ .rep (only possible for static Replicas).
+*/
+
+/*!
+ \fn void QRemoteObjectReplica::stateChanged(State state, State oldState)
+
+ This signal is emitted whenever a replica's state toggles between
+ \l QRemoteObjectReplica::State.
+
+ The change in state is represented with \a state and \a oldState.
+
+ \sa state(), initialized()
+*/
+
+/*!
+ \fn void QRemoteObjectReplica::initialized()
+
+ This signal is emitted once the replica is initialized. An intialized replica
+ has all property values set, but has not yet emitted any property change
+ notifications.
+
+ \sa isInitialized(), stateChanged()
+*/
+
+/*!
+ \fn void QRemoteObjectReplica::notified()
+
+ This signal is emitted once the replica is initialized and all property change
+ notifications have been emitted.
+
+ It is sometimes useful to respond to property changes as events.
+ For example, you might want to display a user notification when a certain
+ property change occurs. However, this user notification would then also be
+ triggered when a replica first became \c QRemoteObjectReplica::Valid, as
+ all property change signals are emitted at that time. This isn't always desirable,
+ and \c notified allows the developer to distinguish between these two cases.
+*/
+
+/*!
+ \internal
+ \enum QRemoteObjectReplica::ConstructorType
+*/
+
+/*!
+ \property QRemoteObjectReplica::state
+ \brief Returns the replica state.
+
+ This property holds the replica \l QRemoteObjectReplica::State.
+*/
+
+/*!
+ \property QRemoteObjectReplica::node
+ \brief A pointer to the node this object was acquired from.
+*/
+
+/*!
+ \internal This (protected) constructor for QRemoteObjectReplica can be used to create
+ replica objects from QML.
+*/
+QRemoteObjectReplica::QRemoteObjectReplica(ConstructorType t)
+ : QObject(nullptr)
+ , d_impl(t == DefaultConstructor ? new QStubReplicaImplementation : nullptr)
+{
+ qRegisterMetaType<State>("State");
+}
+
+QRemoteObjectReplica::QRemoteObjectReplica(QObjectPrivate &dptr, QObject *parent)
+ : QObject(dptr, parent)
+ , d_impl(new QStubReplicaImplementation)
+{
+}
+
+/*!
+ \internal
+*/
+QRemoteObjectReplica::~QRemoteObjectReplica()
+{
+}
+
+/*!
+ \internal
+*/
+void QRemoteObjectReplica::send(QMetaObject::Call call, int index, const QVariantList &args)
+{
+ Q_ASSERT(index != -1);
+
+ d_impl->_q_send(call, index, args);
+}
+
+/*!
+ \internal
+*/
+QRemoteObjectPendingCall QRemoteObjectReplica::sendWithReply(QMetaObject::Call call, int index, const QVariantList &args)
+{
+ return d_impl->_q_sendWithReply(call, index, args);
+}
+
+/*!
+ \internal
+*/
+const QVariant QRemoteObjectReplica::propAsVariant(int i) const
+{
+ return d_impl->getProperty(i);
+}
+
+/*!
+ \internal
+*/
+void QRemoteObjectReplica::initializeNode(QRemoteObjectNode *node, const QString &name)
+{
+ node->initializeReplica(this, name);
+}
+
+/*!
+ \internal
+*/
+void QRemoteObjectReplica::setProperties(QVariantList &&properties)
+{
+ d_impl->setProperties(std::move(properties));
+}
+
+/*!
+ \internal
+*/
+void QRemoteObjectReplica::setChild(int i, const QVariant &value)
+{
+ d_impl->setProperty(i, value);
+}
+
+/*!
+ Returns \c true if this replica has been initialized with data from the
+ \l {Source} object. Returns \c false otherwise.
+
+ \sa state()
+*/
+bool QRemoteObjectReplica::isInitialized() const
+{
+ return d_impl->isInitialized();
+}
+
+/*!
+ Returns \c true if this replica has been initialized with data from the
+ \l {Source} object. Returns \c false otherwise.
+
+ \sa isInitialized()
+*/
+QRemoteObjectReplica::State QRemoteObjectReplica::state() const
+{
+ return d_impl->state();
+}
+
+QRemoteObjectNode *QRemoteObjectReplica::node() const
+{
+ return d_impl->node();
+}
+
+void QRemoteObjectReplica::setNode(QRemoteObjectNode *_node)
+{
+ const QRemoteObjectNode *curNode = node();
+ if (curNode) {
+ qCWarning(QT_REMOTEOBJECT) << "Ignoring call to setNode as the node has already been set";
+ return;
+ }
+ d_impl.clear();
+ _node->initializeReplica(this);
+}
+
+/*!
+ \internal
+*/
+void QRemoteObjectReplica::initialize()
+{
+}
+
+/*!
+ Returns \c true if this replica has been initialized and has a valid
+ connection with the \l {QRemoteObjectNode} {node} hosting the \l {Source}.
+ Returns \c false otherwise.
+
+ \sa isInitialized()
+*/
+bool QRemoteObjectReplica::isReplicaValid() const
+{
+ return state() == Valid;
+}
+
+/*!
+ Blocking call that waits for the replica to become initialized or until the
+ \a timeout (in ms) expires. Returns \c true if the replica is initialized
+ when the call completes, \c false otherwise.
+
+ If \a timeout is -1, this function will not time out.
+
+ \sa isInitialized(), initialized()
+*/
+bool QRemoteObjectReplica::waitForSource(int timeout)
+{
+ return d_impl->waitForSource(timeout);
+}
+
+QInProcessReplicaImplementation::QInProcessReplicaImplementation(const QString &name, const QMetaObject *meta, QRemoteObjectNode * node)
+ : QRemoteObjectReplicaImplementation(name, meta, node)
+{
+}
+
+QInProcessReplicaImplementation::~QInProcessReplicaImplementation()
+{
+}
+
+const QVariant QInProcessReplicaImplementation::getProperty(int i) const
+{
+ Q_ASSERT(connectionToSource);
+ Q_ASSERT(connectionToSource->m_object);
+ const int index = i + QRemoteObjectSource::qobjectPropertyOffset;
+ Q_ASSERT(index >= 0 && index < connectionToSource->m_object->metaObject()->propertyCount());
+ return connectionToSource->m_object->metaObject()->property(index).read(connectionToSource->m_object);
+}
+
+void QInProcessReplicaImplementation::setProperties(QVariantList &&)
+{
+ //TODO some verification here maybe?
+}
+
+void QInProcessReplicaImplementation::setProperty(int i, const QVariant &property)
+{
+ Q_ASSERT(connectionToSource);
+ Q_ASSERT(connectionToSource->m_object);
+ const int index = i + QRemoteObjectSource::qobjectPropertyOffset;
+ Q_ASSERT(index >= 0 && index < connectionToSource->m_object->metaObject()->propertyCount());
+ connectionToSource->m_object->metaObject()->property(index).write(connectionToSource->m_object, property);
+}
+
+void QInProcessReplicaImplementation::_q_send(QMetaObject::Call call, int index, const QVariantList &args)
+{
+ Q_ASSERT(call == QMetaObject::InvokeMetaMethod || call == QMetaObject::WriteProperty);
+
+ const SourceApiMap *api = connectionToSource->m_api;
+ if (call == QMetaObject::InvokeMetaMethod) {
+ const int resolvedIndex = api->sourceMethodIndex(index - m_methodOffset);
+ if (resolvedIndex < 0)
+ qCWarning(QT_REMOTEOBJECT) << "Skipping invalid invocation. Index not found:" << index - m_methodOffset;
+ else
+ connectionToSource->invoke(call, index - m_methodOffset, args);
+ } else {
+ const int resolvedIndex = connectionToSource->m_api->sourcePropertyIndex(index - m_propertyOffset);
+ if (resolvedIndex < 0)
+ qCWarning(QT_REMOTEOBJECT) << "Skipping invalid property setter. Index not found:" << index - m_propertyOffset;
+ else
+ connectionToSource->invoke(call, index - m_propertyOffset, args);
+ }
+}
+
+QRemoteObjectPendingCall QInProcessReplicaImplementation::_q_sendWithReply(QMetaObject::Call call, int index, const QVariantList &args)
+{
+ Q_ASSERT(call == QMetaObject::InvokeMetaMethod);
+
+ const int ReplicaIndex = index - m_methodOffset;
+ auto metaType = QMetaType::fromName(connectionToSource->m_api->typeName(ReplicaIndex).constData());
+ if (!metaType.sizeOf())
+ metaType = QMetaType(QMetaType::UnknownType);
+ QVariant returnValue(metaType, nullptr);
+
+ const int resolvedIndex = connectionToSource->m_api->sourceMethodIndex(ReplicaIndex);
+ if (resolvedIndex < 0) {
+ qCWarning(QT_REMOTEOBJECT) << "Skipping invalid invocation. Index not found:" << ReplicaIndex;
+ return QRemoteObjectPendingCall();
+ }
+
+ connectionToSource->invoke(call, ReplicaIndex, args, &returnValue);
+ return QRemoteObjectPendingCall::fromCompletedCall(returnValue);
+}
+
+QStubReplicaImplementation::QStubReplicaImplementation() {}
+
+QStubReplicaImplementation::~QStubReplicaImplementation() {}
+
+const QVariant QStubReplicaImplementation::getProperty(int i) const
+{
+ Q_ASSERT_X(i >= 0 && i < m_propertyStorage.size(), __FUNCTION__, qPrintable(QString(QLatin1String("0 <= %1 < %2")).arg(i).arg(m_propertyStorage.size())));
+ return m_propertyStorage[i];
+}
+
+void QStubReplicaImplementation::setProperties(QVariantList &&properties)
+{
+ Q_ASSERT(m_propertyStorage.isEmpty());
+ m_propertyStorage.reserve(properties.length());
+ m_propertyStorage = std::move(properties);
+}
+
+void QStubReplicaImplementation::setProperty(int i, const QVariant &prop)
+{
+ m_propertyStorage[i] = prop;
+}
+
+void QStubReplicaImplementation::_q_send(QMetaObject::Call call, int index, const QVariantList &args)
+{
+ Q_UNUSED(call)
+ Q_UNUSED(index)
+ Q_UNUSED(args)
+ qWarning("Tried calling a slot or setting a property on a replica that hasn't been initialized with a node");
+}
+
+QRemoteObjectPendingCall QStubReplicaImplementation::_q_sendWithReply(QMetaObject::Call call, int index, const QVariantList &args)
+{
+ Q_UNUSED(call)
+ Q_UNUSED(index)
+ Q_UNUSED(args)
+ qWarning("Tried calling a slot or setting a property on a replica that hasn't been initialized with a node");
+ return QRemoteObjectPendingCall(); //Invalid
+}
+
+QT_END_NAMESPACE
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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.LGPL3 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQREMOTEOBJECTREPLICA_H
+#define QQREMOTEOBJECTREPLICA_H
+
+#include <QtRemoteObjects/qtremoteobjectglobal.h>
+
+#include <QtCore/qsharedpointer.h>
+
+Q_MOC_INCLUDE(<QtRemoteObjects/qremoteobjectnode.h>)
+
+QT_BEGIN_NAMESPACE
+
+class QObjectPrivate;
+class QRemoteObjectPendingCall;
+class QRemoteObjectReplicaImplementation;
+class QReplicaImplementationInterface;
+class QRemoteObjectNode;
+
+class Q_REMOTEOBJECTS_EXPORT QRemoteObjectReplica : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QRemoteObjectNode *node READ node WRITE setNode)
+ Q_PROPERTY(State state READ state NOTIFY stateChanged)
+public:
+ enum State {
+ Uninitialized,
+ Default,
+ Valid,
+ Suspect,
+ SignatureMismatch
+ };
+ Q_ENUM(State)
+
+public:
+ ~QRemoteObjectReplica() override;
+
+ bool isReplicaValid() const;
+ bool waitForSource(int timeout = 30000);
+ bool isInitialized() const;
+ State state() const;
+ QRemoteObjectNode *node() const;
+ virtual void setNode(QRemoteObjectNode *node);
+
+Q_SIGNALS:
+ void initialized();
+ void notified();
+ void stateChanged(State state, State oldState);
+
+protected:
+ enum ConstructorType {DefaultConstructor, ConstructWithNode};
+ explicit QRemoteObjectReplica(ConstructorType t = DefaultConstructor);
+ QRemoteObjectReplica(QObjectPrivate &dptr, QObject *parent);
+
+ virtual void initialize();
+ void send(QMetaObject::Call call, int index, const QVariantList &args);
+ QRemoteObjectPendingCall sendWithReply(QMetaObject::Call call, int index, const QVariantList &args);
+
+protected:
+ void setProperties(QVariantList &&);
+ void setChild(int i, const QVariant &);
+ const QVariant propAsVariant(int i) const;
+ void persistProperties(const QString &repName, const QByteArray &repSig, const QVariantList &props) const;
+ QVariantList retrieveProperties(const QString &repName, const QByteArray &repSig) const;
+ void initializeNode(QRemoteObjectNode *node, const QString &name = QString());
+ QSharedPointer<QReplicaImplementationInterface> d_impl;
+private:
+ friend class QRemoteObjectNodePrivate;
+ friend class QConnectedReplicaImplementation;
+};
+
+QT_END_NAMESPACE
+
+#endif
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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.LGPL3 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QREMOTEOBJECTREPLICA_P_H
+#define QREMOTEOBJECTREPLICA_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qremoteobjectreplica.h"
+
+#include "qremoteobjectpendingcall.h"
+
+#include "qremoteobjectpacket_p.h"
+
+#include <QtCore/qcompilerdetection.h>
+#include <QtCore/qdatastream.h>
+#include <QtCore/qpointer.h>
+#include <QtCore/qtimer.h>
+
+QT_BEGIN_NAMESPACE
+
+class QRemoteObjectReplica;
+class QRemoteObjectSource;
+class QtROIoDeviceBase;
+
+class QReplicaImplementationInterface
+{
+public:
+ virtual ~QReplicaImplementationInterface() {}
+ virtual const QVariant getProperty(int i) const = 0;
+ virtual void setProperties(QVariantList &&) = 0;
+ virtual void setProperty(int i, const QVariant &) = 0;
+ virtual bool isInitialized() const = 0;
+ virtual QRemoteObjectReplica::State state() const = 0;
+ virtual bool waitForSource(int) = 0;
+ virtual QRemoteObjectNode *node() const = 0;
+
+ virtual void _q_send(QMetaObject::Call call, int index, const QVariantList &args) = 0;
+ virtual QRemoteObjectPendingCall _q_sendWithReply(QMetaObject::Call call, int index, const QVariantList &args) = 0;
+};
+
+class QStubReplicaImplementation final : public QReplicaImplementationInterface
+{
+public:
+ explicit QStubReplicaImplementation();
+ ~QStubReplicaImplementation() override;
+
+ const QVariant getProperty(int i) const override;
+ void setProperties(QVariantList &&) override;
+ void setProperty(int i, const QVariant &) override;
+ bool isInitialized() const override { return false; }
+ QRemoteObjectReplica::State state() const override { return QRemoteObjectReplica::State::Uninitialized;}
+ bool waitForSource(int) override { return false; }
+ QRemoteObjectNode *node() const override { return nullptr; }
+
+ void _q_send(QMetaObject::Call call, int index, const QVariantList &args) override;
+ QRemoteObjectPendingCall _q_sendWithReply(QMetaObject::Call call, int index, const QVariantList &args) override;
+ QVariantList m_propertyStorage;
+};
+
+class QRemoteObjectReplicaImplementation : public QObject, public QReplicaImplementationInterface
+{
+public:
+ explicit QRemoteObjectReplicaImplementation(const QString &name, const QMetaObject *, QRemoteObjectNode *);
+ ~QRemoteObjectReplicaImplementation() override;
+
+ bool needsDynamicInitialization() const;
+
+ const QVariant getProperty(int i) const override = 0;
+ void setProperties(QVariantList &&) override = 0;
+ void setProperty(int i, const QVariant &) override = 0;
+ virtual bool isShortCircuit() const = 0;
+ bool isInitialized() const override { return true; }
+ QRemoteObjectReplica::State state() const override { return QRemoteObjectReplica::State(m_state.loadRelaxed()); }
+ void setState(QRemoteObjectReplica::State state);
+ bool waitForSource(int) override { return true; }
+ virtual bool waitForFinished(const QRemoteObjectPendingCall &, int) { return true; }
+ virtual void notifyAboutReply(int, const QVariant &) {}
+ virtual void configurePrivate(QRemoteObjectReplica *);
+ void emitInitialized();
+ void emitNotified();
+ QRemoteObjectNode *node() const override { return m_node; }
+
+ void _q_send(QMetaObject::Call call, int index, const QVariantList &args) override = 0;
+ QRemoteObjectPendingCall _q_sendWithReply(QMetaObject::Call call, int index, const QVariantList &args) override = 0;
+
+ //Dynamic replica functions
+ virtual void setDynamicMetaObject(const QMetaObject *meta);
+ virtual void setDynamicProperties(QVariantList &&values);
+
+ QString m_objectName;
+ const QMetaObject *m_metaObject;
+
+ //Dynamic Replica data
+ int m_numSignals;//TODO maybe here too
+ int m_methodOffset;
+ int m_signalOffset;
+ int m_propertyOffset;
+ QRemoteObjectNode *m_node;
+ QByteArray m_objectSignature;
+ QAtomicInt m_state;
+};
+
+class QConnectedReplicaImplementation final : public QRemoteObjectReplicaImplementation
+{
+public:
+ explicit QConnectedReplicaImplementation(const QString &name, const QMetaObject *, QRemoteObjectNode *);
+ ~QConnectedReplicaImplementation() override;
+ const QVariant getProperty(int i) const override;
+ void setProperties(QVariantList &&) override;
+ void setProperty(int i, const QVariant &) override;
+ bool isShortCircuit() const final { return false; }
+ bool isInitialized() const override;
+ bool waitForSource(int timeout) override;
+ QList<int> childIndices() const;
+ void initialize(QVariantList &&values);
+ void configurePrivate(QRemoteObjectReplica *) override;
+ void requestRemoteObjectSource();
+ bool sendCommand();
+ QRemoteObjectPendingCall sendCommandWithReply(int serialId);
+ bool waitForFinished(const QRemoteObjectPendingCall &call, int timeout) override;
+ void notifyAboutReply(int ackedSerialId, const QVariant &value) override;
+ void setConnection(QtROIoDeviceBase *conn);
+ void setDisconnected();
+
+ void _q_send(QMetaObject::Call call, int index, const QVariantList &args) override;
+ QRemoteObjectPendingCall _q_sendWithReply(QMetaObject::Call call, int index, const QVariantList& args) override;
+
+ void setDynamicMetaObject(const QMetaObject *meta) override;
+ void setDynamicProperties(QVariantList &&) override;
+ QList<QRemoteObjectReplica *> m_parentsNeedingConnect;
+ QVariantList m_propertyStorage;
+ QList<int> m_childIndices;
+ QPointer<QtROIoDeviceBase> connectionToSource;
+
+ // pending call data
+ int m_curSerialId = 1; // 0 is reserved for heartbeat signals
+ QHash<int, QRemoteObjectPendingCall> m_pendingCalls;
+ QTimer m_heartbeatTimer;
+};
+
+class QInProcessReplicaImplementation final : public QRemoteObjectReplicaImplementation
+{
+public:
+ explicit QInProcessReplicaImplementation(const QString &name, const QMetaObject *, QRemoteObjectNode *);
+ ~QInProcessReplicaImplementation() override;
+
+ const QVariant getProperty(int i) const override;
+ void setProperties(QVariantList &&) override;
+ void setProperty(int i, const QVariant &) override;
+ bool isShortCircuit() const final { return true; }
+
+ void _q_send(QMetaObject::Call call, int index, const QVariantList &args) override;
+ QRemoteObjectPendingCall _q_sendWithReply(QMetaObject::Call call, int index, const QVariantList& args) override;
+
+ QPointer<QRemoteObjectSourceBase> connectionToSource;
+};
+
+QT_END_NAMESPACE
+
+#endif
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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.LGPL3 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qremoteobjectsettingsstore.h"
+
+#include "qremoteobjectnode_p.h"
+
+#include <QtCore/private/qobject_p.h>
+#include <QtCore/qsettings.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype SettingsStore
+ \inqmlmodule QtRemoteObjects
+ \brief A basic store for persisted properties.
+
+ This type provides simple QSettings-based storage for properties marked as PERSISTED. It is used in
+ conjunction with Node::persistedStore:
+
+ \code
+ Node {
+ persistedStore: SettingsStore {}
+ }
+ \endcode
+*/
+
+class QRemoteObjectSettingsStorePrivate : public QRemoteObjectAbstractPersistedStorePrivate
+{
+public:
+ QRemoteObjectSettingsStorePrivate();
+ virtual ~QRemoteObjectSettingsStorePrivate();
+
+ QSettings settings;
+ Q_DECLARE_PUBLIC(QRemoteObjectSettingsStore)
+};
+
+QRemoteObjectSettingsStorePrivate::QRemoteObjectSettingsStorePrivate()
+{
+}
+
+QRemoteObjectSettingsStorePrivate::~QRemoteObjectSettingsStorePrivate()
+{
+}
+
+QRemoteObjectSettingsStore::QRemoteObjectSettingsStore(QObject *parent)
+ : QRemoteObjectAbstractPersistedStore(*new QRemoteObjectSettingsStorePrivate, parent)
+{
+}
+
+QRemoteObjectSettingsStore::~QRemoteObjectSettingsStore()
+{
+}
+
+QVariantList QRemoteObjectSettingsStore::restoreProperties(const QString &repName, const QByteArray &repSig)
+{
+ Q_D(QRemoteObjectSettingsStore);
+ d->settings.beginGroup(repName + QLatin1Char('/') + QString::fromLatin1(repSig));
+ QVariantList values = d->settings.value(QStringLiteral("values")).toList();
+ d->settings.endGroup();
+ return values;
+}
+
+void QRemoteObjectSettingsStore::saveProperties(const QString &repName, const QByteArray &repSig, const QVariantList &values)
+{
+ Q_D(QRemoteObjectSettingsStore);
+ d->settings.beginGroup(repName + QLatin1Char('/') + QString::fromLatin1(repSig));
+ d->settings.setValue(QStringLiteral("values"), values);
+ d->settings.endGroup();
+ d->settings.sync();
+}
+
+QT_END_NAMESPACE
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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.LGPL3 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QREMOTEOBJECTSETTINGSSTORE_H
+#define QREMOTEOBJECTSETTINGSSTORE_H
+
+#include <QtRemoteObjects/qremoteobjectnode.h>
+
+QT_BEGIN_NAMESPACE
+
+class QRemoteObjectSettingsStorePrivate;
+
+class Q_REMOTEOBJECTS_EXPORT QRemoteObjectSettingsStore : public QRemoteObjectAbstractPersistedStore
+{
+ Q_OBJECT
+
+public:
+ QRemoteObjectSettingsStore(QObject *parent = nullptr);
+ ~QRemoteObjectSettingsStore() override;
+
+ void saveProperties(const QString &repName, const QByteArray &repSig, const QVariantList &values) override;
+ QVariantList restoreProperties(const QString &repName, const QByteArray &repSig) override;
+
+private:
+ Q_DECLARE_PRIVATE(QRemoteObjectSettingsStore)
+};
+
+QT_END_NAMESPACE
+
+#endif // QREMOTEOBJECTSETTINGSSTORE_H
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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.LGPL3 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qremoteobjectsource.h"
+#include "qremoteobjectsource_p.h"
+#include "qremoteobjectnode.h"
+#include "qremoteobjectdynamicreplica.h"
+
+#include "qconnectionfactories_p.h"
+#include "qremoteobjectsourceio_p.h"
+#include "qremoteobjectabstractitemmodeladapter_p.h"
+
+#include <QtCore/qmetaobject.h>
+#include <QtCore/qvarlengtharray.h>
+#include <QtCore/qabstractitemmodel.h>
+
+#include <algorithm>
+#include <iterator>
+
+QT_BEGIN_NAMESPACE
+
+using namespace QRemoteObjectPackets;
+using namespace QRemoteObjectStringLiterals;
+
+const int QRemoteObjectSourceBase::qobjectPropertyOffset = QObject::staticMetaObject.propertyCount();
+const int QRemoteObjectSourceBase::qobjectMethodOffset = QObject::staticMetaObject.methodCount();
+static const QByteArray s_classinfoRemoteobjectSignature(QCLASSINFO_REMOTEOBJECT_SIGNATURE);
+
+namespace QtPrivate {
+
+// The stringData, methodMatch and QMetaObjectPrivate methods are modified versions of the code
+// from qmetaobject_p.h/qmetaobject.cpp. The modifications are based on our custom need to match
+// a method name that comes from the .rep file.
+// The QMetaObjectPrivate struct should only have members appended to maintain binary compatibility,
+// so we should be fine with only the listed version with the fields we use.
+inline const QByteArray apiStringData(const QMetaObject *mo, int index)
+{
+ uint offset = mo->d.stringdata[2*index];
+ uint length = mo->d.stringdata[2*index + 1];
+ const char *string = reinterpret_cast<const char *>(mo->d.stringdata) + offset;
+ return QByteArray::fromRawData(string, length);
+}
+
+
+// From QMetaMethod in qmetaobject.h
+struct Data {
+ enum { Size = 6 };
+
+ uint name() const { return d[0]; }
+ uint argc() const { return d[1]; }
+ uint parameters() const { return d[2]; }
+ uint tag() const { return d[3]; }
+ uint flags() const { return d[4]; }
+ uint metaTypeOffset() const { return d[5]; }
+ bool operator==(const Data &other) const { return d == other.d; }
+
+ const uint *d;
+};
+
+inline bool apiMethodMatch(const QMetaObject *m, const Data &data, const QByteArray &name, int argc,
+ const int *types)
+{
+ if (data.argc() != uint(argc))
+ return false;
+ if (apiStringData(m, data.name()) != name)
+ return false;
+ for (int i = 0; i < argc; ++i) {
+ auto mt = QMetaType(m->d.metaTypes[data.metaTypeOffset() + i + 1]);
+ if (mt != QMetaType(types[i]))
+ return false;
+ }
+ return true;
+}
+
+struct QMetaObjectPrivate
+{
+ // revision 7 is Qt 5.0 everything lower is not supported
+ // revision 8 is Qt 5.12: It adds the enum name to QMetaEnum
+ enum { OutputRevision = 8 }; // Used by moc, qmetaobjectbuilder and qdbus
+
+ int revision;
+ int className;
+ int classInfoCount, classInfoData;
+ int methodCount, methodData;
+ int propertyCount, propertyData;
+ int enumeratorCount, enumeratorData;
+ int constructorCount, constructorData;
+ int flags;
+ int signalCount;
+};
+
+inline Data fromRelativeMethodIndex(const QMetaObject *mobj, int index)
+{
+ const auto priv = reinterpret_cast<const QMetaObjectPrivate*>(mobj->d.data);
+ return { mobj->d.data + priv->methodData + index * Data::Size };
+}
+
+int qtro_method_index_impl(const QMetaObject * staticMetaObj, const char *className,
+ const char *methodName, int *count, int const **types)
+{
+ int result = staticMetaObj->indexOfMethod(methodName);
+ if (result >= 0)
+ return result;
+ // We can have issues, specifically with enums, since the compiler can infer the class. Since
+ // indexOfMethod() is doing string comparisons for registered types, "MyEnum" and "MyClass::MyEnum"
+ // won't match.
+ // Below is similar to QMetaObject->indexOfMethod, but template magic has already matched parameter
+ // types, so we need to find a match for the API method name + parameters. Neither approach works
+ // 100%, as the below code doesn't match a parameter of type "size_t" (which the template match
+ // identifies as "ulong"). These subtleties can cause the below string comparison fails.
+ // There is no known case that would fail both methods.
+ // TODO: is there a way to make this a constexpr so a failure is detected at compile time?
+ int nameLength = strchr(methodName, '(') - methodName;
+ const auto name = QByteArray::fromRawData(methodName, nameLength);
+ for (const QMetaObject *m = staticMetaObj; m; m = m->d.superdata) {
+ const auto priv = reinterpret_cast<const QMetaObjectPrivate*>(m->d.data);
+ int i = (priv->methodCount - 1);
+ const int end = priv->signalCount;
+ for (; i >= end; --i) {
+ const Data data = fromRelativeMethodIndex(m, i);
+ if (apiMethodMatch(m, data, name, *count, *types))
+ return i + m->methodOffset();
+ }
+ }
+ qWarning() << "No matching method for" << methodName << "in the provided metaclass" << className;
+ return -1;
+}
+
+} // namespace QtPrivate
+
+QByteArray QtPrivate::qtro_classinfo_signature(const QMetaObject *metaObject)
+{
+ if (!metaObject)
+ return QByteArray{};
+
+ for (int i = metaObject->classInfoOffset(); i < metaObject->classInfoCount(); ++i) {
+ auto ci = metaObject->classInfo(i);
+ if (s_classinfoRemoteobjectSignature == ci.name())
+ return ci.value();
+ }
+ return QByteArray{};
+}
+
+inline bool qtro_is_cloned_method(const QMetaObject *mobj, int index)
+{
+ int local_method_index = index - mobj->methodOffset();
+ if (local_method_index < 0 && mobj->superClass())
+ return qtro_is_cloned_method(mobj->superClass(), index);
+ const QtPrivate::Data data = QtPrivate::fromRelativeMethodIndex(mobj, local_method_index);
+ if (data.flags() & 0x20 /*MethodFlags::MethodCloned*/)
+ return true;
+ return false;
+}
+
+QRemoteObjectSourceBase::QRemoteObjectSourceBase(QObject *obj, Private *d, const SourceApiMap *api,
+ QObject *adapter)
+ : QObject(obj),
+ m_object(obj),
+ m_adapter(adapter),
+ m_api(api),
+ d(d)
+{
+ if (!obj) {
+ qCWarning(QT_REMOTEOBJECT) << "QRemoteObjectSourceBase: Cannot replicate a NULL object" << m_api->name();
+ return;
+ }
+
+ setConnections();
+
+ const auto nChildren = api->m_models.count() + api->m_subclasses.count();
+ if (nChildren > 0) {
+ QList<int> roles;
+ const int numProperties = api->propertyCount();
+ int modelIndex = 0, subclassIndex = 0;
+ for (int i = 0; i < numProperties; ++i) {
+ if (api->isAdapterProperty(i))
+ continue;
+ const int index = api->sourcePropertyIndex(i);
+ const auto property = m_object->metaObject()->property(index);
+ const auto metaType = property.metaType();
+ if (metaType.flags().testFlag(QMetaType::PointerToQObject)) {
+ auto propertyMeta = metaType.metaObject();
+ QObject *child = property.read(m_object).value<QObject *>();
+ const QMetaObject *meta = child ? child->metaObject() : propertyMeta;
+ if (!meta)
+ continue;
+ if (meta->inherits(&QAbstractItemModel::staticMetaObject)) {
+ const auto modelInfo = api->m_models.at(modelIndex++);
+ QAbstractItemModel *model = qobject_cast<QAbstractItemModel *>(child);
+ QAbstractItemAdapterSourceAPI<QAbstractItemModel, QAbstractItemModelSourceAdapter> *modelApi =
+ new QAbstractItemAdapterSourceAPI<QAbstractItemModel, QAbstractItemModelSourceAdapter>(modelInfo.name);
+ if (!model)
+ m_children.insert(i, new QRemoteObjectSource(nullptr, d, modelApi, nullptr, api->name()));
+ else {
+ roles.clear();
+ const auto knownRoles = model->roleNames();
+ for (auto role : modelInfo.roles.split('|')) {
+ if (role.isEmpty())
+ continue;
+ const int roleIndex = knownRoles.key(role, -1);
+ if (roleIndex == -1) {
+ qCWarning(QT_REMOTEOBJECT) << "Invalid role" << role << "for model" << model->metaObject()->className();
+ qCWarning(QT_REMOTEOBJECT) << " known roles:" << knownRoles;
+ } else
+ roles << roleIndex;
+ }
+ auto adapter = new QAbstractItemModelSourceAdapter(model, nullptr,
+ roles.isEmpty() ? knownRoles.keys().toVector() : roles);
+ m_children.insert(i, new QRemoteObjectSource(model, d, modelApi, adapter, api->name()));
+ }
+ } else {
+ const auto classApi = api->m_subclasses.at(subclassIndex++);
+ m_children.insert(i, new QRemoteObjectSource(child, d, classApi, nullptr, api->name()));
+ }
+ }
+ }
+ }
+}
+
+QRemoteObjectSource::QRemoteObjectSource(QObject *obj, Private *dd, const SourceApiMap *api, QObject *adapter, const QString &parentName)
+ : QRemoteObjectSourceBase(obj, dd, api, adapter)
+ , m_name(api->typeName() == QLatin1String("QAbstractItemModelAdapter") ? MODEL().arg(parentName + QLatin1String("::") + api->name()) :
+ CLASS().arg(parentName + QLatin1String("::") + api->name()))
+{
+ if (obj)
+ d->m_sourceIo->registerSource(this);
+}
+
+QRemoteObjectRootSource::QRemoteObjectRootSource(QObject *obj, const SourceApiMap *api,
+ QObject *adapter, QRemoteObjectSourceIo *sourceIo)
+ : QRemoteObjectSourceBase(obj, new Private(sourceIo, this), api, adapter)
+ , m_name(api->name())
+{
+ d->m_sourceIo->registerSource(this);
+}
+
+QRemoteObjectSourceBase::~QRemoteObjectSourceBase()
+{
+ delete m_api;
+}
+
+void QRemoteObjectSourceBase::setConnections()
+{
+ const QMetaObject *meta = m_object->metaObject();
+
+ const int index = meta->indexOfClassInfo(QCLASSINFO_REMOTEOBJECT_TYPE);
+ if (index != -1) { //We have an object created from repc or at least with QCLASSINFO defined
+ while (true) {
+ Q_ASSERT(meta->superClass()); //This recurses to QObject, which doesn't have QCLASSINFO_REMOTEOBJECT_TYPE
+ if (index != meta->superClass()->indexOfClassInfo(QCLASSINFO_REMOTEOBJECT_TYPE)) //At the point we don't find the same QCLASSINFO_REMOTEOBJECT_TYPE,
+ //we have the metaobject we should work from
+ break;
+ meta = meta->superClass();
+ }
+ }
+
+ for (int idx = 0; idx < m_api->signalCount(); ++idx) {
+ const int sourceIndex = m_api->sourceSignalIndex(idx);
+ const bool isAdapter = m_api->isAdapterSignal(idx);
+ const auto targetMeta = isAdapter ? m_adapter->metaObject() : meta;
+
+ // don't connect cloned signals, or we end up with multiple emissions
+ if (qtro_is_cloned_method(targetMeta, sourceIndex))
+ continue;
+ // This basically connects the parent Signals (note, all dynamic properties have onChange
+ //notifications, thus signals) to us. Normally each Signal is mapped to a unique index,
+ //but since we are forwarding them all, we keep the offset constant.
+ //
+ //We know no one will inherit from this class, so no need to worry about indices from
+ //derived classes.
+ const auto target = isAdapter ? m_adapter : m_object;
+ if (!QMetaObject::connect(target, sourceIndex, this, QRemoteObjectSource::qobjectMethodOffset+idx, Qt::DirectConnection, nullptr)) {
+ qCWarning(QT_REMOTEOBJECT) << "QRemoteObjectSourceBase: QMetaObject::connect returned false. Unable to connect.";
+ return;
+ }
+
+ qCDebug(QT_REMOTEOBJECT) << "Connection made" << idx << sourceIndex
+ << targetMeta->method(sourceIndex).name();
+ }
+}
+
+void QRemoteObjectSourceBase::resetObject(QObject *newObject)
+{
+ if (m_object)
+ m_object->disconnect(this);
+ if (m_adapter) {
+ m_adapter->disconnect(this);
+ delete m_adapter;
+ m_adapter = nullptr;
+ }
+ // We need some dynamic replica specific code here, in case an object had null sub-classes that
+ // have been replaced with real objects. In this case, the ApiMap could be wrong and need updating.
+ if (newObject && qobject_cast<QRemoteObjectDynamicReplica *>(newObject) && m_api->isDynamic()) {
+ auto api = static_cast<const DynamicApiMap*>(m_api);
+ if (api->m_properties[0] == 0) { // 0 is an index into QObject itself, so this isn't a valid QtRO index
+ const auto rep = qobject_cast<QRemoteObjectDynamicReplica *>(newObject);
+ auto tmp = m_api;
+ m_api = new DynamicApiMap(newObject, rep->metaObject(), api->m_name, QLatin1String(rep->metaObject()->className()));
+ qCDebug(QT_REMOTEOBJECT) << " Reset m_api for" << api->m_name << "using new metaObject:" << rep->metaObject()->className();
+ delete tmp;
+ }
+ }
+
+ m_object = newObject;
+ auto model = qobject_cast<QAbstractItemModel *>(newObject);
+ if (model) {
+ d->m_sourceIo->registerSource(this);
+ m_adapter = new QAbstractItemModelSourceAdapter(model, nullptr, model->roleNames().keys().toVector());
+ }
+
+ setParent(newObject);
+ if (newObject)
+ setConnections();
+
+ const auto nChildren = m_api->m_models.count() + m_api->m_subclasses.count();
+ if (nChildren == 0)
+ return;
+
+ if (!newObject) {
+ for (auto child : m_children)
+ child->resetObject(nullptr);
+ return;
+ }
+
+ for (int i : m_children.keys()) {
+ const int index = m_api->sourcePropertyIndex(i);
+ const auto property = m_object->metaObject()->property(index);
+ QObject *child = property.read(m_object).value<QObject *>();
+ m_children[i]->resetObject(child);
+ }
+}
+
+QRemoteObjectSource::~QRemoteObjectSource()
+{
+ for (auto it : m_children) {
+ // We used QPointers for m_children because we don't control the lifetime of child QObjects
+ // Since the this/source QObject's parent is the referenced QObject, it could have already
+ // been deleted
+ delete it;
+ }
+}
+
+QRemoteObjectRootSource::~QRemoteObjectRootSource()
+{
+ for (auto it : m_children) {
+ // We used QPointers for m_children because we don't control the lifetime of child QObjects
+ // Since the this/source QObject's parent is the referenced QObject, it could have already
+ // been deleted
+ delete it;
+ }
+ d->m_sourceIo->unregisterSource(this);
+ // removeListener tries to modify d->m_listeners, this is O(N²),
+ // so clear d->m_listeners prior to calling unregister (consume loop).
+ // We can do this, because we don't care about the return value of removeListener() here.
+ for (QtROIoDeviceBase *io : qExchange(d->m_listeners, {})) {
+ removeListener(io, true);
+ }
+ delete d;
+}
+
+QVariantList* QRemoteObjectSourceBase::marshalArgs(int index, void **a)
+{
+ QVariantList &list = m_marshalledArgs;
+ int N = m_api->signalParameterCount(index);
+ if (N == 1 && QMetaType(m_api->signalParameterType(index, 0)).flags().testFlag(QMetaType::PointerToQObject))
+ N = 0; // Don't try to send pointers, the will be handle by QRO_
+ if (list.size() < N)
+ list.reserve(N);
+ const int minFill = std::min(int(list.size()), N);
+ for (int i = 0; i < minFill; ++i) {
+ const int type = m_api->signalParameterType(index, i);
+ if (type == QMetaType::QVariant)
+ list[i] = *reinterpret_cast<QVariant *>(a[i + 1]);
+ else
+ list[i] = QVariant(QMetaType(type), a[i + 1]);
+ }
+ for (int i = int(list.size()); i < N; ++i) {
+ const int type = m_api->signalParameterType(index, i);
+ if (type == QMetaType::QVariant)
+ list << *reinterpret_cast<QVariant *>(a[i + 1]);
+ else
+ list << QVariant(QMetaType(type), a[i + 1]);
+ }
+ for (int i = N; i < list.size(); ++i)
+ list.removeLast();
+ return &m_marshalledArgs;
+}
+
+bool QRemoteObjectSourceBase::invoke(QMetaObject::Call c, int index, const QVariantList &args, QVariant* returnValue)
+{
+ int status = -1;
+ int flags = 0;
+ bool forAdapter = (c == QMetaObject::InvokeMetaMethod ? m_api->isAdapterMethod(index) : m_api->isAdapterProperty(index));
+ int resolvedIndex = (c == QMetaObject::InvokeMetaMethod ? m_api->sourceMethodIndex(index) : m_api->sourcePropertyIndex(index));
+ if (resolvedIndex < 0)
+ return false;
+ QVarLengthArray<void*, 10> param(args.size() + 1);
+
+ if (c == QMetaObject::InvokeMetaMethod) {
+ QMetaMethod method;
+ if (!forAdapter)
+ method = parent()->metaObject()->method(resolvedIndex);
+
+ if (returnValue) {
+ if (!forAdapter && method.isValid() && method.returnType() == QMetaType::QVariant)
+ param[0] = const_cast<void*>(reinterpret_cast<const void*>(returnValue));
+ else
+ param[0] = returnValue->data();
+ } else {
+ param[0] = nullptr;
+ }
+
+ auto argument = [&](int i) -> void * {
+ if ((forAdapter && m_api->methodParameterType(index, i) == QMetaType::QVariant) ||
+ (method.isValid() && method.parameterType(i) == QMetaType::QVariant)) {
+ return const_cast<void*>(reinterpret_cast<const void*>(&args.at(i)));
+ }
+ return const_cast<void*>(args.at(i).data());
+ };
+
+ for (int i = 0; i < args.size(); ++i) {
+ param[i + 1] = argument(i);
+ }
+ } else if (c == QMetaObject::WriteProperty || c == QMetaObject::ReadProperty) {
+ bool isQVariant = !forAdapter && parent()->metaObject()->property(resolvedIndex).userType() == QMetaType::QVariant;
+ for (int i = 0; i < args.size(); ++i) {
+ if (isQVariant)
+ param[i] = const_cast<void*>(reinterpret_cast<const void*>(&args.at(i)));
+ else
+ param[i] = const_cast<void*>(args.at(i).data());
+ }
+ if (c == QMetaObject::WriteProperty) {
+ Q_ASSERT(param.size() == 2); // for return-value and setter value
+ // check QMetaProperty::write for an explanation of these
+ param.append(&status);
+ param.append(&flags);
+ }
+ } else {
+ // Better safe than sorry
+ return false;
+ }
+ int r = -1;
+ if (forAdapter)
+ r = m_adapter->qt_metacall(c, resolvedIndex, param.data());
+ else
+ r = parent()->qt_metacall(c, resolvedIndex, param.data());
+ return r == -1 && status == -1;
+}
+
+void QRemoteObjectSourceBase::handleMetaCall(int index, QMetaObject::Call call, void **a)
+{
+ if (d->m_listeners.empty())
+ return;
+
+ int propertyIndex = m_api->propertyIndexFromSignal(index);
+ if (propertyIndex >= 0) {
+ const int internalIndex = m_api->propertyRawIndexFromSignal(index);
+ const auto target = m_api->isAdapterProperty(internalIndex) ? m_adapter : m_object;
+ const QMetaProperty mp = target->metaObject()->property(propertyIndex);
+ qCDebug(QT_REMOTEOBJECT) << "Sending Invoke Property" << (m_api->isAdapterSignal(internalIndex) ? "via adapter" : "") << internalIndex << propertyIndex << mp.name() << mp.read(target);
+
+ d->codec->serializePropertyChangePacket(this, index);
+ propertyIndex = internalIndex;
+ }
+
+ qCDebug(QT_REMOTEOBJECT) << "# Listeners" << d->m_listeners.length();
+ qCDebug(QT_REMOTEOBJECT) << "Invoke args:" << m_object
+ << (call == 0 ? QLatin1String("InvokeMetaMethod") : QStringLiteral("Non-invoked call: %d").arg(call))
+ << m_api->signalSignature(index) << *marshalArgs(index, a);
+
+ d->codec->serializeInvokePacket(name(), call, index, *marshalArgs(index, a), -1, propertyIndex);
+
+ d->codec->send(d->m_listeners);
+}
+
+void QRemoteObjectRootSource::addListener(QtROIoDeviceBase *io, bool dynamic)
+{
+ d->m_listeners.append(io);
+ d->isDynamic = d->isDynamic || dynamic;
+
+ if (dynamic) {
+ d->sentTypes.clear();
+ d->codec->serializeInitDynamicPacket(this);
+ d->codec->send(io);
+ } else {
+ d->codec->serializeInitPacket(this);
+ d->codec->send(io);
+ }
+}
+
+int QRemoteObjectRootSource::removeListener(QtROIoDeviceBase *io, bool shouldSendRemove)
+{
+ d->m_listeners.removeAll(io);
+ if (shouldSendRemove)
+ {
+ d->codec->serializeRemoveObjectPacket(m_api->name());
+ d->codec->send(io);
+ }
+ return int(d->m_listeners.length());
+}
+
+int QRemoteObjectSourceBase::qt_metacall(QMetaObject::Call call, int methodId, void **a)
+{
+ methodId = QObject::qt_metacall(call, methodId, a);
+ if (methodId < 0)
+ return methodId;
+
+ if (call == QMetaObject::InvokeMetaMethod)
+ handleMetaCall(methodId, call, a);
+
+ return -1;
+}
+
+DynamicApiMap::DynamicApiMap(QObject *object, const QMetaObject *metaObject, const QString &name, const QString &typeName)
+ : m_name(name),
+ m_typeName(typeName),
+ m_metaObject(metaObject),
+ m_cachedMetamethodIndex(-1)
+{
+ m_enumOffset = metaObject->enumeratorOffset();
+ m_enumCount = metaObject->enumeratorCount() - m_enumOffset;
+
+ const int propCount = metaObject->propertyCount();
+ const int propOffset = metaObject->propertyOffset();
+ m_properties.reserve(propCount-propOffset);
+ QSet<int> invalidSignals;
+ for (int i = propOffset; i < propCount; ++i) {
+ const QMetaProperty property = metaObject->property(i);
+ const auto metaType = property.metaType();
+ if (metaType.flags().testFlag(QMetaType::PointerToQObject)) {
+ auto propertyMeta = metaType.metaObject();
+ QObject *child = property.read(object).value<QObject *>();
+ const QMetaObject *meta = child ? child->metaObject() : propertyMeta;
+ if (!meta) {
+ const int notifyIndex = metaObject->property(i).notifySignalIndex();
+ if (notifyIndex != -1)
+ invalidSignals << notifyIndex;
+ continue;
+ }
+ if (meta->inherits(&QAbstractItemModel::staticMetaObject)) {
+ const QByteArray name = QByteArray::fromRawData(property.name(),
+ qsizetype(qstrlen(property.name())));
+ const QByteArray infoName = name.toUpper() + QByteArrayLiteral("_ROLES");
+ const int infoIndex = metaObject->indexOfClassInfo(infoName.constData());
+ QByteArray roleInfo;
+ if (infoIndex >= 0) {
+ auto ci = metaObject->classInfo(infoIndex);
+ roleInfo = QByteArray::fromRawData(ci.value(), qsizetype(qstrlen(ci.value())));
+ }
+ m_models << ModelInfo({qobject_cast<QAbstractItemModel *>(child),
+ QString::fromLatin1(property.name()),
+ roleInfo});
+ } else {
+ QString typeName = QtRemoteObjects::getTypeNameAndMetaobjectFromClassInfo(meta);
+ if (typeName.isNull()) {
+ typeName = QString::fromLatin1(meta->className());
+ if (typeName.contains(QLatin1String("QQuick")))
+ typeName.remove(QLatin1String("QQuick"));
+ else if (int index = typeName.indexOf(QLatin1String("_QMLTYPE_")))
+ typeName.truncate(index);
+ // TODO better way to ensure we have consistent typenames between source/replicas?
+ else if (typeName.endsWith(QLatin1String("Source")))
+ typeName.chop(6);
+ }
+
+ m_subclasses << new DynamicApiMap(child, meta, QString::fromLatin1(property.name()), typeName);
+ }
+ }
+ m_properties << i;
+ const int notifyIndex = metaObject->property(i).notifySignalIndex();
+ if (notifyIndex != -1) {
+ m_signals << notifyIndex;
+ m_propertyAssociatedWithSignal.append(i-propOffset);
+ //The starting values of _signals will be the notify signals
+ //So if we are processing _signal with index i, api->sourcePropertyIndex(_propertyAssociatedWithSignal.at(i))
+ //will be the property that changed. This is only valid if i < _propertyAssociatedWithSignal.size().
+ }
+ }
+ const int methodCount = metaObject->methodCount();
+ const int methodOffset = metaObject->methodOffset();
+ for (int i = methodOffset; i < methodCount; ++i) {
+ const QMetaMethod mm = metaObject->method(i);
+ const QMetaMethod::MethodType m = mm.methodType();
+ if (m == QMetaMethod::Signal) {
+ if (m_signals.indexOf(i) >= 0) // Already added as a property notifier
+ continue;
+ if (invalidSignals.contains(i)) // QObject with no metatype
+ continue;
+ m_signals << i;
+ } else if (m == QMetaMethod::Slot || m == QMetaMethod::Method)
+ m_methods << i;
+ }
+
+ m_objectSignature = QtPrivate::qtro_classinfo_signature(metaObject);
+}
+
+QByteArrayList DynamicApiMap::signalParameterNames(int index) const
+{
+ const int objectIndex = m_signals.at(index);
+ checkCache(objectIndex);
+ return m_cachedMetamethod.parameterNames();
+}
+
+int DynamicApiMap::parameterCount(int objectIndex) const
+{
+ checkCache(objectIndex);
+ return m_cachedMetamethod.parameterCount();
+}
+
+int DynamicApiMap::parameterType(int objectIndex, int paramIndex) const
+{
+ checkCache(objectIndex);
+ return m_cachedMetamethod.parameterType(paramIndex);
+}
+
+const QByteArray DynamicApiMap::signature(int objectIndex) const
+{
+ checkCache(objectIndex);
+ return m_cachedMetamethod.methodSignature();
+}
+
+QMetaMethod::MethodType DynamicApiMap::methodType(int index) const
+{
+ const int objectIndex = m_methods.at(index);
+ checkCache(objectIndex);
+ return m_cachedMetamethod.methodType();
+}
+
+const QByteArray DynamicApiMap::typeName(int index) const
+{
+ const int objectIndex = m_methods.at(index);
+ checkCache(objectIndex);
+ return m_cachedMetamethod.typeName();
+}
+
+QByteArrayList DynamicApiMap::methodParameterNames(int index) const
+{
+ const int objectIndex = m_methods.at(index);
+ checkCache(objectIndex);
+ return m_cachedMetamethod.parameterNames();
+}
+
+QRemoteObjectSourceBase::Private::Private(QRemoteObjectSourceIo *io, QRemoteObjectRootSource *root)
+ : m_sourceIo(io), codec(io->m_codec.data()), isDynamic(false), root(root)
+{
+}
+
+QT_END_NAMESPACE
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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.LGPL3 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QREMOTEOBJECTSOURCE_H
+#define QREMOTEOBJECTSOURCE_H
+
+#include <QtCore/qscopedpointer.h>
+#include <QtRemoteObjects/qtremoteobjectglobal.h>
+#include <QtCore/qmetaobject.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QtPrivate {
+
+//Based on compile time checks for static connect() from qobjectdefs_impl.h
+template <class ObjectType, typename Func1, typename Func2>
+static inline int qtro_property_index(Func1, Func2, const char *propName)
+{
+ typedef QtPrivate::FunctionPointer<Func1> Type1;
+ typedef QtPrivate::FunctionPointer<Func2> Type2;
+
+ //compilation error if the arguments do not match.
+ Q_STATIC_ASSERT_X(int(Type1::ArgumentCount) >= int(Type2::ArgumentCount),
+ "Argument counts are not compatible.");
+ Q_STATIC_ASSERT_X((QtPrivate::CheckCompatibleArguments<typename Type1::Arguments, typename Type2::Arguments>::value),
+ "Arguments are not compatible.");
+ Q_STATIC_ASSERT_X((QtPrivate::AreArgumentsCompatible<typename Type1::ReturnType, typename Type2::ReturnType>::value),
+ "Return types are not compatible.");
+ return ObjectType::staticMetaObject.indexOfProperty(propName);
+}
+
+template <class ObjectType, typename Func1, typename Func2>
+static inline int qtro_signal_index(Func1 func, Func2, int *count, int const **types)
+{
+ typedef QtPrivate::FunctionPointer<Func1> Type1;
+ typedef QtPrivate::FunctionPointer<Func2> Type2;
+
+ //compilation error if the arguments do not match.
+ Q_STATIC_ASSERT_X(int(Type1::ArgumentCount) >= int(Type2::ArgumentCount),
+ "Argument counts are not compatible.");
+ Q_STATIC_ASSERT_X((QtPrivate::CheckCompatibleArguments<typename Type1::Arguments, typename Type2::Arguments>::value),
+ "Arguments are not compatible.");
+ Q_STATIC_ASSERT_X((QtPrivate::AreArgumentsCompatible<typename Type1::ReturnType, typename Type2::ReturnType>::value),
+ "Return types are not compatible.");
+ const QMetaMethod sig = QMetaMethod::fromSignal(func);
+ *count = Type2::ArgumentCount;
+ *types = QtPrivate::ConnectionTypes<typename Type2::Arguments>::types();
+ return sig.methodIndex();
+}
+
+template <class ObjectType, typename Func1, typename Func2>
+static inline void qtro_method_test(Func1, Func2)
+{
+ typedef QtPrivate::FunctionPointer<Func1> Type1;
+ typedef QtPrivate::FunctionPointer<Func2> Type2;
+
+ //compilation error if the arguments do not match.
+ Q_STATIC_ASSERT_X(int(Type1::ArgumentCount) >= int(Type2::ArgumentCount),
+ "Argument counts are not compatible.");
+ Q_STATIC_ASSERT_X((QtPrivate::CheckCompatibleArguments<typename Type1::Arguments, typename Type2::Arguments>::value),
+ "Arguments are not compatible.");
+ Q_STATIC_ASSERT_X((QtPrivate::AreArgumentsCompatible<typename Type1::ReturnType, typename Type2::ReturnType>::value),
+ "Return types are not compatible.");
+}
+
+Q_REMOTEOBJECTS_EXPORT
+int qtro_method_index_impl(const QMetaObject *staticMetaObj, const char *className,
+ const char *methodName, int *count, const int **types);
+
+template <class ObjectType, typename Func1, typename Func2>
+static inline int qtro_method_index(Func1, Func2, const char *methodName, int *count, int const **types)
+{
+ typedef QtPrivate::FunctionPointer<Func1> Type1;
+ typedef QtPrivate::FunctionPointer<Func2> Type2;
+
+ //compilation error if the arguments do not match.
+ Q_STATIC_ASSERT_X(int(Type1::ArgumentCount) >= int(Type2::ArgumentCount),
+ "Argument counts are not compatible.");
+ Q_STATIC_ASSERT_X((QtPrivate::CheckCompatibleArguments<typename Type1::Arguments, typename Type2::Arguments>::value),
+ "Arguments are not compatible.");
+ Q_STATIC_ASSERT_X((QtPrivate::AreArgumentsCompatible<typename Type1::ReturnType, typename Type2::ReturnType>::value),
+ "Return types are not compatible.");
+ *count = Type2::ArgumentCount;
+ *types = QtPrivate::ConnectionTypes<typename Type2::Arguments>::types();
+
+ return qtro_method_index_impl(&ObjectType::staticMetaObject,
+ ObjectType::staticMetaObject.className(), methodName, count,
+ types);
+}
+
+template <class ObjectType>
+static inline QByteArray qtro_enum_signature(const char *enumName)
+{
+ const auto qme = ObjectType::staticMetaObject.enumerator(ObjectType::staticMetaObject.indexOfEnumerator(enumName));
+ return QByteArrayLiteral("1::2").replace("1", qme.scope()).replace("2", qme.name());
+}
+
+QByteArray qtro_classinfo_signature(const QMetaObject *metaObject);
+
+}
+
+// TODO ModelInfo just needs roles, and no need for SubclassInfo
+class QAbstractItemModel;
+
+struct ModelInfo
+{
+ QAbstractItemModel *ptr;
+ QString name;
+ QByteArray roles;
+};
+
+class SourceApiMap
+{
+protected:
+ SourceApiMap() {}
+public:
+ virtual ~SourceApiMap() {}
+ virtual QString name() const = 0;
+ virtual QString typeName() const = 0;
+ virtual QByteArray className() const { return typeName().toLatin1().append("Source"); }
+ virtual int enumCount() const = 0;
+ virtual int propertyCount() const = 0;
+ virtual int signalCount() const = 0;
+ virtual int methodCount() const = 0;
+ virtual int sourceEnumIndex(int index) const = 0;
+ virtual int sourcePropertyIndex(int index) const = 0;
+ virtual int sourceSignalIndex(int index) const = 0;
+ virtual int sourceMethodIndex(int index) const = 0;
+ virtual int signalParameterCount(int index) const = 0;
+ virtual int signalParameterType(int sigIndex, int paramIndex) const = 0;
+ virtual const QByteArray signalSignature(int index) const = 0;
+ virtual QByteArrayList signalParameterNames(int index) const = 0;
+ virtual int methodParameterCount(int index) const = 0;
+ virtual int methodParameterType(int methodIndex, int paramIndex) const = 0;
+ virtual const QByteArray methodSignature(int index) const = 0;
+ virtual QMetaMethod::MethodType methodType(int index) const = 0;
+ virtual const QByteArray typeName(int index) const = 0;
+ virtual QByteArrayList methodParameterNames(int index) const = 0;
+ virtual int propertyIndexFromSignal(int index) const = 0;
+ virtual int propertyRawIndexFromSignal(int index) const = 0;
+ virtual QByteArray objectSignature() const = 0;
+ virtual bool isDynamic() const { return false; }
+ virtual bool isAdapterSignal(int) const { return false; }
+ virtual bool isAdapterMethod(int) const { return false; }
+ virtual bool isAdapterProperty(int) const { return false; }
+ QList<ModelInfo> m_models;
+ QList<SourceApiMap *> m_subclasses;
+};
+
+QT_END_NAMESPACE
+
+#endif
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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.LGPL3 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QREMOTEOBJECTSOURCE_P_H
+#define QREMOTEOBJECTSOURCE_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qlist.h>
+#include <QtCore/qmetaobject.h>
+#include <QtCore/qobject.h>
+#include <QtCore/qpointer.h>
+#include "qremoteobjectsource.h"
+#include "qremoteobjectpacket_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QRemoteObjectSourceIo;
+class QtROIoDeviceBase;
+
+class QRemoteObjectSourceBase : public QObject
+{
+public:
+ ~QRemoteObjectSourceBase() override;
+
+ void setConnections();
+ void resetObject(QObject *newObject);
+ int qt_metacall(QMetaObject::Call call, int methodId, void **a) final;
+ QObject *m_object, *m_adapter;
+ const SourceApiMap *m_api;
+ QVariantList m_marshalledArgs;
+ bool hasAdapter() const { return m_adapter; }
+ virtual QString name() const = 0;
+ virtual bool isRoot() const = 0;
+
+ QVariantList* marshalArgs(int index, void **a);
+ void handleMetaCall(int index, QMetaObject::Call call, void **a);
+ bool invoke(QMetaObject::Call c, int index, const QVariantList& args, QVariant* returnValue = nullptr);
+ QByteArray m_objectChecksum;
+ QMap<int, QPointer<QRemoteObjectSourceBase>> m_children;
+ struct Private {
+ Private(QRemoteObjectSourceIo *io, QRemoteObjectRootSource *root);
+ QRemoteObjectSourceIo *m_sourceIo;
+ QList<QtROIoDeviceBase*> m_listeners;
+ // Pointer to codec, not owned by Private. We can assume it is valid.
+ QRemoteObjectPackets::CodecBase *codec;
+
+ // Types needed during recursively sending a root to a new listener
+ QSet<QString> sentTypes;
+ bool isDynamic;
+ QRemoteObjectRootSource *root;
+ };
+ Private *d;
+ static const int qobjectPropertyOffset;
+ static const int qobjectMethodOffset;
+protected:
+ explicit QRemoteObjectSourceBase(QObject *object, Private *d, const SourceApiMap *, QObject *adapter);
+};
+
+class QRemoteObjectSource : public QRemoteObjectSourceBase
+{
+public:
+ explicit QRemoteObjectSource(QObject *object, Private *d, const SourceApiMap *, QObject *adapter, const QString &parentName);
+ ~QRemoteObjectSource() override;
+
+ bool isRoot() const override { return false; }
+ QString name() const override { return m_name; }
+
+ QString m_name;
+};
+
+class QRemoteObjectRootSource : public QRemoteObjectSourceBase
+{
+public:
+ explicit QRemoteObjectRootSource(QObject *object, const SourceApiMap *,
+ QObject *adapter, QRemoteObjectSourceIo *sourceIo);
+ ~QRemoteObjectRootSource() override;
+
+ bool isRoot() const override { return true; }
+ QString name() const override { return m_name; }
+ void addListener(QtROIoDeviceBase *io, bool dynamic = false);
+ int removeListener(QtROIoDeviceBase *io, bool shouldSendRemove = false);
+
+ QString m_name;
+};
+
+class DynamicApiMap final : public SourceApiMap
+{
+public:
+ DynamicApiMap(QObject *object, const QMetaObject *metaObject, const QString &name, const QString &typeName);
+ ~DynamicApiMap() override {}
+ QString name() const override { return m_name; }
+ QString typeName() const override { return m_typeName; }
+ QByteArray className() const override { return QByteArray(m_metaObject->className()); }
+ int enumCount() const override { return m_enumCount; }
+ int propertyCount() const override { return m_properties.size(); }
+ int signalCount() const override { return m_signals.size(); }
+ int methodCount() const override { return m_methods.size(); }
+ int sourceEnumIndex(int index) const override
+ {
+ if (index < 0 || index >= enumCount())
+ return -1;
+ return m_enumOffset + index;
+ }
+ int sourcePropertyIndex(int index) const override
+ {
+ if (index < 0 || index >= propertyCount())
+ return -1;
+ return m_properties.at(index);
+ }
+ int sourceSignalIndex(int index) const override
+ {
+ if (index < 0 || index >= signalCount())
+ return -1;
+ return m_signals.at(index);
+ }
+ int sourceMethodIndex(int index) const override
+ {
+ if (index < 0 || index >= methodCount())
+ return -1;
+ return m_methods.at(index);
+ }
+ int signalParameterCount(int index) const override { return parameterCount(m_signals.at(index)); }
+ int signalParameterType(int sigIndex, int paramIndex) const override { return parameterType(m_signals.at(sigIndex), paramIndex); }
+ const QByteArray signalSignature(int index) const override { return signature(m_signals.at(index)); }
+ QByteArrayList signalParameterNames(int index) const override;
+
+ int methodParameterCount(int index) const override { return parameterCount(m_methods.at(index)); }
+ int methodParameterType(int methodIndex, int paramIndex) const override { return parameterType(m_methods.at(methodIndex), paramIndex); }
+ const QByteArray methodSignature(int index) const override { return signature(m_methods.at(index)); }
+ QMetaMethod::MethodType methodType(int index) const override;
+ const QByteArray typeName(int index) const override;
+ QByteArrayList methodParameterNames(int index) const override;
+
+ int propertyIndexFromSignal(int index) const override
+ {
+ if (index >= 0 && index < m_propertyAssociatedWithSignal.size())
+ return m_properties.at(m_propertyAssociatedWithSignal.at(index));
+ return -1;
+ }
+ int propertyRawIndexFromSignal(int index) const override
+ {
+ if (index >= 0 && index < m_propertyAssociatedWithSignal.size())
+ return m_propertyAssociatedWithSignal.at(index);
+ return -1;
+ }
+ QByteArray objectSignature() const override { return m_objectSignature; }
+
+ bool isDynamic() const override { return true; }
+
+ int parameterCount(int objectIndex) const;
+ int parameterType(int objectIndex, int paramIndex) const;
+ const QByteArray signature(int objectIndex) const;
+ inline void checkCache(int objectIndex) const
+ {
+ if (objectIndex != m_cachedMetamethodIndex) {
+ m_cachedMetamethodIndex = objectIndex;
+ m_cachedMetamethod = m_metaObject->method(objectIndex);
+ }
+ }
+
+ QString m_name;
+ QString m_typeName;
+ int m_enumCount;
+ int m_enumOffset;
+ QList<int> m_properties;
+ QList<int> m_signals;
+ QList<int> m_methods;
+ QList<int> m_propertyAssociatedWithSignal;
+ const QMetaObject *m_metaObject;
+ mutable QMetaMethod m_cachedMetamethod;
+ mutable int m_cachedMetamethodIndex;
+ QByteArray m_objectSignature;
+};
+
+QT_END_NAMESPACE
+
+#endif
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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.LGPL3 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qremoteobjectsourceio_p.h"
+
+#include "qremoteobjectpacket_p.h"
+#include "qremoteobjectsource_p.h"
+#include "qremoteobjectnode_p.h"
+#include "qremoteobjectpendingcall.h"
+#include "qtremoteobjectglobal.h"
+
+#include <QtCore/qstringlist.h>
+
+QT_BEGIN_NAMESPACE
+
+using namespace QtRemoteObjects;
+
+QRemoteObjectSourceIo::QRemoteObjectSourceIo(const QUrl &address, QObject *parent)
+ : QObject(parent)
+ , m_server(QtROServerFactory::instance()->isValid(address) ?
+ QtROServerFactory::instance()->create(address, this) : nullptr)
+ , m_address(address)
+{
+ if (m_server == nullptr)
+ qRODebug(this) << "Using" << m_address << "as external url.";
+}
+
+QRemoteObjectSourceIo::QRemoteObjectSourceIo(QObject *parent)
+ : QObject(parent)
+ , m_server(nullptr)
+{
+}
+
+QRemoteObjectSourceIo::~QRemoteObjectSourceIo()
+{
+ qDeleteAll(m_sourceRoots.values());
+}
+
+bool QRemoteObjectSourceIo::startListening()
+{
+ if (!m_server->listen(m_address)) {
+ qROCritical(this) << "Listen failed for URL:" << m_address;
+ qROCritical(this) << m_server->serverError();
+ return false;
+ }
+
+ qRODebug(this) << "QRemoteObjectSourceIo is Listening" << m_address;
+ connect(m_server.data(), &QConnectionAbstractServer::newConnection, this,
+ &QRemoteObjectSourceIo::handleConnection);
+ return true;
+}
+
+bool QRemoteObjectSourceIo::enableRemoting(QObject *object, const QMetaObject *meta, const QString &name, const QString &typeName)
+{
+ if (m_sourceRoots.contains(name)) {
+ qROWarning(this) << "Tried to register QRemoteObjectRootSource twice" << name;
+ return false;
+ }
+
+ return enableRemoting(object, new DynamicApiMap(object, meta, name, typeName));
+}
+
+bool QRemoteObjectSourceIo::enableRemoting(QObject *object, const SourceApiMap *api, QObject *adapter)
+{
+ const QString name = api->name();
+ if (!api->isDynamic() && m_sourceRoots.contains(name)) {
+ qROWarning(this) << "Tried to register QRemoteObjectRootSource twice" << name;
+ return false;
+ }
+
+ new QRemoteObjectRootSource(object, api, adapter, this);
+ m_codec->serializeObjectListPacket({QRemoteObjectPackets::ObjectInfo{api->name(), api->typeName(), api->objectSignature()}});
+ m_codec->send(m_connections);
+ if (const int count = m_connections.size())
+ qRODebug(this) << "Wrote new QObjectListPacket for" << api->name() << "to" << count << "connections";
+ return true;
+}
+
+bool QRemoteObjectSourceIo::disableRemoting(QObject *object)
+{
+ QRemoteObjectRootSource *source = m_objectToSourceMap.take(object);
+ if (!source)
+ return false;
+
+ delete source;
+ return true;
+}
+
+void QRemoteObjectSourceIo::registerSource(QRemoteObjectSourceBase *source)
+{
+ Q_ASSERT(source);
+ const QString &name = source->name();
+ m_sourceObjects[name] = source;
+ if (source->isRoot()) {
+ QRemoteObjectRootSource *root = static_cast<QRemoteObjectRootSource *>(source);
+ qRODebug(this) << "Registering" << name;
+ m_sourceRoots[name] = root;
+ m_objectToSourceMap[source->m_object] = root;
+ if (serverAddress().isValid()) {
+ const auto &type = source->m_api->typeName();
+ emit remoteObjectAdded(qMakePair(name, QRemoteObjectSourceLocationInfo(type, serverAddress())));
+ }
+ }
+}
+
+void QRemoteObjectSourceIo::unregisterSource(QRemoteObjectSourceBase *source)
+{
+ Q_ASSERT(source);
+ const QString &name = source->name();
+ m_sourceObjects.remove(name);
+ if (source->isRoot()) {
+ const auto type = source->m_api->typeName();
+ m_objectToSourceMap.remove(source->m_object);
+ m_sourceRoots.remove(name);
+ if (serverAddress().isValid())
+ emit remoteObjectRemoved(qMakePair(name, QRemoteObjectSourceLocationInfo(type, serverAddress())));
+ }
+}
+
+void QRemoteObjectSourceIo::onServerDisconnect(QObject *conn)
+{
+ QtROIoDeviceBase *connection = qobject_cast<QtROIoDeviceBase*>(conn);
+ m_connections.remove(connection);
+
+ qRODebug(this) << "OnServerDisconnect";
+
+ for (QRemoteObjectRootSource *root : qAsConst(m_sourceRoots))
+ root->removeListener(connection);
+
+ const QUrl location = m_registryMapping.value(connection);
+ emit serverRemoved(location);
+ m_registryMapping.remove(connection);
+ connection->close();
+ connection->deleteLater();
+}
+
+void QRemoteObjectSourceIo::onServerRead(QObject *conn)
+{
+ // Assert the invariant here conn is of type QIODevice
+ QtROIoDeviceBase *connection = qobject_cast<QtROIoDeviceBase*>(conn);
+ QRemoteObjectPacketTypeEnum packetType;
+
+ do {
+
+ if (!connection->read(packetType, m_rxName))
+ return;
+
+ using namespace QRemoteObjectPackets;
+
+ switch (packetType) {
+ case Ping:
+ m_codec->serializePongPacket(m_rxName);
+ m_codec->send(connection);
+ break;
+ case AddObject:
+ {
+ bool isDynamic;
+ m_codec->deserializeAddObjectPacket(connection->d_func()->stream(), isDynamic);
+ qRODebug(this) << "AddObject" << m_rxName << isDynamic;
+ if (m_sourceRoots.contains(m_rxName)) {
+ QRemoteObjectRootSource *root = m_sourceRoots[m_rxName];
+ root->addListener(connection, isDynamic);
+ } else {
+ qROWarning(this) << "Request to attach to non-existent RemoteObjectSource:" << m_rxName;
+ }
+ break;
+ }
+ case RemoveObject:
+ {
+ qRODebug(this) << "RemoveObject" << m_rxName;
+ if (m_sourceRoots.contains(m_rxName)) {
+ QRemoteObjectRootSource *root = m_sourceRoots[m_rxName];
+ const int count = root->removeListener(connection);
+ Q_UNUSED(count);
+ //TODO - possible to have a timer that closes connections if not reopened within a timeout?
+ } else {
+ qROWarning(this) << "Request to detach from non-existent RemoteObjectSource:" << m_rxName;
+ }
+ qRODebug(this) << "RemoveObject finished" << m_rxName;
+ break;
+ }
+ case InvokePacket:
+ {
+ int call, index, serialId, propertyId;
+ m_codec->deserializeInvokePacket(connection->d_func()->stream(), call, index, m_rxArgs, serialId, propertyId);
+ if (m_rxName == QLatin1String("Registry") && !m_registryMapping.contains(connection)) {
+ const QRemoteObjectSourceLocation loc = m_rxArgs.first().value<QRemoteObjectSourceLocation>();
+ m_registryMapping[connection] = loc.second.hostUrl;
+ }
+ if (m_sourceObjects.contains(m_rxName)) {
+ QRemoteObjectSourceBase *source = m_sourceObjects[m_rxName];
+ if (call == QMetaObject::InvokeMetaMethod) {
+ const int resolvedIndex = source->m_api->sourceMethodIndex(index);
+ if (resolvedIndex < 0) { //Invalid index
+ qROWarning(this) << "Invalid method invoke packet received. Index =" << index <<"which is out of bounds for type"<<m_rxName;
+ //TODO - consider moving this to packet validation?
+ break;
+ }
+ if (source->m_api->isAdapterMethod(index))
+ qRODebug(this) << "Adapter (method) Invoke-->" << m_rxName << source->m_adapter->metaObject()->method(resolvedIndex).name();
+ else {
+ qRODebug(this) << "Source (method) Invoke-->" << m_rxName << source->m_object->metaObject()->method(resolvedIndex).methodSignature();
+ auto method = source->m_object->metaObject()->method(resolvedIndex);
+ const int parameterCount = method.parameterCount();
+ for (int i = 0; i < parameterCount; i++)
+ m_rxArgs[i] = decodeVariant(std::move(m_rxArgs[i]), method.parameterMetaType(i));
+ }
+ auto metaType = QMetaType::fromName(source->m_api->typeName(index).constData());
+ if (!metaType.sizeOf())
+ metaType = QMetaType(QMetaType::UnknownType);
+ QVariant returnValue(metaType, nullptr);
+ // If a Replica is used as a Source (which node->proxy() does) we can have a PendingCall return value.
+ // In this case, we need to wait for the pending call and send that.
+ if (source->m_api->typeName(index) == QByteArrayLiteral("QRemoteObjectPendingCall"))
+ returnValue = QVariant::fromValue<QRemoteObjectPendingCall>(QRemoteObjectPendingCall());
+ source->invoke(QMetaObject::InvokeMetaMethod, index, m_rxArgs, &returnValue);
+ // send reply if wanted
+ if (serialId >= 0) {
+ if (returnValue.canConvert<QRemoteObjectPendingCall>()) {
+ QRemoteObjectPendingCall call = returnValue.value<QRemoteObjectPendingCall>();
+ // Watcher will be destroyed when connection is, or when the finished lambda is called
+ QRemoteObjectPendingCallWatcher *watcher = new QRemoteObjectPendingCallWatcher(call, connection);
+ QObject::connect(watcher, &QRemoteObjectPendingCallWatcher::finished, connection, [this, serialId, connection, watcher]() {
+ if (watcher->error() == QRemoteObjectPendingCall::NoError) {
+ m_codec->serializeInvokeReplyPacket(this->m_rxName, serialId, encodeVariant(watcher->returnValue()));
+ m_codec->send(connection);
+ }
+ watcher->deleteLater();
+ });
+ } else {
+ m_codec->serializeInvokeReplyPacket(m_rxName, serialId, encodeVariant(returnValue));
+ m_codec->send(connection);
+ }
+ }
+ } else {
+ const int resolvedIndex = source->m_api->sourcePropertyIndex(index);
+ if (resolvedIndex < 0) {
+ qROWarning(this) << "Invalid property invoke packet received. Index =" << index <<"which is out of bounds for type"<<m_rxName;
+ //TODO - consider moving this to packet validation?
+ break;
+ }
+ if (source->m_api->isAdapterProperty(index))
+ qRODebug(this) << "Adapter (write property) Invoke-->" << m_rxName << source->m_adapter->metaObject()->property(resolvedIndex).name();
+ else
+ qRODebug(this) << "Source (write property) Invoke-->" << m_rxName << source->m_object->metaObject()->property(resolvedIndex).name();
+ source->invoke(QMetaObject::WriteProperty, index, m_rxArgs);
+ }
+ }
+ break;
+ }
+ default:
+ qRODebug(this) << "OnReadReady invalid type" << packetType;
+ }
+ } while (connection->bytesAvailable()); // have bytes left over, so do another iteration
+}
+
+void QRemoteObjectSourceIo::handleConnection()
+{
+ qRODebug(this) << "handleConnection" << m_connections;
+
+ QtROServerIoDevice *conn = m_server->nextPendingConnection();
+ newConnection(conn);
+}
+
+void QRemoteObjectSourceIo::newConnection(QtROIoDeviceBase *conn)
+{
+ m_connections.insert(conn);
+ connect(conn, &QtROIoDeviceBase::readyRead, this, [this, conn]() {
+ onServerRead(conn);
+ });
+ connect(conn, &QtROIoDeviceBase::disconnected, this, [this, conn]() {
+ onServerDisconnect(conn);
+ });
+
+ m_codec->serializeHandshakePacket();
+ m_codec->send(conn);
+
+ QRemoteObjectPackets::ObjectInfoList infos;
+ infos.reserve(m_sourceRoots.size());
+ for (auto remoteObject : qAsConst(m_sourceRoots)) {
+ infos << QRemoteObjectPackets::ObjectInfo{remoteObject->m_api->name(), remoteObject->m_api->typeName(), remoteObject->m_api->objectSignature()};
+ }
+ m_codec->serializeObjectListPacket(infos);
+ m_codec->send(conn);
+ qRODebug(this) << "Wrote ObjectList packet from Server" << QStringList(m_sourceRoots.keys());
+}
+
+QUrl QRemoteObjectSourceIo::serverAddress() const
+{
+ if (m_server)
+ return m_server->address();
+ return m_address;
+}
+
+QT_END_NAMESPACE
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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.LGPL3 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QREMOTEOBJECTSOURCEIO_P_H
+#define QREMOTEOBJECTSOURCEIO_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qconnectionfactories_p.h"
+#include "qtremoteobjectglobal.h"
+#include "qremoteobjectpacket_p.h"
+
+#include <QtCore/qiodevice.h>
+#include <QtCore/qscopedpointer.h>
+
+QT_BEGIN_NAMESPACE
+
+class QRemoteObjectSourceBase;
+class QRemoteObjectRootSource;
+class SourceApiMap;
+class QRemoteObjectHostBase;
+
+class QRemoteObjectSourceIo : public QObject
+{
+ Q_OBJECT
+public:
+ explicit QRemoteObjectSourceIo(const QUrl &address, QObject *parent = nullptr);
+ explicit QRemoteObjectSourceIo(QObject *parent = nullptr);
+ ~QRemoteObjectSourceIo() override;
+
+ bool startListening();
+ bool enableRemoting(QObject *object, const QMetaObject *meta, const QString &name,
+ const QString &typeName);
+ bool enableRemoting(QObject *object, const SourceApiMap *api, QObject *adapter = nullptr);
+ bool disableRemoting(QObject *object);
+ void newConnection(QtROIoDeviceBase *conn);
+
+ QUrl serverAddress() const;
+
+public Q_SLOTS:
+ void handleConnection();
+ void onServerDisconnect(QObject *obj = nullptr);
+ void onServerRead(QObject *obj);
+
+Q_SIGNALS:
+ void remoteObjectAdded(const QRemoteObjectSourceLocation &);
+ void remoteObjectRemoved(const QRemoteObjectSourceLocation &);
+ void serverRemoved(const QUrl& url);
+
+public:
+ void registerSource(QRemoteObjectSourceBase *source);
+ void unregisterSource(QRemoteObjectSourceBase *source);
+
+ QHash<QIODevice*, quint32> m_readSize;
+ QSet<QtROIoDeviceBase*> m_connections;
+ QHash<QObject *, QRemoteObjectRootSource*> m_objectToSourceMap;
+ QMap<QString, QRemoteObjectSourceBase*> m_sourceObjects;
+ QMap<QString, QRemoteObjectRootSource*> m_sourceRoots;
+ QHash<QtROIoDeviceBase*, QUrl> m_registryMapping;
+ QScopedPointer<QConnectionAbstractServer> m_server;
+ // TODO should have some sort of manager for the codec
+ QScopedPointer<QRemoteObjectPackets::CodecBase> m_codec{new QRemoteObjectPackets::QDataStreamCodec};
+ QString m_rxName;
+ QVariantList m_rxArgs;
+ QUrl m_address;
+};
+
+QT_END_NAMESPACE
+
+#endif
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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.LGPL3 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qtremoteobjectglobal.h"
+#include "qremoteobjectpacket_p.h"
+
+#include <QtCore/qdatastream.h>
+#include <QtCore/qmetaobject.h>
+
+QT_BEGIN_NAMESPACE
+
+Q_LOGGING_CATEGORY(QT_REMOTEOBJECT, "qt.remoteobjects", QtWarningMsg)
+Q_LOGGING_CATEGORY(QT_REMOTEOBJECT_MODELS, "qt.remoteobjects.models", QtWarningMsg)
+Q_LOGGING_CATEGORY(QT_REMOTEOBJECT_IO, "qt.remoteobjects.io", QtWarningMsg)
+
+/*!
+ \namespace QtRemoteObjects
+ \inmodule QtRemoteObjects
+
+ \brief The QtRemoteObjects namespace contains identifiers used in the
+ Remote Objects module, as well as some functions used from code generated
+ by the \l{Qt Remote Objects Compiler}{Replica Compiler (repc)}.
+*/
+
+/*!
+ \enum QtRemoteObjects::InitialAction
+
+ This enum type specifies the initial action when acquiring a \l Replica derived
+ from QAbstractItemModel.
+
+ \value FetchRootSize Only the size of the model is requested before the
+ \l {QRemoteObjectReplica::}{initialized} signal is emitted,
+ no data will be prefetched before that.
+ \value PrefetchData Some data can be prefetched before the
+ \l {QRemoteObjectReplica::}{initialized} signal is emitted.
+
+ \sa QRemoteObjectNode::acquireModel(), QRemoteObjectReplica::initialized()
+*/
+
+namespace QtRemoteObjects {
+
+void copyStoredProperties(const QMetaObject *mo, const void *src, void *dst)
+{
+ if (!src) {
+ qCWarning(QT_REMOTEOBJECT) << Q_FUNC_INFO << ": trying to copy from a null source";
+ return;
+ }
+ if (!dst) {
+ qCWarning(QT_REMOTEOBJECT) << Q_FUNC_INFO << ": trying to copy to a null destination";
+ return;
+ }
+
+ for (int i = 0, end = mo->propertyCount(); i != end; ++i) {
+ const QMetaProperty mp = mo->property(i);
+ mp.writeOnGadget(dst, mp.readOnGadget(src));
+ }
+}
+
+void copyStoredProperties(const QMetaObject *mo, const void *src, QDataStream &dst)
+{
+ if (!src) {
+ qCWarning(QT_REMOTEOBJECT) << Q_FUNC_INFO << ": trying to copy from a null source";
+ return;
+ }
+
+ for (int i = 0, end = mo->propertyCount(); i != end; ++i) {
+ const QMetaProperty mp = mo->property(i);
+ dst << QRemoteObjectPackets::encodeVariant(mp.readOnGadget(src));
+ }
+}
+
+void copyStoredProperties(const QMetaObject *mo, QDataStream &src, void *dst)
+{
+ if (!dst) {
+ qCWarning(QT_REMOTEOBJECT) << Q_FUNC_INFO << ": trying to copy to a null destination";
+ return;
+ }
+
+ for (int i = 0, end = mo->propertyCount(); i != end; ++i) {
+ const QMetaProperty mp = mo->property(i);
+ QVariant v;
+ src >> v;
+ mp.writeOnGadget(dst, QRemoteObjectPackets::decodeVariant(std::move(v), mp.metaType()));
+ }
+}
+
+} // namespace QtRemoteObjects
+
+QT_END_NAMESPACE
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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.LGPL3 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QTREMOTEOBJECTGLOBAL_H
+#define QTREMOTEOBJECTGLOBAL_H
+
+#include <QtCore/qglobal.h>
+#include <QtCore/qhash.h>
+#include <QtCore/qurl.h>
+#include <QtCore/qloggingcategory.h>
+
+QT_BEGIN_NAMESPACE
+
+struct QRemoteObjectSourceLocationInfo
+{
+ QRemoteObjectSourceLocationInfo() = default;
+ QRemoteObjectSourceLocationInfo(const QString &typeName_, const QUrl &hostUrl_)
+ : typeName(typeName_), hostUrl(hostUrl_) {}
+
+ inline bool operator==(const QRemoteObjectSourceLocationInfo &other) const Q_DECL_NOTHROW
+ {
+ return other.typeName == typeName && other.hostUrl == hostUrl;
+ }
+ inline bool operator!=(const QRemoteObjectSourceLocationInfo &other) const Q_DECL_NOTHROW
+ {
+ return !(*this == other);
+ }
+
+ QString typeName;
+ QUrl hostUrl;
+};
+
+inline QDebug operator<<(QDebug dbg, const QRemoteObjectSourceLocationInfo &info)
+{
+ dbg.nospace() << "SourceLocationInfo(" << info.typeName << ", " << info.hostUrl << ")";
+ return dbg.space();
+}
+
+inline QDataStream& operator<<(QDataStream &stream, const QRemoteObjectSourceLocationInfo &info)
+{
+ return stream << info.typeName << info.hostUrl;
+}
+
+inline QDataStream& operator>>(QDataStream &stream, QRemoteObjectSourceLocationInfo &info)
+{
+ return stream >> info.typeName >> info.hostUrl;
+}
+
+typedef QPair<QString, QRemoteObjectSourceLocationInfo> QRemoteObjectSourceLocation;
+typedef QHash<QString, QRemoteObjectSourceLocationInfo> QRemoteObjectSourceLocations;
+typedef QHash<int, QByteArray> QIntHash;
+
+QT_END_NAMESPACE
+Q_DECLARE_METATYPE(QRemoteObjectSourceLocation)
+Q_DECLARE_METATYPE(QRemoteObjectSourceLocations)
+Q_DECLARE_METATYPE(QIntHash)
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_STATIC
+# if defined(QT_BUILD_REMOTEOBJECTS_LIB)
+# define Q_REMOTEOBJECTS_EXPORT Q_DECL_EXPORT
+# else
+# define Q_REMOTEOBJECTS_EXPORT Q_DECL_IMPORT
+# endif
+#else
+# define Q_REMOTEOBJECTS_EXPORT
+#endif
+
+#define QCLASSINFO_REMOTEOBJECT_TYPE "RemoteObject Type"
+#define QCLASSINFO_REMOTEOBJECT_SIGNATURE "RemoteObject Signature"
+
+class QDataStream;
+
+namespace QRemoteObjectStringLiterals {
+
+// when QStringLiteral is used with the same string in different functions,
+// it creates duplicate static data. Wrapping it in inline functions prevents it.
+
+inline QString local() { return QStringLiteral("local"); }
+inline QString localabstract() { return QStringLiteral("localabstract"); }
+inline QString tcp() { return QStringLiteral("tcp"); }
+inline QString CLASS() { return QStringLiteral("Class::%1"); }
+inline QString MODEL() { return QStringLiteral("Model::%1"); }
+inline QString QAIMADAPTER() { return QStringLiteral("QAbstractItemModelAdapter"); }
+
+}
+
+Q_DECLARE_LOGGING_CATEGORY(QT_REMOTEOBJECT)
+Q_DECLARE_LOGGING_CATEGORY(QT_REMOTEOBJECT_MODELS)
+Q_DECLARE_LOGGING_CATEGORY(QT_REMOTEOBJECT_IO)
+
+namespace QtRemoteObjects {
+
+Q_NAMESPACE
+
+Q_REMOTEOBJECTS_EXPORT void copyStoredProperties(const QMetaObject *mo, const void *src, void *dst);
+Q_REMOTEOBJECTS_EXPORT void copyStoredProperties(const QMetaObject *mo, const void *src, QDataStream &dst);
+Q_REMOTEOBJECTS_EXPORT void copyStoredProperties(const QMetaObject *mo, QDataStream &src, void *dst);
+
+QString getTypeNameAndMetaobjectFromClassInfo(const QMetaObject *& meta);
+
+template <typename T>
+void copyStoredProperties(const T *src, T *dst)
+{
+ copyStoredProperties(&T::staticMetaObject, src, dst);
+}
+
+template <typename T>
+void copyStoredProperties(const T *src, QDataStream &dst)
+{
+ copyStoredProperties(&T::staticMetaObject, src, dst);
+}
+
+template <typename T>
+void copyStoredProperties(QDataStream &src, T *dst)
+{
+ copyStoredProperties(&T::staticMetaObject, src, dst);
+}
+
+template <typename E>
+constexpr typename std::underlying_type<E>::type to_underlying(E e) noexcept {
+ return static_cast<typename std::underlying_type<E>::type>(e);
+}
+
+enum QRemoteObjectPacketTypeEnum
+{
+ Invalid = 0,
+ Handshake,
+ InitPacket,
+ InitDynamicPacket,
+ AddObject,
+ RemoveObject,
+ InvokePacket,
+ InvokeReplyPacket,
+ PropertyChangePacket,
+ ObjectList,
+ Ping,
+ Pong
+};
+Q_ENUM_NS(QRemoteObjectPacketTypeEnum)
+
+enum InitialAction {
+ FetchRootSize,
+ PrefetchData
+};
+Q_ENUM_NS(InitialAction)
+
+}
+
+QT_END_NAMESPACE
+
+#endif // QTREMOTEOBJECTSGLOBAL_H
--- /dev/null
+
+#####################################################################
+## qtremoteobjects Plugin:
+#####################################################################
+
+qt_internal_add_qml_module(RemoteObjectsQml
+ URI "QtRemoteObjects"
+ VERSION "${PROJECT_VERSION}"
+ PLUGIN_TARGET declarative_remoteobjects
+ CLASS_NAME QtRemoteObjectsPlugin
+ SOURCES
+ qremoteobjectsqml_p.h
+ PUBLIC_LIBRARIES
+ Qt::Core
+ Qt::Gui
+ Qt::Qml
+ Qt::QmlPrivate
+ Qt::RemoteObjects
+)
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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.LGPL3 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QREMOTEOBJECTSQML_P_H
+#define QREMOTEOBJECTSQML_P_H
+
+#include <QtRemoteObjects/qremoteobjectnode.h>
+#include <QtRemoteObjects/qremoteobjectpendingcall.h>
+#include <QtRemoteObjects/qremoteobjectsettingsstore.h>
+
+#include <QtCore/qtimer.h>
+#include <QtQml/QJSValue>
+#include <QtQml/private/qjsvalue_p.h>
+#include <QtQml/qqml.h>
+#include <QtQml/qqmlengine.h>
+#include <QtQml/qqmlinfo.h>
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+QT_BEGIN_NAMESPACE
+
+struct QtQmlRemoteObjectsResponse
+{
+ QJSValue promise;
+ QTimer *timer;
+};
+
+// documentation updates for this class can be made in remoteobjects-qml.qdoc
+class QtQmlRemoteObjects : public QObject
+{
+ Q_OBJECT
+ QML_NAMED_ELEMENT(QtRemoteObjects)
+ QML_SINGLETON
+ QML_ADDED_IN_VERSION(5, 14)
+
+public:
+ ~QtQmlRemoteObjects()
+ {
+ auto i = m_callbacks.begin();
+ while (i != m_callbacks.end()) {
+ delete i.key();
+ delete i.value().timer;
+ i = m_callbacks.erase(i);
+ }
+ }
+
+ Q_INVOKABLE QJSValue watch(const QRemoteObjectPendingCall &reply, int timeout = 30000)
+ {
+ if (m_accessiblePromise.isUndefined())
+ m_accessiblePromise = qmlEngine(this)->evaluate(QLatin1String(
+ "(function() { var obj = {}; obj.promise = new Promise(function(resolve, "
+ "reject) { obj.resolve = resolve; obj.reject = reject; }); return obj; })"));
+
+ QRemoteObjectPendingCallWatcher *watcher = new QRemoteObjectPendingCallWatcher(reply);
+
+ QJSValue promise = m_accessiblePromise.call();
+ QtQmlRemoteObjectsResponse response;
+ response.promise = promise;
+ response.timer = new QTimer();
+ response.timer->setSingleShot(true);
+ m_callbacks.insert(watcher, response);
+
+ // handle timeout
+ connect(response.timer, &QTimer::timeout, [this, watcher]() {
+ auto i = m_callbacks.find(watcher);
+ if (i == m_callbacks.end()) {
+ qmlWarning(this) << "could not find callback for watcher.";
+ return;
+ }
+
+ QJSValue v(QLatin1String("timeout"));
+ i.value().promise.property(QLatin1String("reject")).call(QJSValueList() << v);
+
+ delete i.key();
+ delete i.value().timer;
+ m_callbacks.erase(i);
+ });
+
+ // handle success
+ connect(watcher, &QRemoteObjectPendingCallWatcher::finished,
+ [this](QRemoteObjectPendingCallWatcher *self) {
+ auto i = m_callbacks.find(self);
+ if (i == m_callbacks.end()) {
+ qmlWarning(this) << "could not find callback for watcher.";
+ return;
+ }
+ QJSValue v = qmlEngine(this)->toScriptValue(self->returnValue());
+ i.value().promise.property(QLatin1String("resolve")).call(QJSValueList() << v);
+
+ delete i.key();
+ delete i.value().timer;
+ m_callbacks.erase(i);
+ });
+
+ response.timer->start(timeout);
+ return promise.property(QLatin1String("promise"));
+ }
+
+private:
+ QHash<QRemoteObjectPendingCallWatcher *, QtQmlRemoteObjectsResponse> m_callbacks;
+ QJSValue m_accessiblePromise;
+};
+
+struct QRemoteObjectNodeForeign
+{
+ Q_GADGET
+ QML_FOREIGN(QRemoteObjectNode)
+ QML_NAMED_ELEMENT(Node)
+ QML_ADDED_IN_VERSION(5, 12)
+};
+
+struct QRemoteObjectSettingsStoreForeign
+{
+ Q_GADGET
+ QML_FOREIGN(QRemoteObjectSettingsStore)
+ QML_NAMED_ELEMENT(SettingsStore)
+ QML_ADDED_IN_VERSION(5, 12)
+};
+
+struct QRemoteObjectHostForeign
+{
+ Q_GADGET
+ QML_FOREIGN(QRemoteObjectHost)
+ QML_NAMED_ELEMENT(Host)
+ QML_ADDED_IN_VERSION(5, 15)
+};
+
+struct QRemoteObjectAbstractPersistedStoreForeign
+{
+ Q_GADGET
+ QML_FOREIGN(QRemoteObjectAbstractPersistedStore)
+ QML_NAMED_ELEMENT(PersistedStore)
+ QML_UNCREATABLE("QRemoteObjectAbstractPersistedStore is Abstract")
+ QML_ADDED_IN_VERSION(5, 12)
+};
+
+QT_END_NAMESPACE
+
+#endif // QREMOTEOBJECTSQML_P_H
--- /dev/null
+
+#####################################################################
+## RepParser Module:
+#####################################################################
+
+qt_internal_add_module(RepParser
+ HEADER_MODULE
+ PUBLIC_LIBRARIES
+ Qt::Core
+)
+
+qt_internal_module_info(module RepParser)
+qt_path_join(parser_install_dir "${QT_INSTALL_DIR}" "${INSTALL_INCLUDEDIR}" "${module}")
+
+qt_copy_or_install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/parser.g" DESTINATION "${parser_install_dir}")
--- /dev/null
+----------------------------------------------------------------------------
+--
+-- Copyright (C) 2014-2020 Ford Motor Company.
+-- Contact: https://www.qt.io/licensing/
+--
+-- This file is part of the QtRemoteObjects module of the Qt Toolkit.
+--
+-- $QT_BEGIN_LICENSE:LGPL$
+-- Commercial License Usage
+-- Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+-- and conditions see https://www.qt.io/terms-conditions. For further
+-- information use the contact form at https://www.qt.io/contact-us.
+--
+-- 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.LGPL3 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.
+--
+-- GNU General Public License Usage
+-- Alternatively, this file may be used under the terms of the GNU
+-- General Public License version 2.0 or (at your option) the GNU General
+-- Public license version 3 or any later version approved by the KDE Free
+-- Qt Foundation. The licenses are as published by the Free Software
+-- Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+-- included in the packaging of this file. Please review the following
+-- information to ensure the GNU General Public License requirements will
+-- be met: https://www.gnu.org/licenses/gpl-2.0.html and
+-- https://www.gnu.org/licenses/gpl-3.0.html.
+--
+-- $QT_END_LICENSE$
+--
+----------------------------------------------------------------------------
+
+%parser rep_grammar
+%decl repparser.h
+%impl repparser.cpp
+
+%token_prefix Token_
+%token semicolon "[semicolon];"
+%token class "[class]class[ \\t]+(?<name>[A-Za-z_][A-Za-z0-9_]+)[ \\t]*"
+%token pod "[pod]POD[ \\t]*(?<name>[A-Za-z_][A-Za-z0-9_]+)[ \\t]*\\((?<types>[^\\)]*)\\);?[ \\t]*"
+%token pod2 "[pod2]POD[ \\t]*(?<name>[A-Za-z_][A-Za-z0-9_]+)[ \\t]*"
+%token flag "[flag][ \\t]*FLAG[ \t]*\\([ \t]*(?<name>[A-Za-z_][A-Za-z0-9_]*)[ \t]+(?<enum>[A-Za-z_][A-Za-z0-9_]*)[ \t]*\\)[ \t]*"
+%token enum "[enum][ \\t]*ENUM[ \t]+(?:(?<class>class[ \t]+))?(?<name>[A-Za-z_][A-Za-z0-9_]*)[ \t]*(?::[ \t]*(?<type>[a-zA-Z0-9 _:]*[a-zA-Z0-9_])[ \t]*)?"
+%token prop "[prop][ \\t]*PROP[ \\t]*\\((?<args>[^\\)]+)\\);?[ \\t]*"
+%token use_enum "[use_enum]USE_ENUM[ \\t]*\\((?<name>[^\\)]*)\\);?[ \\t]*"
+%token signal "[signal][ \\t]*SIGNAL[ \\t]*\\([ \\t]*(?<name>\\S+)[ \\t]*\\((?<args>[^\\)]*)\\)[ \\t]*\\);?[ \\t]*"
+%token slot "[slot][ \\t]*SLOT[ \\t]*\\((?<type>[^\\(]*)\\((?<args>[^\\)]*)\\)[ \\t]*\\);?[ \\t]*"
+%token model "[model][ \\t]*MODEL[ \\t]+(?<name>[A-Za-z_][A-Za-z0-9_]+)\\((?<args>[^\\)]+)\\)[ \\t]*;?[ \\t]*"
+%token childrep "[childrep][ \\t]*CLASS[ \\t]+(?<name>[A-Za-z_][A-Za-z0-9_]+)\\((?<type>[^\\)]+)\\)[ \\t]*;?[ \\t]*"
+%token qualifier "[qualifier][ \\t]*(?<value>const|unsigned|signed)[ \\t]*"
+%token passbyqual "[passbyqual][ \\t]*(?<value>&)[ \\t]*"
+%token symbol "[symbol][ \\t]*(?<symbol>[A-Za-z_][A-Za-z0-9_]*)[ \\t]*"
+%token value "[value][ \\t]*(?<value>-\\d+|0[xX][0-9A-Fa-f]+|\\d+)[ \\t]*"
+%token start "[start][ \\t]*\\{[ \\t]*"
+%token stop "[stop][ \\t]*\\};?[ \\t]*"
+%token comma "[comma],"
+%token equals "[equals]="
+%token comment "[comment](?<comment>[ \\t]*//[^\\n]*\\n)"
+%token mcomment "[mcomment,M](?<comment>/\\*(.*?)\\*/)"
+%token preprocessor_directive "[preprocessor_directive](?<preprocessor_directive>#[ \\t]*[^\\n]*\\n)"
+%token newline "[newline](\\r)?\\n"
+%token tstart "[tstart]<"
+%token tstop "[tstop]>[ \\t]*"
+
+%start TopLevel
+
+/:
+#ifndef REPPARSER_H
+#define REPPARSER_H
+
+#include <rep_grammar_p.h>
+#include <qregexparser.h>
+#include <QStringList>
+#include <QList>
+#include <QRegularExpression>
+
+QT_BEGIN_NAMESPACE
+class QIODevice;
+class QCryptographicHash;
+
+struct AST;
+
+struct SignedType
+{
+ SignedType(const QString &name = QString());
+ virtual ~SignedType() {}
+ void generateSignature(AST &ast);
+ virtual QString typeName() const;
+ virtual void signature_impl(const AST &ast, QCryptographicHash &checksum) = 0;
+ QString name;
+};
+
+/// A property of a Class declaration
+struct ASTProperty
+{
+ enum Modifier
+ {
+ Constant,
+ ReadOnly,
+ ReadPush,
+ ReadWrite,
+ SourceOnlySetter
+ };
+
+ ASTProperty();
+ ASTProperty(const QString &type, const QString &name, const QString &defaultValue, Modifier modifier, bool persisted,
+ bool isPointer=false);
+
+ QString type;
+ QString name;
+ QString defaultValue;
+ Modifier modifier;
+ bool persisted;
+ bool isPointer;
+};
+Q_DECLARE_TYPEINFO(ASTProperty, Q_RELOCATABLE_TYPE);
+
+struct ASTDeclaration
+{
+ enum VariableType {
+ None = 0,
+ Constant = 1,
+ Reference = 2,
+ };
+ Q_DECLARE_FLAGS(VariableTypes, VariableType)
+
+ ASTDeclaration(const QString &declarationType = QString(), const QString &declarationName = QString(), VariableTypes declarationVariableType = None)
+ : type(declarationType),
+ name(declarationName),
+ variableType(declarationVariableType)
+ {
+ }
+
+ QString asString(bool withName) const;
+
+ QString type;
+ QString name;
+ VariableTypes variableType;
+};
+Q_DECLARE_TYPEINFO(ASTDeclaration, Q_RELOCATABLE_TYPE);
+
+struct ASTFunction
+{
+ enum ParamsAsStringFormat {
+ Default,
+ Normalized
+ };
+
+ explicit ASTFunction(const QString &name = QString(), const QString &returnType = QLatin1String("void"));
+
+ QString paramsAsString(ParamsAsStringFormat format = Default) const;
+ QStringList paramNames() const;
+
+ QString returnType;
+ QString name;
+ QList<ASTDeclaration> params;
+};
+Q_DECLARE_TYPEINFO(ASTFunction, Q_RELOCATABLE_TYPE);
+
+struct ASTEnumParam
+{
+ ASTEnumParam(const QString ¶mName = QString(), int paramValue = 0)
+ : name(paramName),
+ value(paramValue)
+ {
+ }
+
+ QString asString() const;
+
+ QString name;
+ int value;
+};
+Q_DECLARE_TYPEINFO(ASTEnumParam, Q_RELOCATABLE_TYPE);
+
+struct ASTEnum : public SignedType
+{
+ explicit ASTEnum(const QString &name = QString());
+ void signature_impl(const AST &ast, QCryptographicHash &checksum) override;
+ QString typeName() const override;
+
+ QString type;
+ QString scope;
+ QList<ASTEnumParam> params;
+ bool isSigned;
+ bool isScoped;
+ int max;
+ int flagIndex = -1;
+};
+Q_DECLARE_TYPEINFO(ASTEnum, Q_RELOCATABLE_TYPE);
+
+struct ASTFlag : public SignedType
+{
+ explicit ASTFlag(const QString &name = {}, const QString &_enum = {});
+ void signature_impl(const AST &ast, QCryptographicHash &checksum) override;
+ QString typeName() const override;
+
+ bool isValid() const;
+ QString _enum;
+ QString scope;
+};
+Q_DECLARE_TYPEINFO(ASTFlag, Q_RELOCATABLE_TYPE);
+
+struct ASTModelRole
+{
+ ASTModelRole(const QString &roleName = QString())
+ : name(roleName)
+ {
+ }
+
+ QString name;
+};
+Q_DECLARE_TYPEINFO(ASTModelRole, Q_RELOCATABLE_TYPE);
+
+struct ASTModel : public SignedType
+{
+ ASTModel(const QString &name, const QString &scope, int index = -1)
+ : SignedType(name), scope(scope), propertyIndex(index) {}
+ void signature_impl(const AST &ast, QCryptographicHash &checksum) override;
+ QString typeName() const override;
+
+ QList<ASTModelRole> roles;
+ QString scope;
+ int propertyIndex;
+};
+Q_DECLARE_TYPEINFO(ASTModel, Q_RELOCATABLE_TYPE);
+
+/// A Class declaration
+struct ASTClass : public SignedType
+{
+ explicit ASTClass(const QString& name = QString());
+ void signature_impl(const AST &ast, QCryptographicHash &checksum) override;
+
+ bool isValid() const;
+ bool hasPointerObjects() const;
+
+ QList<ASTProperty> properties;
+ QList<ASTFunction> signalsList;
+ QList<ASTFunction> slotsList;
+ QList<ASTEnum> enums;
+ QList<ASTFlag> flags;
+ bool hasPersisted;
+ QList<ASTModel> modelMetadata;
+ QList<int> subClassPropertyIndices;
+};
+Q_DECLARE_TYPEINFO(ASTClass, Q_RELOCATABLE_TYPE);
+
+// The attribute of a POD
+struct PODAttribute
+{
+ explicit PODAttribute(const QString &type_ = QString(), const QString &name_ = QString())
+ : type(type_),
+ name(name_)
+ {}
+ QString type;
+ QString name;
+};
+Q_DECLARE_TYPEINFO(PODAttribute, Q_RELOCATABLE_TYPE);
+
+// A POD declaration
+struct POD : public SignedType
+{
+ void signature_impl(const AST &ast, QCryptographicHash &checksum) override;
+
+ QList<PODAttribute> attributes;
+ QList<ASTEnum> enums;
+ QList<ASTFlag> flags;
+};
+Q_DECLARE_TYPEINFO(POD, Q_RELOCATABLE_TYPE);
+
+// The AST representation of a .rep file
+struct AST
+{
+ QList<ASTClass> classes;
+ QList<POD> pods;
+ QList<ASTEnum> enums;
+ QList<ASTFlag> flags;
+ QList<QString> enumUses;
+ QStringList preprocessorDirectives;
+ QHash<QString, QByteArray> typeSignatures;
+ QByteArray typeData(const QString &type, const QString &className) const;
+ QByteArray functionsData(const QList<ASTFunction> &functions, const QString &className) const;
+};
+Q_DECLARE_TYPEINFO(AST, Q_RELOCATABLE_TYPE);
+
+class RepParser: public QRegexParser<RepParser, $table>
+{
+public:
+ explicit RepParser(QIODevice &outputDevice);
+ virtual ~RepParser() {}
+
+ bool parse() override { return QRegexParser<RepParser, $table>::parse(); }
+
+ void reset() override;
+ int nextToken();
+ bool consumeRule(int ruleno);
+
+ AST ast() const;
+
+private:
+ struct TypeParser
+ {
+ void parseArguments(const QString &arguments);
+ void appendParams(ASTFunction &slot);
+ void appendPods(POD &pods);
+ void generateFunctionParameter(QString variableName, const QString &propertyType, int &variableNameIndex, ASTDeclaration::VariableTypes variableType);
+ //Type, Variable
+ QList<ASTDeclaration> arguments;
+ };
+
+ bool parseProperty(ASTClass &astClass, const QString &propertyDeclaration);
+ /// A helper function to parse modifier flag of property declaration
+ bool parseModifierFlag(const QString &flag, ASTProperty::Modifier &modifier, bool &persisted);
+
+ bool parseRoles(ASTModel &astModel, const QString &modelRoles);
+
+ AST m_ast;
+
+ ASTClass m_astClass;
+ POD m_astPod;
+ QString m_symbol;
+ QString m_argString;
+ ASTEnum m_astEnum;
+ int m_astEnumValue;
+};
+QT_END_NAMESPACE
+#endif
+:/
+
+
+/.
+#include "repparser.h"
+
+#include <QCryptographicHash>
+#include <QDebug>
+#include <QTextStream>
+
+// for normalizeTypeInternal
+#include <private/qmetaobject_p.h>
+#include <private/qmetaobject_moc_p.h>
+
+// Code copied from moc.cpp
+// We cannot depend on QMetaObject::normalizedSignature,
+// since repc is linked against Qt5Bootstrap (which doesn't offer QMetaObject) when cross-compiling
+// Thus, just use internal API which is exported in private headers, as moc does
+static QByteArray normalizeType(const QByteArray &ba)
+{
+ const char *s = ba.constData();
+ int len = ba.size();
+ char stackbuf[64];
+ char *buf = (len >= 64 ? new char[len + 1] : stackbuf);
+ char *d = buf;
+ char last = 0;
+ while (*s && is_space(*s))
+ s++;
+ while (*s) {
+ while (*s && !is_space(*s))
+ last = *d++ = *s++;
+ while (*s && is_space(*s))
+ s++;
+ if (*s && ((is_ident_char(*s) && is_ident_char(last))
+ || ((*s == ':') && (last == '<')))) {
+ last = *d++ = ' ';
+ }
+ }
+ *d = '\0';
+ QByteArray result = normalizeTypeInternal(buf, d);
+ if (buf != stackbuf)
+ delete [] buf;
+ return result;
+}
+
+SignedType::SignedType(const QString &name) : name(name)
+{
+}
+
+void SignedType::generateSignature(AST &ast)
+{
+ QCryptographicHash checksum(QCryptographicHash::Sha1);
+ signature_impl(ast, checksum);
+ ast.typeSignatures[typeName()] = checksum.result().toHex();
+}
+
+QString SignedType::typeName() const
+{
+ return name;
+}
+
+ASTProperty::ASTProperty()
+ : modifier(ReadPush), persisted(false), isPointer(false)
+{
+}
+
+ASTProperty::ASTProperty(const QString &type, const QString &name, const QString &defaultValue, Modifier modifier, bool persisted, bool isPointer)
+ : type(type), name(name), defaultValue(defaultValue), modifier(modifier), persisted(persisted), isPointer(isPointer)
+{
+}
+
+QString ASTDeclaration::asString(bool withName) const
+{
+ QString str;
+ if (variableType & ASTDeclaration::Constant)
+ str += QLatin1String("const ");
+ str += type;
+ if (variableType & ASTDeclaration::Reference)
+ str += QLatin1String(" &");
+ if (withName)
+ str += QString::fromLatin1(" %1").arg(name);
+ return str;
+}
+
+ASTFunction::ASTFunction(const QString &name, const QString &returnType)
+ : returnType(returnType), name(name)
+{
+}
+
+QString ASTFunction::paramsAsString(ParamsAsStringFormat format) const
+{
+ QString str;
+ for (const ASTDeclaration ¶m : params) {
+ QString paramStr = param.asString(format != Normalized);
+ if (format == Normalized) {
+ paramStr = QString::fromLatin1(::normalizeType(paramStr.toLatin1().constData()));
+ str += paramStr + QLatin1Char(',');
+ } else {
+ str += paramStr + QLatin1String(", ");
+ }
+ }
+
+ str.chop((format == Normalized ? 1 : 2)); // chop trailing ',' or ', '
+
+ return str;
+}
+
+QStringList ASTFunction::paramNames() const
+{
+ QStringList names;
+ names.reserve(params.size());
+ for (const ASTDeclaration ¶m : params)
+ names << param.name;
+ return names;
+}
+
+ASTEnum::ASTEnum(const QString &name)
+ : SignedType(name), isSigned(false), isScoped(false), max(0)
+{
+}
+
+void ASTEnum::signature_impl(const AST &ast, QCryptographicHash &checksum)
+{
+ Q_UNUSED(ast)
+ checksum.addData(name.toLatin1());
+ if (isScoped)
+ checksum.addData("class", qstrlen("class"));
+ if (!type.isEmpty())
+ checksum.addData(type.toLatin1());
+ for (const ASTEnumParam ¶m : params) {
+ checksum.addData(param.name.toLatin1());
+ checksum.addData(QByteArray::number(param.value));
+ }
+}
+
+QString ASTEnum::typeName() const
+{
+ if (scope.isEmpty())
+ return name;
+
+ return QLatin1String("%1::%2").arg(scope, name);
+}
+
+ASTFlag::ASTFlag(const QString &name, const QString &_enum)
+ : SignedType(name), _enum(_enum)
+{
+}
+
+void ASTFlag::signature_impl(const AST &ast, QCryptographicHash &checksum)
+{
+ checksum.addData(name.toLatin1());
+ checksum.addData(ast.typeData(_enum, scope));
+}
+
+QString ASTFlag::typeName() const
+{
+ if (scope.isEmpty())
+ return name;
+
+ return QLatin1String("%1::%2").arg(scope, name);
+}
+
+bool ASTFlag::isValid() const
+{
+ return !name.isEmpty();
+}
+
+void ASTModel::signature_impl(const AST &ast, QCryptographicHash &checksum)
+{
+ Q_UNUSED(ast)
+ QByteArrayList _roles;
+ for (const auto &role : roles)
+ _roles << role.name.toLatin1();
+ std::sort(_roles.begin(), _roles.end());
+ checksum.addData(_roles.join('_'));
+}
+
+QString ASTModel::typeName() const
+{
+ return QLatin1String("%1::%2").arg(scope, name);
+}
+
+ASTClass::ASTClass(const QString &name)
+ : SignedType(name), hasPersisted(false)
+{
+}
+
+void ASTClass::signature_impl(const AST &ast, QCryptographicHash &checksum)
+{
+ checksum.addData(name.toLatin1());
+
+ // Checksum properties
+ QSet<int> classIndices{ subClassPropertyIndices.begin(),
+ subClassPropertyIndices.end() };
+ int propertyIndex = -1;
+ int modelIndex = 0;
+ for (const ASTProperty &p : properties) {
+ propertyIndex++;
+ checksum.addData(p.name.toLatin1());
+ if (p.type == QLatin1String("QAbstractItemModel"))
+ checksum.addData(ast.typeSignatures[modelMetadata[modelIndex++].typeName()]);
+ else if (classIndices.contains(propertyIndex))
+ checksum.addData(ast.typeSignatures[p.type]);
+ else
+ checksum.addData(ast.typeData(p.type, name));
+ ASTProperty::Modifier m = p.modifier;
+ // Treat ReadOnly and SourceOnlySetter the same (interface-wise they are)
+ if (m == ASTProperty::SourceOnlySetter)
+ m = ASTProperty::ReadOnly;
+ checksum.addData(reinterpret_cast<const char *>(&m), sizeof(m));
+ }
+
+ // Checksum signals
+ checksum.addData(ast.functionsData(signalsList, name));
+
+ // Checksum slots
+ checksum.addData(ast.functionsData(slotsList, name));
+}
+
+void POD::signature_impl(const AST &ast, QCryptographicHash &checksum)
+{
+ checksum.addData(name.toLatin1());
+ for (const PODAttribute &attr : attributes) {
+ checksum.addData(attr.name.toLatin1());
+ checksum.addData(ast.typeData(attr.type, name));
+ }
+}
+
+bool ASTClass::isValid() const
+{
+ return !name.isEmpty();
+}
+
+bool ASTClass::hasPointerObjects() const
+{
+ int count = modelMetadata.size() + subClassPropertyIndices.size();
+ return count > 0;
+}
+
+QByteArray AST::typeData(const QString &type, const QString &className) const
+{
+ static const QRegularExpression re = QRegularExpression(QLatin1String("([^<>,\\s]+)"));
+ if (type.contains(QLatin1Char('<'))) { // templated type
+ QByteArray result;
+ for (const QRegularExpressionMatch &match : re.globalMatch(type))
+ result += typeData(match.captured(1), className);
+ return result;
+ }
+ // Try enum/flags within the class first
+ if (!className.isEmpty()) {
+ auto classType = QLatin1String("%1::%2").arg(className, type);
+ auto it = typeSignatures.find(classType);
+ if (it != typeSignatures.end())
+ return it.value();
+ }
+ auto it = typeSignatures.find(type);
+ if (it != typeSignatures.end())
+ return it.value();
+ const auto pos = type.lastIndexOf(QLatin1String("::"));
+ if (pos > 0)
+ return typeData(type.mid(pos + 2), className);
+ return type.toLatin1();
+}
+
+QByteArray AST::functionsData(const QList<ASTFunction> &functions, const QString &className) const
+{
+ QByteArray ret;
+ for (const ASTFunction &func : functions) {
+ ret += func.name.toLatin1();
+ for (const ASTDeclaration ¶m : func.params) {
+ ret += param.name.toLatin1();
+ ret += typeData(param.type, className);
+ ret += QByteArray(reinterpret_cast<const char *>(¶m.variableType),
+ sizeof(param.variableType));
+ }
+ ret += typeData(func.returnType, className);
+ }
+ return ret;
+}
+
+RepParser::RepParser(QIODevice &outputDevice)
+ : QRegexParser(), m_astEnumValue(-1)
+{
+ setBufferFromDevice(&outputDevice);
+}
+
+void RepParser::reset()
+{
+ m_ast = AST();
+ m_astClass = ASTClass();
+ m_astPod = POD();
+ m_argString.clear();
+ m_astEnum = ASTEnum();
+ //setDebug();
+}
+
+bool RepParser::parseModifierFlag(const QString &flag, ASTProperty::Modifier &modifier, bool &persisted)
+{
+ QRegularExpression regex(QStringLiteral("\\s*,\\s*"));
+ QStringList flags = flag.split(regex);
+ persisted = flags.removeAll(QStringLiteral("PERSISTED")) > 0;
+ if (flags.length() == 0)
+ return true;
+ if (flags.length() > 1) {
+ // Only valid combination is "READONLY" and "CONSTANT"
+ if (flags.length() == 2 && flags.contains(QStringLiteral("READONLY")) &&
+ flags.contains(QStringLiteral("CONSTANT"))) {
+ // If we have READONLY and CONSTANT that means CONSTANT
+ modifier = ASTProperty::Constant;
+ return true;
+ } else {
+ setErrorString(QLatin1String("Invalid property declaration: combination not allowed (%1)").arg(flag));
+ return false;
+ }
+ }
+ const QString &f = flags.at(0);
+ if (f == QLatin1String("READONLY"))
+ modifier = ASTProperty::ReadOnly;
+ else if (f == QLatin1String("CONSTANT"))
+ modifier = ASTProperty::Constant;
+ else if (f == QLatin1String("READPUSH"))
+ modifier = ASTProperty::ReadPush;
+ else if (f == QLatin1String("READWRITE"))
+ modifier = ASTProperty::ReadWrite;
+ else if (f == QLatin1String("SOURCEONLYSETTER"))
+ modifier = ASTProperty::SourceOnlySetter;
+ else {
+ setErrorString(QLatin1String("Invalid property declaration: flag %1 is unknown").arg(flag));
+ return false;
+ }
+
+ return true;
+}
+
+QString stripArgs(const QString &arguments)
+{
+ // This repc parser searches for the longest possible matches, which can be multiline.
+ // This method "cleans" the string input, removing comments and converting to a single
+ // line for subsequent parsing.
+ QStringList lines = arguments.split(QRegularExpression(QStringLiteral("\r?\n")));
+ for (auto & line : lines)
+ line.replace(QRegularExpression(QStringLiteral("//.*")),QString());
+ return lines.join(QString());
+}
+
+bool RepParser::parseProperty(ASTClass &astClass, const QString &propertyDeclaration)
+{
+ QString input = stripArgs(propertyDeclaration).trimmed();
+ const QRegularExpression whitespace(QStringLiteral("\\s"));
+
+ QString propertyType;
+ QString propertyName;
+ QString propertyDefaultValue;
+ ASTProperty::Modifier propertyModifier = ASTProperty::ReadPush;
+ bool persisted = false;
+
+ // parse type declaration which could be a nested template as well
+ bool inTemplate = false;
+ int templateDepth = 0;
+ int nameIndex = -1;
+
+ for (int i = 0; i < input.size(); ++i) {
+ const QChar inputChar(input.at(i));
+ if (inputChar == QLatin1Char('<')) {
+ propertyType += inputChar;
+ inTemplate = true;
+ ++templateDepth;
+ } else if (inputChar == QLatin1Char('>')) {
+ propertyType += inputChar;
+ --templateDepth;
+ if (templateDepth == 0)
+ inTemplate = false;
+ } else if (inputChar.isSpace()) {
+ if (!inTemplate) {
+ nameIndex = i;
+ break;
+ } else {
+ propertyType += inputChar;
+ }
+ } else {
+ propertyType += inputChar;
+ }
+ }
+
+ if (nameIndex == -1) {
+ setErrorString(QLatin1String("PROP: Invalid property declaration: %1").arg(propertyDeclaration));
+ return false;
+ }
+
+ // parse the name of the property
+ input = input.mid(nameIndex).trimmed();
+
+ const int equalSignIndex = input.indexOf(QLatin1Char('='));
+ if (equalSignIndex != -1) { // we have a default value
+ propertyName = input.left(equalSignIndex).trimmed();
+
+ input = input.mid(equalSignIndex + 1).trimmed();
+ const int lastQuoteIndex = input.lastIndexOf(QLatin1Char('"'));
+ if (lastQuoteIndex != -1) {
+ propertyDefaultValue = input.left(lastQuoteIndex + 1);
+ input = input.mid(lastQuoteIndex + 1);
+ }
+ const int whitespaceIndex = input.indexOf(whitespace);
+ if (whitespaceIndex == -1) { // no flag given
+ if (propertyDefaultValue.isEmpty())
+ propertyDefaultValue = input;
+ propertyModifier = ASTProperty::ReadPush;
+ } else { // flag given
+ if (propertyDefaultValue.isEmpty())
+ propertyDefaultValue = input.left(whitespaceIndex).trimmed();
+
+ const QString flag = input.mid(whitespaceIndex + 1).trimmed();
+ if (!parseModifierFlag(flag, propertyModifier, persisted))
+ return false;
+ }
+ } else { // there is no default value
+ const int whitespaceIndex = input.indexOf(whitespace);
+ if (whitespaceIndex == -1) { // no flag given
+ propertyName = input;
+ propertyModifier = ASTProperty::ReadPush;
+ } else { // flag given
+ propertyName = input.left(whitespaceIndex).trimmed();
+
+ const QString flag = input.mid(whitespaceIndex + 1).trimmed();
+ if (!parseModifierFlag(flag, propertyModifier, persisted))
+ return false;
+ }
+ }
+
+ astClass.properties << ASTProperty(propertyType, propertyName, propertyDefaultValue, propertyModifier, persisted);
+ if (persisted)
+ astClass.hasPersisted = true;
+ return true;
+}
+
+bool RepParser::parseRoles(ASTModel &astModel, const QString &modelRoles)
+{
+ const QString input = modelRoles.trimmed();
+
+ if (input.isEmpty())
+ return true;
+
+ const QStringList roleStrings = input.split(QChar(QLatin1Char(',')));
+ for (auto role : roleStrings)
+ astModel.roles << ASTModelRole(role.trimmed());
+ return true;
+}
+
+AST RepParser::ast() const
+{
+ return m_ast;
+}
+
+void RepParser::TypeParser::parseArguments(const QString &arguments)
+{
+ const QString strippedArgs = stripArgs(arguments);
+ int templateDepth = 0;
+ bool inTemplate = false;
+ bool inVariable = false;
+ QString propertyType;
+ QString variableName;
+ ASTDeclaration::VariableTypes variableType = ASTDeclaration::None;
+ int variableNameIndex = 0;
+ for (int i = 0; i < strippedArgs.size(); ++i) {
+ const QChar inputChar(strippedArgs.at(i));
+ if (inputChar == QLatin1Char('<')) {
+ propertyType += inputChar;
+ inTemplate = true;
+ ++templateDepth;
+ } else if (inputChar == QLatin1Char('>')) {
+ propertyType += inputChar;
+ --templateDepth;
+ if (templateDepth == 0)
+ inTemplate = false;
+ } else if (inputChar.isSpace()) {
+ if (inTemplate)
+ propertyType += inputChar;
+ else if (!propertyType.isEmpty()) {
+ if (propertyType == QLatin1String("const")) {
+ propertyType.clear();
+ variableType |= ASTDeclaration::Constant;
+ } else {
+ inVariable = true;
+ }
+ }
+ } else if (inputChar == QLatin1Char('&')) {
+ variableType |= ASTDeclaration::Reference;
+ } else if (inputChar == QLatin1Char(',')) {
+ if (!inTemplate) {
+ RepParser::TypeParser::generateFunctionParameter(variableName, propertyType, variableNameIndex, variableType);
+ propertyType.clear();
+ variableName.clear();
+ variableType = ASTDeclaration::None;
+ inVariable = false;
+ } else {
+ propertyType += inputChar;
+ }
+ } else {
+ if (inVariable)
+ variableName += inputChar;
+ else
+ propertyType += inputChar;
+ }
+ }
+ if (!propertyType.isEmpty()) {
+ RepParser::TypeParser::generateFunctionParameter(variableName, propertyType, variableNameIndex, variableType);
+ }
+}
+
+void RepParser::TypeParser::generateFunctionParameter(QString variableName, const QString &propertyType, int &variableNameIndex, ASTDeclaration::VariableTypes variableType)
+{
+ if (!variableName.isEmpty())
+ variableName = variableName.trimmed();
+ else
+ variableName = QString::fromLatin1("__repc_variable_%1").arg(++variableNameIndex);
+ arguments.append(ASTDeclaration(propertyType, variableName, variableType));
+}
+
+void RepParser::TypeParser::appendParams(ASTFunction &slot)
+{
+ for (const ASTDeclaration &arg : qAsConst(arguments))
+ slot.params << arg;
+}
+
+void RepParser::TypeParser::appendPods(POD &pods)
+{
+ for (const ASTDeclaration &arg : qAsConst(arguments)) {
+ PODAttribute attr;
+ attr.type = arg.type;
+ attr.name = arg.name;
+ pods.attributes.append(qMove(attr));
+ }
+}
+
+bool RepParser::consumeRule(int ruleno)
+{
+ if (isDebug()) {
+ qDebug() << "consumeRule:" << ruleno << spell[rule_info[rule_index[ruleno]]];
+ }
+ switch (ruleno) {
+./
+
+TopLevel: Types | Newlines Types | FileComments Types | Newlines FileComments Types;
+
+FileComments: Comments;
+
+Types: Type | Type Types;
+
+Newlines: newline | newline Newlines;
+Comments: Comment | Comment Comments;
+Comment: comment | comment Newlines | mcomment | mcomment Newlines;
+Type: PreprocessorDirective | PreprocessorDirective Newlines;
+Type: Pod | Pod Newlines;
+Type: Pod2;
+Type: Class;
+Type: UseEnum | UseEnum Newlines;
+Type: Comments | Comments Newlines;
+Type: Enum;
+/.
+ case $rule_number:
+ {
+ m_astEnum.generateSignature(m_ast);
+ m_ast.enums.append(m_astEnum);
+ }
+ break;
+./
+Type: Flag | Flag Newlines;
+
+Comma: comma | comma Newlines;
+
+Equals: equals;
+
+PreprocessorDirective: preprocessor_directive;
+/.
+ case $rule_number:
+ {
+ m_ast.preprocessorDirectives.append(captured().value(QStringLiteral("preprocessor_directive")));
+ }
+ break;
+./
+
+Pod: pod;
+/.
+ case $rule_number:
+ {
+ POD pod;
+ pod.name = captured().value(QStringLiteral("name")).trimmed();
+
+ const QString argString = captured().value(QLatin1String("types")).trimmed();
+ if (argString.isEmpty()) {
+ qWarning() << "[repc] - Ignoring POD with no data members. POD name: " << qPrintable(pod.name);
+ return true;
+ }
+ if (argString.contains(QLatin1String("ENUM"))) {
+ setErrorString(QLatin1String("ENUMs are only available in PODs using bracket syntax ('{'), not parentheses"));
+ return false;
+ }
+
+ RepParser::TypeParser parseType;
+ parseType.parseArguments(argString);
+ parseType.appendPods(pod);
+ pod.generateSignature(m_ast);
+ m_ast.pods.append(pod);
+ }
+ break;
+./
+
+Class: ClassStart Start ClassTypes Stop;
+/.
+ case $rule_number:
+./
+Class: ClassStart Start Comments Stop;
+/.
+ case $rule_number:
+./
+Class: ClassStart Start Stop;
+/.
+ case $rule_number:
+ {
+ m_astClass.generateSignature(m_ast);
+ m_ast.classes.append(m_astClass);
+ }
+ break;
+./
+
+ClassTypes: ClassType | ClassType ClassTypes;
+ClassType: DecoratedProp | DecoratedSignal | DecoratedSlot | DecoratedModel | DecoratedClass | DecoratedClassFlag | Comments;
+ClassType: Enum;
+/.
+ case $rule_number:
+ {
+ m_astEnum.scope = m_astClass.name;
+ m_astEnum.generateSignature(m_ast);
+ m_astClass.enums.append(m_astEnum);
+ }
+ break;
+./
+
+Pod2: PodStart Start PodTypes Stop;
+/.
+ case $rule_number:
+./
+Pod2: PodStart Start Comments Stop;
+/.
+ case $rule_number:
+./
+Pod2: PodStart Start Stop;
+/.
+ case $rule_number:
+ {
+ RepParser::TypeParser parseType;
+ parseType.parseArguments(m_argString);
+ parseType.appendPods(m_astPod);
+ m_astPod.generateSignature(m_ast);
+ m_ast.pods.append(m_astPod);
+ }
+ break;
+./
+
+PodTypes: PodType | PodType Newlines | PodType CaptureComma PodTypes | PodType PodTypes | PodType Newlines PodTypes;
+PodType: DecoratedPODFlag | Comments;
+PodType: Enum;
+/.
+ case $rule_number:
+ {
+ m_astEnum.generateSignature(m_ast);
+ m_astPod.enums.append(m_astEnum);
+ }
+ break;
+./
+
+PodType: Parameter;
+Parameter: DecoratedParameterType ParameterName;
+
+DecoratedParameterType: ParameterType | Qualified ParameterType | ParameterType PassByReference | Qualified ParameterType PassByReference;
+
+ParameterType: SimpleType | TemplateType;
+
+TemplateType: TemplateTypename TStart ParameterTypes TStop;
+
+TemplateTypename: Symbol;
+/.
+ case $rule_number:
+ {
+ m_argString += m_symbol;
+ }
+ break;
+./
+
+TStart: tstart;
+/.
+ case $rule_number:
+ {
+ m_argString += QLatin1Char('<');
+ }
+ break;
+./
+
+TStop: tstop;
+/.
+ case $rule_number:
+ {
+ m_argString += QLatin1Char('>');
+ }
+ break;
+./
+
+Qualified: qualifier;
+/.
+ case $rule_number:
+ {
+ m_argString += captured().value(QLatin1String("value")).trimmed() + QLatin1Char(' ');
+ }
+ break;
+./
+
+PassByReference: passbyqual;
+/.
+ case $rule_number:
+ {
+ m_argString += QLatin1Char(' ') + captured().value(QLatin1String("value")).trimmed();
+ }
+ break;
+./
+
+ParameterTypes: DecoratedParameterType | DecoratedParameterType CaptureComma ParameterTypes;
+
+CaptureComma: comma;
+/.
+ case $rule_number:
+./
+CaptureComma: comma Newlines;
+/.
+ case $rule_number:
+ {
+ m_argString += QLatin1Char(',');
+ }
+ break;
+./
+
+SimpleType: Symbol;
+/.
+ case $rule_number:
+ {
+ m_argString += m_symbol;
+ }
+ break;
+./
+
+ParameterName: Symbol;
+/.
+ case $rule_number:
+ {
+ m_argString += QLatin1Char(' ') + m_symbol;
+ }
+ break;
+./
+
+DecoratedSlot: Slot | Comments Slot | Slot Newlines | Comments Slot Newlines;
+DecoratedSignal: Signal | Comments Signal | Signal Newlines | Comments Signal Newlines;
+DecoratedProp: Prop | Comments Prop | Prop Newlines | Comments Prop Newlines;
+DecoratedModel: Model | Comments Model | Model Newlines | Comments Model Newlines;
+DecoratedClass: ChildRep | Comments ChildRep | ChildRep Newlines | Comments ChildRep Newlines;
+DecoratedEnumParam: EnumParam | Comments EnumParam | EnumParam Newlines | Comments EnumParam Newlines;
+DecoratedClassFlag: ClassFlag | Comments ClassFlag | ClassFlag Newlines | Comments ClassFlag Newlines;
+
+DecoratedPODFlag: PODFlag | Comments PODFlag | PODFlag Newlines | Comments PODFlag Newlines;
+
+Start: start | Comments start | start Newlines | Comments start Newlines;
+Stop: stop | stop Newlines;
+
+Enum: EnumStart Start EnumParams Comments Stop;
+Enum: EnumStart Start EnumParams Stop;
+
+EnumStart: enum;
+/.
+ case $rule_number:
+ {
+ const QString name = captured().value(QLatin1String("name"));
+ const QString type = captured().value(QLatin1String("type"));
+ const QString _class = captured().value(QLatin1String("class"));
+
+ // new Class declaration
+ m_astEnum = ASTEnum(name);
+ if (!_class.isEmpty())
+ m_astEnum.isScoped = true;
+ if (!type.isEmpty())
+ m_astEnum.type = type;
+ m_astEnumValue = -1;
+ }
+ break;
+./
+
+EnumParams: DecoratedEnumParam | DecoratedEnumParam Comma EnumParams;
+
+EnumParam: Symbol;
+/.
+ case $rule_number:
+ {
+ ASTEnumParam param;
+ param.name = m_symbol;
+ param.value = ++m_astEnumValue;
+ if (m_astEnum.max < param.value)
+ m_astEnum.max = param.value;
+ m_astEnum.params << param;
+ }
+ break;
+./
+
+EnumParam: Symbol Equals Value;
+/.
+ case $rule_number:
+ {
+ ASTEnumParam param;
+ param.name = m_symbol;
+ param.value = m_astEnumValue;
+ if (param.value < 0) {
+ m_astEnum.isSigned = true;
+ if (m_astEnum.max < -param.value)
+ m_astEnum.max = -param.value;
+ } else if (m_astEnum.max < param.value)
+ m_astEnum.max = param.value;
+ m_astEnum.params << param;
+ }
+ break;
+./
+
+Symbol: symbol;
+/.
+ case $rule_number:
+ {
+ m_symbol = captured().value(QStringLiteral("symbol")).trimmed();
+ }
+ break;
+./
+
+Value: value;
+/.
+ case $rule_number:
+ {
+ QString value = captured().value(QStringLiteral("value")).trimmed();
+ if (value.startsWith(QLatin1String("0x"), Qt::CaseInsensitive))
+ m_astEnumValue = value.toInt(0,16);
+ else
+ m_astEnumValue = value.toInt();
+ }
+ break;
+./
+
+ClassFlag: flag;
+/.
+ case $rule_number:
+ {
+ const QString name = captured().value(QLatin1String("name"));
+ const QString _enum = captured().value(QLatin1String("enum"));
+ int enumIndex = 0;
+ for (auto &en : m_astClass.enums) {
+ if (en.name == _enum) {
+ en.flagIndex = m_astClass.flags.count();
+ break;
+ }
+ enumIndex++;
+ }
+ if (enumIndex == m_astClass.enums.count()) {
+ setErrorString(QLatin1String("FLAG: Unknown (class) enum: %1").arg(_enum));
+ return false;
+ }
+ auto flag = ASTFlag(name, _enum);
+ flag.scope = m_astClass.name;
+ flag.generateSignature(m_ast);
+ m_astClass.flags.append(flag);
+ }
+ break;
+./
+
+PODFlag: flag;
+/.
+ case $rule_number:
+ {
+ const QString name = captured().value(QLatin1String("name"));
+ const QString _enum = captured().value(QLatin1String("enum"));
+ int enumIndex = 0;
+ for (auto &en : m_astPod.enums) {
+ if (en.name == _enum) {
+ en.flagIndex = m_astPod.flags.count();
+ break;
+ }
+ enumIndex++;
+ }
+ if (enumIndex == m_astPod.enums.count()) {
+ setErrorString(QLatin1String("FLAG: Unknown (pod) enum: %1").arg(_enum));
+ return false;
+ }
+ auto flag = ASTFlag(name, _enum);
+ flag.scope = m_astPod.name;
+ flag.generateSignature(m_ast);
+ m_astPod.flags.append(flag);
+ }
+ break;
+./
+
+Prop: prop;
+/.
+ case $rule_number:
+ {
+ const QString args = captured().value(QLatin1String("args"));
+ if (!parseProperty(m_astClass, args))
+ return false;
+ }
+ break;
+./
+
+Signal: signal;
+/.
+ case $rule_number:
+ {
+ ASTFunction signal;
+ signal.name = captured().value(QLatin1String("name")).trimmed();
+
+ const QString argString = captured().value(QLatin1String("args")).trimmed();
+ RepParser::TypeParser parseType;
+ parseType.parseArguments(argString);
+ parseType.appendParams(signal);
+ m_astClass.signalsList << signal;
+ }
+ break;
+./
+
+Slot: slot;
+/.
+ case $rule_number:
+ {
+ QString returnTypeAndName = captured().value(QLatin1String("type")).trimmed();
+ const QString argString = captured().value(QLatin1String("args")).trimmed();
+
+ // compat code with old SLOT declaration: "SLOT(func(...))"
+ const bool hasWhitespace = returnTypeAndName.indexOf(u' ') != -1;
+ if (!hasWhitespace) {
+ qWarning() << "[repc] - Adding 'void' for unspecified return type on" << qPrintable(returnTypeAndName);
+ returnTypeAndName.prepend(QLatin1String("void "));
+ }
+
+ const int startOfFunctionName = returnTypeAndName.lastIndexOf(u' ') + 1;
+
+ ASTFunction slot;
+ slot.returnType = returnTypeAndName.mid(0, startOfFunctionName-1);
+ slot.name = returnTypeAndName.mid(startOfFunctionName);
+
+ RepParser::TypeParser parseType;
+ parseType.parseArguments(argString);
+ parseType.appendParams(slot);
+ m_astClass.slotsList << slot;
+ }
+ break;
+./
+
+Model: model;
+/.
+ case $rule_number:
+ {
+ const QString name = captured().value(QLatin1String("name")).trimmed();
+ const QString argString = captured().value(QLatin1String("args")).trimmed();
+
+ ASTModel model(name, m_astClass.name, m_astClass.properties.size());
+ if (!parseRoles(model, argString))
+ return false;
+
+ model.generateSignature(m_ast);
+ m_astClass.modelMetadata << model;
+ m_astClass.properties << ASTProperty(QStringLiteral("QAbstractItemModel"), name, QStringLiteral("nullptr"), ASTProperty::SourceOnlySetter, false, true);
+ }
+ break;
+./
+
+ChildRep: childrep;
+/.
+case $rule_number:
+{
+ const QString name = captured().value(QLatin1String("name")).trimmed();
+ const QString type = captured().value(QLatin1String("type")).trimmed();
+
+ m_astClass.subClassPropertyIndices << m_astClass.properties.size();
+ m_astClass.properties << ASTProperty(type, name, QStringLiteral("nullptr"), ASTProperty::SourceOnlySetter, false, true);
+}
+break;
+./
+
+ClassStart: class Newlines;
+/.
+ case $rule_number:
+./
+ClassStart: class;
+/.
+ case $rule_number:
+ {
+ const QString name = captured().value(QLatin1String("name"));
+
+ // new Class declaration
+ m_astClass = ASTClass(name);
+ }
+ break;
+./
+
+PodStart: pod2;
+/.
+ case $rule_number:
+./
+PodStart: pod2 Newlines;
+/.
+ case $rule_number:
+ {
+ // new POD declaration
+ m_astPod = POD();
+ m_astPod.name = captured().value(QLatin1String("name")).trimmed();
+ m_argString.clear();
+ }
+ break;
+./
+
+UseEnum: use_enum;
+/.
+ case $rule_number:
+ {
+ const QString name = captured().value(QLatin1String("name"));
+
+ m_ast.enumUses.append(name);
+ }
+ break;
+./
+
+Flag: flag;
+/.
+ case $rule_number:
+ {
+ const QString name = captured().value(QLatin1String("name"));
+ const QString _enum = captured().value(QLatin1String("enum"));
+ int enumIndex = 0;
+ for (auto &en : m_ast.enums) {
+ if (en.name == _enum) {
+ en.flagIndex = m_ast.flags.count();
+ break;
+ }
+ if (en.name == _enum)
+ break;
+ enumIndex++;
+ }
+ if (enumIndex == m_ast.enums.count()) {
+ setErrorString(QLatin1String("FLAG: Unknown (global) enum: %1").arg(_enum));
+ return false;
+ }
+ auto flag = ASTFlag(name, _enum);
+ flag.generateSignature(m_ast);
+ m_ast.flags.append(flag);
+ }
+ break;
+./
+
+--Error conditions/messages
+ClassType: ClassStart;
+/.
+ case $rule_number:
+ {
+ setErrorString(QStringLiteral("class: Cannot be nested"));
+ return false;
+ }
+ break;
+./
+ClassType: Pod;
+/.
+ case $rule_number:
+ {
+ setErrorString(QStringLiteral("POD: Can only be used in global scope"));
+ return false;
+ }
+ break;
+./
+ClassType: UseEnum;
+/.
+ case $rule_number:
+ {
+ setErrorString(QStringLiteral("USE_ENUM: Can only be used in global scope"));
+ return false;
+ }
+ break;
+./
+Type: Signal;
+/.
+ case $rule_number:
+ {
+ setErrorString(QStringLiteral("SIGNAL: Can only be used in class scope"));
+ return false;
+ }
+ break;
+./
+Type: Slot;
+/.
+ case $rule_number:
+ {
+ setErrorString(QStringLiteral("SLOT: Can only be used in class scope"));
+ return false;
+ }
+ break;
+./
+Type: Prop;
+/.
+ case $rule_number:
+ {
+ setErrorString(QStringLiteral("PROP: Can only be used in class scope"));
+ return false;
+ }
+ break;
+./
+Type: Model;
+/.
+ case $rule_number:
+ {
+ setErrorString(QStringLiteral("MODEL: Can only be used in class scope"));
+ return false;
+ }
+ break;
+./
+
+Type: ChildRep;
+/.
+ case $rule_number:
+ {
+ setErrorString(QStringLiteral("CLASS: Can only be used in class scope"));
+ return false;
+ }
+ break;
+./
+
+/.
+ } // switch
+ return true;
+}
+./
--- /dev/null
+/****************************************************************************
+** Copyright (C) 2017-2020 Ford Motor Company.
+** All rights reserved.
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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.LGPL3 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QREGEXPARSER_H
+#define QREGEXPARSER_H
+
+#include <QtCore/qshareddata.h>
+#include <QtCore/qvarlengtharray.h>
+#include <QtCore/qvariant.h>
+#include <QtCore/qregularexpression.h>
+#include <QtCore/qmap.h>
+#include <QtCore/qfile.h>
+#include <QtCore/qtextstream.h>
+#include <QtCore/qdebug.h>
+
+struct MatchCandidate {
+ MatchCandidate(const QString &n, const QString &t, int i) : name(n), matchText(t), index(i) {}
+ QString name;
+ QString matchText;
+ int index;
+};
+
+QT_BEGIN_NAMESPACE
+
+template <typename _Parser, typename _Table>
+class QRegexParser: protected _Table
+{
+public:
+ QRegexParser(int maxMatchLen=4096);
+ virtual ~QRegexParser();
+
+ virtual bool parse();
+
+ virtual void reset() {}
+
+ inline QVariant &sym(int index);
+
+ void setBuffer(const QString &buffer);
+
+ void setBufferFromDevice(QIODevice *device);
+
+ void setDebug();
+
+ QString errorString() const
+ {
+ return m_errorString;
+ }
+
+ void setErrorString(const QString &error)
+ {
+ m_errorString = error;
+ qWarning() << m_errorString;
+ }
+
+ inline const QMap<QString, QString>& captured() const
+ {
+ return m_captured;
+ }
+
+ inline bool isDebug() const
+ {
+ return m_debug;
+ }
+
+ inline int lineNumber() const
+ {
+ return m_lineno;
+ }
+
+private:
+ int nextToken();
+
+ inline bool consumeRule(int rule)
+ {
+ return static_cast<_Parser*> (this)->consumeRule(rule);
+ }
+
+ enum { DefaultStackSize = 128 };
+
+ struct Data: public QSharedData
+ {
+ Data(): stackSize (DefaultStackSize), tos (0) {}
+
+ QVarLengthArray<int, DefaultStackSize> stateStack;
+ QVarLengthArray<QVariant, DefaultStackSize> parseStack;
+ int stackSize;
+ int tos;
+
+ void reallocateStack() {
+ stackSize <<= 1;
+ stateStack.resize(stackSize);
+ parseStack.resize(stackSize);
+ }
+ };
+
+ inline QString escapeString(QString s)
+ {
+ return s.replace(QLatin1Char('\n'), QLatin1String("\\n")).replace(QLatin1Char('\t'), QLatin1String("\\t"));
+ }
+
+ QSharedDataPointer<Data> d;
+
+ QList<QRegularExpression> m_regexes;
+ QMap<QChar, QList<int> > regexCandidates;
+ QList<int> m_tokens;
+ QString m_buffer, m_lastMatchText;
+ int m_loc, m_lastNewlinePosition;
+ int m_lineno;
+ int m_debug;
+ QStringList m_tokenNames;
+ QMap<QString, QString> m_captured;
+ int m_maxMatchLen;
+ QString m_errorString;
+ QList<QMap<int, QString>> m_names; //storage for match names
+};
+
+template <typename _Parser, typename _Table>
+inline QVariant &QRegexParser<_Parser, _Table>::sym(int n)
+{
+ return d->parseStack [d->tos + n - 1];
+}
+
+template <typename _Parser, typename _Table>
+QRegexParser<_Parser, _Table>::~QRegexParser()
+{
+}
+
+template <typename _Parser, typename _Table>
+bool QRegexParser<_Parser, _Table>::parse()
+{
+ m_errorString.clear();
+ reset();
+ const int INITIAL_STATE = 0;
+
+ d->tos = 0;
+ d->reallocateStack();
+
+ int act = d->stateStack[++d->tos] = INITIAL_STATE;
+ int token = -1;
+
+ Q_FOREVER {
+ if (token == -1 && - _Table::TERMINAL_COUNT != _Table::action_index[act])
+ token = nextToken();
+
+ act = _Table::t_action(act, token);
+
+ if (d->stateStack[d->tos] == _Table::ACCEPT_STATE)
+ return true;
+
+ else if (act > 0) {
+ if (++d->tos == d->stackSize)
+ d->reallocateStack();
+
+ d->parseStack[d->tos] = d->parseStack[d->tos - 1];
+ d->stateStack[d->tos] = act;
+ token = -1;
+ }
+
+ else if (act < 0) {
+ int r = - act - 1;
+ d->tos -= _Table::rhs[r];
+ act = d->stateStack[d->tos++];
+ if (!consumeRule(r))
+ return false;
+ act = d->stateStack[d->tos] = _Table::nt_action(act, _Table::lhs[r] - _Table::TERMINAL_COUNT);
+ }
+
+ else break;
+ }
+
+ setErrorString(QStringLiteral("Unknown token encountered"));
+ return false;
+}
+
+template <typename _Parser, typename _Table>
+QRegexParser<_Parser, _Table>::QRegexParser(int maxMatchLen) : d(new Data()), m_loc(0), m_lastNewlinePosition(0), m_lineno(1), m_debug(0), m_maxMatchLen(maxMatchLen)
+{
+ QRegularExpression re(QStringLiteral("\\[([_a-zA-Z][_0-9a-zA-Z]*)(,\\s*M)?\\](.+)$"));
+ re.optimize();
+ QMap<QString, int> token_lookup;
+ QMap<int, QString> names;
+ for (int i = 1; i < _Table::lhs[0]; i++) {
+ const QString text = QLatin1String(_Table::spell[i]);
+ names.clear();
+ QRegularExpressionMatch match = re.match(text, 0, QRegularExpression::NormalMatch, QRegularExpression::DontCheckSubjectStringMatchOption);
+ if (match.hasMatch()) {
+ const QString token = match.captured(1);
+ const bool multiline = match.captured(2).length() > 0;
+ const QString pattern = match.captured(3);
+ m_tokenNames.append(token);
+ int index = i;
+ if (token_lookup.contains(token))
+ index = token_lookup[token];
+ else
+ token_lookup[token] = i;
+ QRegularExpression pat(pattern);
+ if (multiline)
+ pat.setPatternOptions(QRegularExpression::DotMatchesEverythingOption);
+
+ if (!pat.isValid())
+ qCritical() << "Pattern error for token #" << i << "for" << text << "pattern =" << pat << ":" << pat.errorString();
+ else {
+ pat.optimize();
+ int counter = 0;
+ const auto namedCaptureGroups = pat.namedCaptureGroups();
+ for (const QString &name : namedCaptureGroups) {
+ if (!name.isEmpty())
+ names.insert(counter, name);
+ ++counter;
+ }
+ m_names.append(names);
+ m_regexes.append(pat);
+ if (token.startsWith(QLatin1String("ignore")))
+ m_tokens.append(-1);
+ else
+ m_tokens.append(index);
+ }
+ } else {
+ qCritical() << "Error parsing regex at token #" << i << "for" << text << "Invalid syntax";
+ }
+ }
+}
+
+template <typename _Parser, typename _Table>
+void QRegexParser<_Parser, _Table>::setBuffer(const QString &buffer)
+{
+ m_buffer = buffer;
+}
+
+template <typename _Parser, typename _Table>
+void QRegexParser<_Parser, _Table>::setBufferFromDevice(QIODevice *device)
+{
+ QTextStream in(device);
+ m_buffer = in.readAll();
+}
+
+template <typename _Parser, typename _Table>
+void QRegexParser<_Parser, _Table>::setDebug()
+{
+ m_debug = true;
+ for (int r = 0; r < _Table::RULE_COUNT; ++r)
+ {
+ int ridx = _Table::rule_index[r];
+ int _rhs = _Table::rhs[r];
+ qDebug("%3d) %s ::=", r + 1, _Table::spell[_Table::rule_info[ridx]]);
+ ++ridx;
+ for (int i = ridx; i < ridx + _rhs; ++i)
+ {
+ int symbol = _Table::rule_info[i];
+ if (symbol > 0 && symbol < _Table::lhs[0])
+ qDebug(" token_%s (pattern = %s)",qPrintable(m_tokenNames[symbol-1]),qPrintable(m_regexes[symbol-1].pattern()));
+ else if (const char *name = _Table::spell[symbol])
+ qDebug(" %s", name);
+ else
+ qDebug(" #%d", symbol);
+ }
+ qDebug();
+ }
+}
+
+template <typename _Parser, typename _Table>
+int QRegexParser<_Parser, _Table>::nextToken()
+{
+ const QStringView buffer { m_buffer };
+ static const QRegularExpression newline(QLatin1String("(\\n)"));
+ int token = -1;
+ while (token < 0)
+ {
+ if (m_loc == buffer.size())
+ return _Table::EOF_SYMBOL;
+
+ //Check m_lastMatchText for newlines and update m_lineno
+ //This isn't necessary, but being able to provide the line # and character #
+ //where the match is failing sure makes building/debugging grammars easier.
+ QRegularExpressionMatchIterator matches = newline.globalMatch(m_lastMatchText);
+ while (matches.hasNext()) {
+ m_lineno++;
+ QRegularExpressionMatch match = matches.next();
+ if (!matches.hasNext())
+ m_lastNewlinePosition += match.capturedEnd();
+ }
+
+ if (m_debug) {
+ qDebug();
+ qDebug() << "nextToken loop, line =" << m_lineno
+ << "line position =" << m_loc - m_lastNewlinePosition
+ << "next 5 characters =" << escapeString(buffer.mid(m_loc, 5).toString());
+ }
+ int best = -1, maxLen = -1;
+ QRegularExpressionMatch bestRegex;
+
+ //Find the longest match.
+ //If more than one are the same (longest) length, return the first one in
+ //the order defined.
+ QList<MatchCandidate> candidates;
+ //We used PCRE's PartialMatch to eliminate most of the regexes by the first
+ //character, so we keep a regexCandidates map with the list of possible regexes
+ //based on initial characters found so far.
+ const QChar nextChar = buffer.at(m_loc);
+ //Populate the list if we haven't seeen this character before
+ if (!regexCandidates.contains(nextChar)) {
+ const QStringView tmp = buffer.mid(m_loc,1);
+ int i = 0;
+ regexCandidates[nextChar] = QList<int>();
+ for (const QRegularExpression &re : qAsConst(m_regexes))
+ {
+ QRegularExpressionMatch match = re.match(tmp, 0, QRegularExpression::PartialPreferFirstMatch, QRegularExpression::DontCheckSubjectStringMatchOption);
+ //qDebug() << nextChar << tmp << match.hasMatch() << match.hasPartialMatch() << re.pattern();
+ if (match.hasMatch() || match.hasPartialMatch())
+ regexCandidates[nextChar] << i;
+ i++;
+ }
+ }
+ const auto indices = regexCandidates.value(nextChar);
+ for (int i : indices)
+ {
+ //Seems like I should be able to run the regex on the entire string, but performance is horrible
+ //unless I use a substring.
+ //QRegularExpressionMatch match = m_regexes[i].match(m_buffer, m_loc, QRegularExpression::NormalMatch, QRegularExpression::AnchorAtOffsetMatchOption);
+ QRegularExpressionMatch match = m_regexes.at(i).match(buffer.mid(m_loc, m_maxMatchLen), 0, QRegularExpression::NormalMatch, QRegularExpression::AnchorAtOffsetMatchOption | QRegularExpression::DontCheckSubjectStringMatchOption);
+ if (match.hasMatch()) {
+ if (m_debug)
+ candidates << MatchCandidate(m_tokenNames[i], match.captured(), i);
+ if (match.capturedLength() > maxLen) {
+ best = i;
+ maxLen = match.capturedLength();
+ bestRegex = match;
+ }
+ }
+ }
+ if (best < 0) {
+ setErrorString(QLatin1String("Error generating tokens from file, next characters >%1<").arg(buffer.mid(m_loc, 15)));
+ return -1;
+ } else {
+ const QMap<int, QString> &map = m_names.at(best);
+ if (!map.isEmpty())
+ m_captured.clear();
+ for (auto iter = map.cbegin(), end = map.cend(); iter != end; ++iter)
+ m_captured.insert(iter.value(), bestRegex.captured(iter.key()));
+ if (m_debug) {
+ qDebug() << "Match candidates:";
+ for (const MatchCandidate &m : qAsConst(candidates)) {
+ QLatin1String result = m.index == best ? QLatin1String(" * ") : QLatin1String(" ");
+ qDebug() << qPrintable(result) << qPrintable(m.name) << qPrintable(escapeString(m.matchText));
+ }
+ }
+ m_loc += maxLen;
+ if (m_tokens.at(best) >= 0)
+ token = m_tokens.at(best);
+ m_lastMatchText = bestRegex.captured(0);
+ }
+ }
+ return token;
+}
+
+QT_END_NAMESPACE
+
+#endif // QREGEXPARSER_H
--- /dev/null
+%modules = ( # path to module name map
+ "QtRemoteObjects" => "$basedir/src/remoteobjects",
+ "QtRemoteObjectsQml" => "$basedir/src/remoteobjectsqml",
+ "QtRepParser" => "$basedir/src/repparser",
+);
--- /dev/null
+
+if(QT_BUILD_STANDALONE_TESTS)
+ # Add qt_find_package calls for extra dependencies that need to be found when building
+ # the standalone tests here.
+endif()
+qt_build_tests()
--- /dev/null
+
+add_subdirectory(benchmarks)
+add_subdirectory(cmake)
+add_subdirectory(modelreplica)
+add_subdirectory(modelview)
+add_subdirectory(pods)
+add_subdirectory(proxy)
+add_subdirectory(rep_from_header)
+add_subdirectory(repc)
+add_subdirectory(repcodegenerator)
+add_subdirectory(repparser)
+add_subdirectory(subclassreplica)
+if(QT_FEATURE_ssl)
+ add_subdirectory(external_IODevice)
+endif()
+if(TARGET Qt::Qml)
+ add_subdirectory(qml)
+endif()
+if(QT_FEATURE_process)
+ add_subdirectory(integration_multiprocess)
+ add_subdirectory(proxy_multiprocess)
+ add_subdirectory(integration_external)
+ add_subdirectory(restart)
+ add_subdirectory(reconnect)
+endif()
+add_subdirectory(localsockettestserver)
+add_subdirectory(integration)
--- /dev/null
+
+#####################################################################
+## tst_benchmarkstest Test:
+#####################################################################
+
+qt_internal_add_test(tst_benchmarkstest
+ SOURCES
+ tst_benchmarkstest.cpp
+ DEFINES
+ SRCDIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/\\\"
+ PUBLIC_LIBRARIES
+ Qt::Network
+ Qt::RemoteObjects
+)
+qt6_add_repc_sources(tst_benchmarkstest
+ ../repfiles/localdatacenter.rep
+ ../repfiles/tcpdatacenter.rep
+)
+qt6_add_repc_replicas(tst_benchmarkstest
+ ../repfiles/localdatacenter.rep
+ ../repfiles/tcpdatacenter.rep
+)
+
+#### Keys ignored in scope 1:.:.:benchmarks.pro:<TRUE>:
+# TEMPLATE = "app"
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017-2015 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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 with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QString>
+#include <QDataStream>
+#include <QLocalSocket>
+#include <QLocalServer>
+#include <QtTest>
+#include <QtRemoteObjects/QAbstractItemModelReplica>
+#include <QtRemoteObjects/QRemoteObjectNode>
+#include "rep_localdatacenter_replica.h"
+#include "rep_localdatacenter_source.h"
+
+class BenchmarksModel : public QAbstractListModel
+{
+ // QAbstractItemModel interface
+public:
+ int rowCount(const QModelIndex &parent) const override;
+ QVariant data(const QModelIndex &index, int role) const override;
+ QHash<int, QByteArray> roleNames() const override;
+};
+
+int BenchmarksModel::rowCount(const QModelIndex &parent) const
+{
+ Q_UNUSED(parent)
+ return 100000;
+}
+
+QVariant BenchmarksModel::data(const QModelIndex &index, int role) const
+{
+ switch (role) {
+ case Qt::DisplayRole:
+ return QStringLiteral("Benchmark data %1").arg(index.row());
+ case Qt::BackgroundRole:
+ return index.row() % 2 ? QStringLiteral("red") : QStringLiteral("green");
+ }
+ return QVariant();
+}
+
+QHash<int, QByteArray> BenchmarksModel::roleNames() const
+{
+ static QHash<int,QByteArray> roleNames = {
+ {Qt::DisplayRole, "_text"},
+ {Qt::BackgroundRole, "_color"}
+ };
+ return roleNames;
+}
+
+class BenchmarksTest : public QObject
+{
+ Q_OBJECT
+
+public:
+ BenchmarksTest();
+private:
+ QRemoteObjectHost m_basicServer;
+ QRemoteObjectNode m_basicClient;
+ QScopedPointer<LocalDataCenterSimpleSource> dataCenterLocal;
+ BenchmarksModel m_sourceModel;
+
+private Q_SLOTS:
+ void initTestCase();
+ void benchPropertyChangesInt();
+ void benchQDataStreamInt();
+ void benchQLocalSocketInt();
+ void benchQLocalSocketQDataStreamInt();
+ void benchModelLinearAccess();
+ void benchModelRandomAccess();
+};
+
+BenchmarksTest::BenchmarksTest()
+{
+}
+
+void BenchmarksTest::initTestCase() {
+ m_basicServer.setHostUrl(QUrl(QStringLiteral("local:benchmark_replica")));
+ dataCenterLocal.reset(new LocalDataCenterSimpleSource);
+ dataCenterLocal->setData1(5);
+ const bool remoted = m_basicServer.enableRemoting(dataCenterLocal.data());
+ Q_ASSERT(remoted);
+ Q_UNUSED(remoted)
+
+ m_basicClient.connectToNode(QUrl(QStringLiteral("local:benchmark_replica")));
+ Q_ASSERT(m_basicClient.lastError() == QRemoteObjectNode::NoError);
+
+ m_basicServer.enableRemoting(&m_sourceModel, QStringLiteral("BenchmarkRemoteModel"),
+ m_sourceModel.roleNames().keys().toVector());
+}
+
+void BenchmarksTest::benchPropertyChangesInt()
+{
+ QScopedPointer<LocalDataCenterReplica> center;
+ center.reset(m_basicClient.acquire<LocalDataCenterReplica>());
+ if (!center->isInitialized()) {
+ QEventLoop loop;
+ connect(center.data(), &LocalDataCenterReplica::initialized, &loop, &QEventLoop::quit);
+ loop.exec();
+ }
+ QEventLoop loop;
+ int lastValue = 0;
+ connect(center.data(), &LocalDataCenterReplica::data1Changed, [&lastValue, ¢er, &loop]() {
+ const bool res = (lastValue++ == center->data1());
+ Q_ASSERT(res);
+ Q_UNUSED(res)
+ if (lastValue == 50000)
+ loop.quit();
+ });
+ QBENCHMARK {
+ for (int i = 0; i < 50000; ++i) {
+ dataCenterLocal->setData1(i);
+ }
+ loop.exec();
+ }
+}
+// This ONLY tests the optimal case of a non resizing QByteArray
+void BenchmarksTest::benchQDataStreamInt()
+{
+ QByteArray buffer;
+ QDataStream stream(&buffer, QIODevice::WriteOnly);
+ QDataStream rStream(&buffer, QIODevice::ReadOnly);
+ int readout = 0;
+ QBENCHMARK {
+ for (int i = 0; i < 50000; ++i) {
+ stream << i;
+ }
+ for (int i = 0; i < 50000; ++i) {
+ rStream >> readout;
+ Q_ASSERT(i == readout);
+ }
+ }
+}
+
+void BenchmarksTest::benchQLocalSocketInt()
+{
+ const QString socketName = QStringLiteral("benchLocalSocket");
+ QLocalServer server;
+ QLocalServer::removeServer(socketName);
+ server.listen(socketName);
+ QLocalSocket client;
+ client.connectToServer(socketName);
+ QEventLoop loop;
+ QScopedPointer<QLocalSocket> serverSock;
+ if (!server.hasPendingConnections()) {
+ connect(&server, &QLocalServer::newConnection, &loop, &QEventLoop::quit);
+ loop.exec();
+ }
+ Q_ASSERT(server.hasPendingConnections());
+ serverSock.reset(server.nextPendingConnection());
+ int lastValue = 0;
+ connect(&client, &QLocalSocket::readyRead, [&loop, &lastValue, &client]() {
+ int readout = 0;
+ while (client.bytesAvailable() && lastValue < 50000) {
+ client.read(reinterpret_cast<char*>(&readout), sizeof(int));
+ const bool res = (lastValue++ == readout);
+ Q_ASSERT(res);
+ Q_UNUSED(res)
+ }
+ if (lastValue >= 50000)
+ loop.quit();
+ });
+ QBENCHMARK {
+ for (int i = 0; i < 50000; ++i) {
+ const int res = int(serverSock->write(reinterpret_cast<char*>(&i), sizeof(int)));
+ Q_ASSERT(res == sizeof(int));
+ Q_UNUSED(res)
+ }
+ loop.exec();
+ }
+
+#ifdef Q_OS_WIN
+ // Work-around QTBUG-38185: immediately close socket
+ client.abort();
+#endif
+}
+
+void BenchmarksTest::benchQLocalSocketQDataStreamInt()
+{
+ const QString socketName = QStringLiteral("benchLocalSocket");
+ QLocalServer server;
+ QLocalServer::removeServer(socketName);
+ server.listen(socketName);
+ QLocalSocket client;
+ client.connectToServer(socketName);
+ QDataStream readStream(&client);
+ QEventLoop loop;
+ QScopedPointer<QLocalSocket> serverSock;
+ if (!server.hasPendingConnections()) {
+ connect(&server, &QLocalServer::newConnection, &loop, &QEventLoop::quit);
+ loop.exec();
+ }
+ Q_ASSERT(server.hasPendingConnections());
+ serverSock.reset(server.nextPendingConnection());
+ QDataStream writeStream(serverSock.data());
+ int lastValue = 0;
+ connect(&client, &QIODevice::readyRead, [&loop, &lastValue, &readStream]() {
+ int readout = 0;
+ while (readStream.device()->bytesAvailable() && lastValue < 50000) {
+ readStream >> readout;
+ const bool res = (lastValue++ == readout);
+ Q_ASSERT(res);
+ Q_UNUSED(res)
+ }
+ if (lastValue >= 50000)
+ loop.quit();
+ });
+ QBENCHMARK {
+ for (int i = 0; i < 50000; ++i) {
+ writeStream << i;
+ }
+ loop.exec();
+ }
+
+#ifdef Q_OS_WIN
+ // Work-around QTBUG-38185: immediately close socket
+ client.abort();
+#endif
+}
+
+void BenchmarksTest::benchModelLinearAccess()
+{
+ // Simulate an user browse through item them stops.
+ // We're measuring the time needed needed to deliver the visible chunk of data
+ // which are the last 50 items
+ QBENCHMARK {
+ QRemoteObjectNode localClient;
+ localClient.connectToNode(QUrl(QStringLiteral("local:benchmark_replica")));
+ QScopedPointer<QAbstractItemModelReplica> model(localClient.acquireModel(QStringLiteral("BenchmarkRemoteModel")));
+ QEventLoop loop;
+ QHash<int, QPair<QString, QString>> dataToWait;
+ connect(model.data(), &QAbstractItemModelReplica::dataChanged, [&model, &loop, &dataToWait](const QModelIndex &topLeft, const QModelIndex &bottomRight, const QList<int> &roles) {
+ for (int row = topLeft.row(); row <= bottomRight.row(); ++row) {
+ // we're assuming that the view will try use the sent data,
+ // therefore we're not optimizing the code
+ auto it = dataToWait.find(row);
+ if (it == dataToWait.end()) {
+ // simulate some work with the received data
+ QThread::usleep(10);
+ continue;
+ }
+ for (int role : roles) {
+ QVariant data = model->data(model->index(row, 0), role);
+ switch (role) {
+ case Qt::DisplayRole:
+ it->first = data.toString();
+ break;
+ case Qt::BackgroundRole:
+ it->second = data.toString();
+ break;
+ }
+ }
+
+ if (it->first == QStringLiteral("Benchmark data %1").arg(row) &&
+ it->second == (row % 2 ? QStringLiteral("red") : QStringLiteral("green"))) {
+ dataToWait.erase(it);
+ if (dataToWait.isEmpty())
+ break;
+ }
+ }
+ if (dataToWait.isEmpty())
+ loop.quit();
+ });
+
+ auto beginBenchmark = [&model, &dataToWait] {
+ for (int row = 0; row < 1000; ++row) {
+ if (row >= 950)
+ dataToWait.insert(row, QPair<QString, QString>());
+ model->data(model->index(row, 0), Qt::DisplayRole);
+ model->data(model->index(row, 0), Qt::BackgroundRole);
+
+ // Views (e.g. QTreeView) are accessing other roles
+ model->data(model->index(row, 0), Qt::FontRole);
+ model->data(model->index(row, 0), Qt::DecorationRole);
+ model->data(model->index(row, 0), Qt::SizeHintRole);
+ }
+
+ };
+ connect(model.data(), &QAbstractItemModelReplica::initialized, [&model, &loop, &beginBenchmark] {
+ if (model->isInitialized()) {
+ beginBenchmark();
+ } else {
+ Q_ASSERT(false);
+ loop.quit();
+ }
+ });
+ if (model->isInitialized())
+ beginBenchmark();
+
+ QTimer::singleShot(5000, &loop, &QEventLoop::quit);
+ loop.exec();
+ QVERIFY(dataToWait.isEmpty());
+ }
+}
+
+void BenchmarksTest::benchModelRandomAccess()
+{
+ QBENCHMARK {
+ QRemoteObjectNode localClient;
+ localClient.connectToNode(QUrl(QStringLiteral("local:benchmark_replica")));
+ QScopedPointer<QAbstractItemModelReplica> model(localClient.acquireModel(QStringLiteral("BenchmarkRemoteModel")));
+ model->setRootCacheSize(5000); // we need to make room for all 5000 rows that we'll use
+ QEventLoop loop;
+ QHash<int, QPair<QString, QString>> dataToWait;
+ connect(model.data(), &QAbstractItemModelReplica::dataChanged, [&model, &loop, &dataToWait](const QModelIndex &topLeft, const QModelIndex &bottomRight, const QList<int> &roles) {
+ for (int row = topLeft.row(); row <= bottomRight.row(); ++row) {
+ // we're assuming that the view will try use the sent data,
+ // therefore we're not optimizing the code
+ auto it = dataToWait.find(row);
+ if (it == dataToWait.end()) {
+ QThread::yieldCurrentThread(); // instead to wait
+ continue;
+ }
+ for (int role : roles) {
+ QVariant data = model->data(model->index(row, 0), role);
+ switch (role) {
+ case Qt::DisplayRole:
+ it->first = data.toString();
+ break;
+ case Qt::BackgroundRole:
+ it->second = data.toString();
+ break;
+ }
+ }
+
+ if (it->first == QStringLiteral("Benchmark data %1").arg(row) &&
+ it->second == (row % 2 ? QStringLiteral("red") : QStringLiteral("green"))) {
+ dataToWait.erase(it);
+ if (dataToWait.isEmpty())
+ break;
+ }
+ }
+ if (dataToWait.isEmpty())
+ loop.quit();
+ });
+
+ auto beginBenchmark = [&model, &dataToWait] {
+ for (int chunck = 0; chunck < 100; ++chunck) {
+ int row = chunck * 950;
+ for (int r = 0; r < 50; ++r) {
+ dataToWait.insert(r + row, QPair<QString, QString>());
+ model->data(model->index(r + row, 0), Qt::DisplayRole);
+ model->data(model->index(r + row, 0), Qt::BackgroundRole);
+
+ // Views (e.g. QTreeView) are accessing other roles
+ model->data(model->index(r + row, 0), Qt::FontRole);
+ model->data(model->index(r + row, 0), Qt::DecorationRole);
+ model->data(model->index(r + row, 0), Qt::SizeHintRole);
+ }
+ }
+
+ };
+ connect(model.data(), &QAbstractItemModelReplica::initialized, [&model, &loop, &beginBenchmark] {
+ if (model->isInitialized()) {
+ beginBenchmark();
+ } else {
+ Q_ASSERT(false);
+ loop.quit();
+ }
+ });
+ if (model->isInitialized())
+ beginBenchmark();
+
+ QTimer::singleShot(5000, &loop, &QEventLoop::quit);
+ loop.exec();
+ QVERIFY(dataToWait.isEmpty());
+ }
+}
+
+QTEST_MAIN(BenchmarksTest)
+
+#include "tst_benchmarkstest.moc"
--- /dev/null
+Class std::__failure_type
+ size=1 align=1
+ base size=0 base align=1
+std::__failure_type (0x0x7f234e2095a0) 0 empty
+
+Class std::__do_is_destructible_impl
+ size=1 align=1
+ base size=0 base align=1
+std::__do_is_destructible_impl (0x0x7f234e267d20) 0 empty
+
+Class std::__do_is_nt_destructible_impl
+ size=1 align=1
+ base size=0 base align=1
+std::__do_is_nt_destructible_impl (0x0x7f234e267f60) 0 empty
+
+Class std::__do_is_default_constructible_impl
+ size=1 align=1
+ base size=0 base align=1
+std::__do_is_default_constructible_impl (0x0x7f234e2911e0) 0 empty
+
+Class std::__do_is_static_castable_impl
+ size=1 align=1
+ base size=0 base align=1
+std::__do_is_static_castable_impl (0x0x7f234e291420) 0 empty
+
+Class std::__do_is_direct_constructible_impl
+ size=1 align=1
+ base size=0 base align=1
+std::__do_is_direct_constructible_impl (0x0x7f234e2915a0) 0 empty
+
+Class std::__do_is_nary_constructible_impl
+ size=1 align=1
+ base size=0 base align=1
+std::__do_is_nary_constructible_impl (0x0x7f234e291960) 0 empty
+
+Class std::__do_is_implicitly_default_constructible_impl
+ size=1 align=1
+ base size=0 base align=1
+std::__do_is_implicitly_default_constructible_impl (0x0x7f234e2cfa80) 0 empty
+
+Class std::__do_common_type_impl
+ size=1 align=1
+ base size=0 base align=1
+std::__do_common_type_impl (0x0x7f234df4f180) 0 empty
+
+Class std::__do_member_type_wrapper
+ size=1 align=1
+ base size=0 base align=1
+std::__do_member_type_wrapper (0x0x7f234df4f240) 0 empty
+
+Class std::__invoke_memfun_ref
+ size=1 align=1
+ base size=0 base align=1
+std::__invoke_memfun_ref (0x0x7f234df4f600) 0 empty
+
+Class std::__invoke_memfun_deref
+ size=1 align=1
+ base size=0 base align=1
+std::__invoke_memfun_deref (0x0x7f234df4f660) 0 empty
+
+Class std::__invoke_memobj_ref
+ size=1 align=1
+ base size=0 base align=1
+std::__invoke_memobj_ref (0x0x7f234df4f6c0) 0 empty
+
+Class std::__invoke_memobj_deref
+ size=1 align=1
+ base size=0 base align=1
+std::__invoke_memobj_deref (0x0x7f234df4f720) 0 empty
+
+Class std::__invoke_other
+ size=1 align=1
+ base size=0 base align=1
+std::__invoke_other (0x0x7f234df4f780) 0 empty
+
+Class std::__result_of_memfun_ref_impl
+ size=1 align=1
+ base size=0 base align=1
+std::__result_of_memfun_ref_impl (0x0x7f234df4f840) 0 empty
+
+Class std::__result_of_memfun_deref_impl
+ size=1 align=1
+ base size=0 base align=1
+std::__result_of_memfun_deref_impl (0x0x7f234df4f900) 0 empty
+
+Class std::__result_of_memobj_ref_impl
+ size=1 align=1
+ base size=0 base align=1
+std::__result_of_memobj_ref_impl (0x0x7f234df4f9c0) 0 empty
+
+Class std::__result_of_memobj_deref_impl
+ size=1 align=1
+ base size=0 base align=1
+std::__result_of_memobj_deref_impl (0x0x7f234df4fa80) 0 empty
+
+Class std::__result_of_other_impl
+ size=1 align=1
+ base size=0 base align=1
+std::__result_of_other_impl (0x0x7f234df4fde0) 0 empty
+
+Class std::__swappable_details::__do_is_swappable_impl
+ size=1 align=1
+ base size=0 base align=1
+std::__swappable_details::__do_is_swappable_impl (0x0x7f234df8f180) 0 empty
+
+Class std::__swappable_details::__do_is_nothrow_swappable_impl
+ size=1 align=1
+ base size=0 base align=1
+std::__swappable_details::__do_is_nothrow_swappable_impl (0x0x7f234df8f1e0) 0 empty
+
+Class std::__nonesuch
+ size=1 align=1
+ base size=0 base align=1
+std::__nonesuch (0x0x7f234df8f780) 0 empty
+
+Class std::piecewise_construct_t
+ size=1 align=1
+ base size=0 base align=1
+std::piecewise_construct_t (0x0x7f234df8fde0) 0 empty
+
+Class std::__nonesuch_no_braces
+ size=1 align=1
+ base size=1 base align=1
+std::__nonesuch_no_braces (0x0x7f234dfa71a0) 0 empty
+ std::__nonesuch (0x0x7f234dfd2300) 0 empty
+
+Class std::__true_type
+ size=1 align=1
+ base size=0 base align=1
+std::__true_type (0x0x7f234e01fc60) 0 empty
+
+Class std::__false_type
+ size=1 align=1
+ base size=0 base align=1
+std::__false_type (0x0x7f234e01fcc0) 0 empty
+
+Class std::input_iterator_tag
+ size=1 align=1
+ base size=0 base align=1
+std::input_iterator_tag (0x0x7f234e07a9c0) 0 empty
+
+Class std::output_iterator_tag
+ size=1 align=1
+ base size=0 base align=1
+std::output_iterator_tag (0x0x7f234e07aa20) 0 empty
+
+Class std::forward_iterator_tag
+ size=1 align=1
+ base size=1 base align=1
+std::forward_iterator_tag (0x0x7f234dfa7680) 0 empty
+ std::input_iterator_tag (0x0x7f234e07aa80) 0 empty
+
+Class std::bidirectional_iterator_tag
+ size=1 align=1
+ base size=1 base align=1
+std::bidirectional_iterator_tag (0x0x7f234dfa76e8) 0 empty
+ std::forward_iterator_tag (0x0x7f234dfa7750) 0 empty
+ std::input_iterator_tag (0x0x7f234e07aae0) 0 empty
+
+Class std::random_access_iterator_tag
+ size=1 align=1
+ base size=1 base align=1
+std::random_access_iterator_tag (0x0x7f234dfa77b8) 0 empty
+ std::bidirectional_iterator_tag (0x0x7f234dfa7820) 0 empty
+ std::forward_iterator_tag (0x0x7f234dfa7888) 0 empty
+ std::input_iterator_tag (0x0x7f234e07ab40) 0 empty
+
+Class __gnu_cxx::__ops::_Iter_less_iter
+ size=1 align=1
+ base size=0 base align=1
+__gnu_cxx::__ops::_Iter_less_iter (0x0x7f234e12d660) 0 empty
+
+Class __gnu_cxx::__ops::_Iter_less_val
+ size=1 align=1
+ base size=0 base align=1
+__gnu_cxx::__ops::_Iter_less_val (0x0x7f234e12d780) 0 empty
+
+Class __gnu_cxx::__ops::_Val_less_iter
+ size=1 align=1
+ base size=0 base align=1
+__gnu_cxx::__ops::_Val_less_iter (0x0x7f234e12da80) 0 empty
+
+Class __gnu_cxx::__ops::_Iter_equal_to_iter
+ size=1 align=1
+ base size=0 base align=1
+__gnu_cxx::__ops::_Iter_equal_to_iter (0x0x7f234e12dd80) 0 empty
+
+Class __gnu_cxx::__ops::_Iter_equal_to_val
+ size=1 align=1
+ base size=0 base align=1
+__gnu_cxx::__ops::_Iter_equal_to_val (0x0x7f234e12dea0) 0 empty
+
+Class __locale_struct
+ size=232 align=8
+ base size=232 base align=8
+__locale_struct (0x0x7f234ddeb1e0) 0
+
+Class timeval
+ size=16 align=8
+ base size=16 base align=8
+timeval (0x0x7f234ddeb4e0) 0
+
+Class timespec
+ size=16 align=8
+ base size=16 base align=8
+timespec (0x0x7f234ddeb540) 0
+
+Class __pthread_rwlock_arch_t
+ size=56 align=8
+ base size=56 base align=8
+__pthread_rwlock_arch_t (0x0x7f234ddeb600) 0
+
+Class __pthread_internal_list
+ size=16 align=8
+ base size=16 base align=8
+__pthread_internal_list (0x0x7f234ddeb660) 0
+
+Class __pthread_mutex_s
+ size=40 align=8
+ base size=40 base align=8
+__pthread_mutex_s (0x0x7f234ddeb6c0) 0
+
+Class __pthread_cond_s
+ size=48 align=8
+ base size=48 base align=8
+__pthread_cond_s (0x0x7f234ddeb720) 0
+
+Class pthread_attr_t
+ size=56 align=8
+ base size=56 base align=8
+pthread_attr_t (0x0x7f234ddeb9c0) 0
+
+Class random_data
+ size=48 align=8
+ base size=48 base align=8
+random_data (0x0x7f234ddebc60) 0
+
+Class drand48_data
+ size=24 align=8
+ base size=24 base align=8
+drand48_data (0x0x7f234ddebcc0) 0
+
+Vtable for std::exception
+std::exception::_ZTVSt9exception: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTISt9exception)
+16 (int (*)(...))std::exception::~exception
+24 (int (*)(...))std::exception::~exception
+32 (int (*)(...))std::exception::what
+
+Class std::exception
+ size=8 align=8
+ base size=8 base align=8
+std::exception (0x0x7f234deb4a80) 0 nearly-empty
+ vptr=((& std::exception::_ZTVSt9exception) + 16)
+
+Vtable for std::bad_exception
+std::bad_exception::_ZTVSt13bad_exception: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTISt13bad_exception)
+16 (int (*)(...))std::bad_exception::~bad_exception
+24 (int (*)(...))std::bad_exception::~bad_exception
+32 (int (*)(...))std::bad_exception::what
+
+Class std::bad_exception
+ size=8 align=8
+ base size=8 base align=8
+std::bad_exception (0x0x7f234dfa7bc8) 0 nearly-empty
+ vptr=((& std::bad_exception::_ZTVSt13bad_exception) + 16)
+ std::exception (0x0x7f234deb4c60) 0 nearly-empty
+ primary-for std::bad_exception (0x0x7f234dfa7bc8)
+
+Vtable for std::type_info
+std::type_info::_ZTVSt9type_info: 8 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTISt9type_info)
+16 (int (*)(...))std::type_info::~type_info
+24 (int (*)(...))std::type_info::~type_info
+32 (int (*)(...))std::type_info::__is_pointer_p
+40 (int (*)(...))std::type_info::__is_function_p
+48 (int (*)(...))std::type_info::__do_catch
+56 (int (*)(...))std::type_info::__do_upcast
+
+Class std::type_info
+ size=16 align=8
+ base size=16 base align=8
+std::type_info (0x0x7f234deb4e40) 0
+ vptr=((& std::type_info::_ZTVSt9type_info) + 16)
+
+Vtable for std::bad_cast
+std::bad_cast::_ZTVSt8bad_cast: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTISt8bad_cast)
+16 (int (*)(...))std::bad_cast::~bad_cast
+24 (int (*)(...))std::bad_cast::~bad_cast
+32 (int (*)(...))std::bad_cast::what
+
+Class std::bad_cast
+ size=8 align=8
+ base size=8 base align=8
+std::bad_cast (0x0x7f234dfa7c30) 0 nearly-empty
+ vptr=((& std::bad_cast::_ZTVSt8bad_cast) + 16)
+ std::exception (0x0x7f234deeb240) 0 nearly-empty
+ primary-for std::bad_cast (0x0x7f234dfa7c30)
+
+Vtable for std::bad_typeid
+std::bad_typeid::_ZTVSt10bad_typeid: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTISt10bad_typeid)
+16 (int (*)(...))std::bad_typeid::~bad_typeid
+24 (int (*)(...))std::bad_typeid::~bad_typeid
+32 (int (*)(...))std::bad_typeid::what
+
+Class std::bad_typeid
+ size=8 align=8
+ base size=8 base align=8
+std::bad_typeid (0x0x7f234dfa7c98) 0 nearly-empty
+ vptr=((& std::bad_typeid::_ZTVSt10bad_typeid) + 16)
+ std::exception (0x0x7f234deeb420) 0 nearly-empty
+ primary-for std::bad_typeid (0x0x7f234dfa7c98)
+
+Class std::__exception_ptr::exception_ptr
+ size=8 align=8
+ base size=8 base align=8
+std::__exception_ptr::exception_ptr (0x0x7f234deeb600) 0
+
+Vtable for std::nested_exception
+std::nested_exception::_ZTVSt16nested_exception: 4 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTISt16nested_exception)
+16 (int (*)(...))std::nested_exception::~nested_exception
+24 (int (*)(...))std::nested_exception::~nested_exception
+
+Class std::nested_exception
+ size=16 align=8
+ base size=16 base align=8
+std::nested_exception (0x0x7f234deebba0) 0
+ vptr=((& std::nested_exception::_ZTVSt16nested_exception) + 16)
+
+Vtable for std::bad_alloc
+std::bad_alloc::_ZTVSt9bad_alloc: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTISt9bad_alloc)
+16 (int (*)(...))std::bad_alloc::~bad_alloc
+24 (int (*)(...))std::bad_alloc::~bad_alloc
+32 (int (*)(...))std::bad_alloc::what
+
+Class std::bad_alloc
+ size=8 align=8
+ base size=8 base align=8
+std::bad_alloc (0x0x7f234dfa7d00) 0 nearly-empty
+ vptr=((& std::bad_alloc::_ZTVSt9bad_alloc) + 16)
+ std::exception (0x0x7f234df1a2a0) 0 nearly-empty
+ primary-for std::bad_alloc (0x0x7f234dfa7d00)
+
+Vtable for std::bad_array_new_length
+std::bad_array_new_length::_ZTVSt20bad_array_new_length: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTISt20bad_array_new_length)
+16 (int (*)(...))std::bad_array_new_length::~bad_array_new_length
+24 (int (*)(...))std::bad_array_new_length::~bad_array_new_length
+32 (int (*)(...))std::bad_array_new_length::what
+
+Class std::bad_array_new_length
+ size=8 align=8
+ base size=8 base align=8
+std::bad_array_new_length (0x0x7f234dfa7d68) 0 nearly-empty
+ vptr=((& std::bad_array_new_length::_ZTVSt20bad_array_new_length) + 16)
+ std::bad_alloc (0x0x7f234dfa7dd0) 0 nearly-empty
+ primary-for std::bad_array_new_length (0x0x7f234dfa7d68)
+ std::exception (0x0x7f234df1a480) 0 nearly-empty
+ primary-for std::bad_alloc (0x0x7f234dfa7dd0)
+
+Class std::nothrow_t
+ size=1 align=1
+ base size=0 base align=1
+std::nothrow_t (0x0x7f234df1a660) 0 empty
+
+Class std::__allocator_traits_base
+ size=1 align=1
+ base size=0 base align=1
+std::__allocator_traits_base (0x0x7f234df1a840) 0 empty
+
+Class std::__numeric_limits_base
+ size=1 align=1
+ base size=0 base align=1
+std::__numeric_limits_base (0x0x7f234db97d20) 0 empty
+
+Class qIsNull(double)::U
+ size=8 align=8
+ base size=8 base align=8
+qIsNull(double)::U (0x0x7f234d9737e0) 0
+
+Class qIsNull(float)::U
+ size=4 align=4
+ base size=4 base align=4
+qIsNull(float)::U (0x0x7f234d9738a0) 0
+
+Class QSysInfo
+ size=1 align=1
+ base size=0 base align=1
+QSysInfo (0x0x7f234d834240) 0 empty
+
+Class QMessageLogContext
+ size=32 align=8
+ base size=32 base align=8
+QMessageLogContext (0x0x7f234d834360) 0
+
+Class QMessageLogger
+ size=32 align=8
+ base size=32 base align=8
+QMessageLogger (0x0x7f234d8346c0) 0
+
+Class QFlag
+ size=4 align=4
+ base size=4 base align=4
+QFlag (0x0x7f234d834c00) 0
+
+Class QIncompatibleFlag
+ size=4 align=4
+ base size=4 base align=4
+QIncompatibleFlag (0x0x7f234d8ad3c0) 0
+
+Class std::__atomic_flag_base
+ size=1 align=1
+ base size=1 base align=1
+std::__atomic_flag_base (0x0x7f234d5437e0) 0
+
+Class std::atomic_flag
+ size=1 align=1
+ base size=1 base align=1
+std::atomic_flag (0x0x7f234d8e5c30) 0
+ std::__atomic_flag_base (0x0x7f234d543840) 0
+
+Class QAtomicInt
+ size=4 align=4
+ base size=4 base align=4
+QAtomicInt (0x0x7f234d7273a8) 0
+ QAtomicInteger<int> (0x0x7f234d727410) 0
+ QBasicAtomicInteger<int> (0x0x7f234d4787e0) 0
+
+Class QInternal
+ size=1 align=1
+ base size=0 base align=1
+QInternal (0x0x7f234d090ae0) 0 empty
+
+Class QtPrivate::QSlotObjectBase
+ size=16 align=8
+ base size=16 base align=8
+QtPrivate::QSlotObjectBase (0x0x7f234d1010c0) 0
+
+Class QGenericArgument
+ size=16 align=8
+ base size=16 base align=8
+QGenericArgument (0x0x7f234d1017e0) 0
+
+Class QGenericReturnArgument
+ size=16 align=8
+ base size=16 base align=8
+QGenericReturnArgument (0x0x7f234d240f70) 0
+ QGenericArgument (0x0x7f234d101a80) 0
+
+Class QMetaObject
+ size=48 align=8
+ base size=48 base align=8
+QMetaObject (0x0x7f234d101ea0) 0
+
+Class QMetaObject::Connection
+ size=8 align=8
+ base size=8 base align=8
+QMetaObject::Connection (0x0x7f234cd60300) 0
+
+Class QLatin1Char
+ size=1 align=1
+ base size=1 base align=1
+QLatin1Char (0x0x7f234cdc6de0) 0
+
+Class QChar
+ size=2 align=2
+ base size=2 base align=2
+QChar (0x0x7f234cde60c0) 0
+
+Class QtPrivate::RefCount
+ size=4 align=4
+ base size=4 base align=4
+QtPrivate::RefCount (0x0x7f234ce96ea0) 0
+
+Class QArrayData
+ size=24 align=8
+ base size=24 base align=8
+QArrayData (0x0x7f234ceb8240) 0
+
+Class QtPrivate::QContainerImplHelper
+ size=1 align=1
+ base size=0 base align=1
+QtPrivate::QContainerImplHelper (0x0x7f234cf1b540) 0 empty
+
+Class lconv
+ size=96 align=8
+ base size=96 base align=8
+lconv (0x0x7f234cbccd80) 0
+
+Vtable for __cxxabiv1::__forced_unwind
+__cxxabiv1::__forced_unwind::_ZTVN10__cxxabiv115__forced_unwindE: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTIN10__cxxabiv115__forced_unwindE)
+16 0
+24 0
+32 (int (*)(...))__cxa_pure_virtual
+
+Class __cxxabiv1::__forced_unwind
+ size=8 align=8
+ base size=8 base align=8
+__cxxabiv1::__forced_unwind (0x0x7f234cbcce40) 0 nearly-empty
+ vptr=((& __cxxabiv1::__forced_unwind::_ZTVN10__cxxabiv115__forced_unwindE) + 16)
+
+Class sched_param
+ size=4 align=4
+ base size=4 base align=4
+sched_param (0x0x7f234cc8ff60) 0
+
+Class timex
+ size=208 align=8
+ base size=208 base align=8
+timex (0x0x7f234ccc0060) 0
+
+Class tm
+ size=56 align=8
+ base size=56 base align=8
+tm (0x0x7f234ccc00c0) 0
+
+Class itimerspec
+ size=32 align=8
+ base size=32 base align=8
+itimerspec (0x0x7f234ccc0120) 0
+
+Class _pthread_cleanup_buffer
+ size=32 align=8
+ base size=32 base align=8
+_pthread_cleanup_buffer (0x0x7f234ccc0180) 0
+
+Class __pthread_cleanup_frame
+ size=24 align=8
+ base size=24 base align=8
+__pthread_cleanup_frame (0x0x7f234ccc02a0) 0
+
+Class __pthread_cleanup_class
+ size=24 align=8
+ base size=24 base align=8
+__pthread_cleanup_class (0x0x7f234ccc0300) 0
+
+Class _IO_marker
+ size=24 align=8
+ base size=24 base align=8
+_IO_marker (0x0x7f234ca022a0) 0
+
+Class _IO_FILE
+ size=216 align=8
+ base size=216 base align=8
+_IO_FILE (0x0x7f234ca02300) 0
+
+Class std::_Hash_impl
+ size=1 align=1
+ base size=0 base align=1
+std::_Hash_impl (0x0x7f234c7b7360) 0 empty
+
+Class std::_Fnv_hash_impl
+ size=1 align=1
+ base size=0 base align=1
+std::_Fnv_hash_impl (0x0x7f234c7b74e0) 0 empty
+
+Class std::locale
+ size=8 align=8
+ base size=8 base align=8
+std::locale (0x0x7f234c933660) 0
+
+Vtable for std::locale::facet
+std::locale::facet::_ZTVNSt6locale5facetE: 4 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTINSt6locale5facetE)
+16 (int (*)(...))std::locale::facet::~facet
+24 (int (*)(...))std::locale::facet::~facet
+
+Class std::locale::facet
+ size=16 align=8
+ base size=12 base align=8
+std::locale::facet (0x0x7f234c933a20) 0
+ vptr=((& std::locale::facet::_ZTVNSt6locale5facetE) + 16)
+
+Class std::locale::id
+ size=8 align=8
+ base size=8 base align=8
+std::locale::id (0x0x7f234c933cc0) 0
+
+Class std::locale::_Impl
+ size=40 align=8
+ base size=40 base align=8
+std::locale::_Impl (0x0x7f234c933ea0) 0
+
+Class std::__cow_string
+ size=8 align=8
+ base size=8 base align=8
+std::__cow_string (0x0x7f234c588ea0) 0
+
+Vtable for std::logic_error
+std::logic_error::_ZTVSt11logic_error: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTISt11logic_error)
+16 (int (*)(...))std::logic_error::~logic_error
+24 (int (*)(...))std::logic_error::~logic_error
+32 (int (*)(...))std::logic_error::what
+
+Class std::logic_error
+ size=16 align=8
+ base size=16 base align=8
+std::logic_error (0x0x7f234c7b8958) 0
+ vptr=((& std::logic_error::_ZTVSt11logic_error) + 16)
+ std::exception (0x0x7f234c588f60) 0 nearly-empty
+ primary-for std::logic_error (0x0x7f234c7b8958)
+
+Vtable for std::domain_error
+std::domain_error::_ZTVSt12domain_error: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTISt12domain_error)
+16 (int (*)(...))std::domain_error::~domain_error
+24 (int (*)(...))std::domain_error::~domain_error
+32 (int (*)(...))std::logic_error::what
+
+Class std::domain_error
+ size=16 align=8
+ base size=16 base align=8
+std::domain_error (0x0x7f234c7b89c0) 0
+ vptr=((& std::domain_error::_ZTVSt12domain_error) + 16)
+ std::logic_error (0x0x7f234c5d9000) 0
+ primary-for std::domain_error (0x0x7f234c7b89c0)
+ std::exception (0x0x7f234c5da000) 0 nearly-empty
+ primary-for std::logic_error (0x0x7f234c5d9000)
+
+Vtable for std::invalid_argument
+std::invalid_argument::_ZTVSt16invalid_argument: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTISt16invalid_argument)
+16 (int (*)(...))std::invalid_argument::~invalid_argument
+24 (int (*)(...))std::invalid_argument::~invalid_argument
+32 (int (*)(...))std::logic_error::what
+
+Class std::invalid_argument
+ size=16 align=8
+ base size=16 base align=8
+std::invalid_argument (0x0x7f234c5d9068) 0
+ vptr=((& std::invalid_argument::_ZTVSt16invalid_argument) + 16)
+ std::logic_error (0x0x7f234c5d90d0) 0
+ primary-for std::invalid_argument (0x0x7f234c5d9068)
+ std::exception (0x0x7f234c5da060) 0 nearly-empty
+ primary-for std::logic_error (0x0x7f234c5d90d0)
+
+Vtable for std::length_error
+std::length_error::_ZTVSt12length_error: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTISt12length_error)
+16 (int (*)(...))std::length_error::~length_error
+24 (int (*)(...))std::length_error::~length_error
+32 (int (*)(...))std::logic_error::what
+
+Class std::length_error
+ size=16 align=8
+ base size=16 base align=8
+std::length_error (0x0x7f234c5d9138) 0
+ vptr=((& std::length_error::_ZTVSt12length_error) + 16)
+ std::logic_error (0x0x7f234c5d91a0) 0
+ primary-for std::length_error (0x0x7f234c5d9138)
+ std::exception (0x0x7f234c5da0c0) 0 nearly-empty
+ primary-for std::logic_error (0x0x7f234c5d91a0)
+
+Vtable for std::out_of_range
+std::out_of_range::_ZTVSt12out_of_range: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTISt12out_of_range)
+16 (int (*)(...))std::out_of_range::~out_of_range
+24 (int (*)(...))std::out_of_range::~out_of_range
+32 (int (*)(...))std::logic_error::what
+
+Class std::out_of_range
+ size=16 align=8
+ base size=16 base align=8
+std::out_of_range (0x0x7f234c5d9208) 0
+ vptr=((& std::out_of_range::_ZTVSt12out_of_range) + 16)
+ std::logic_error (0x0x7f234c5d9270) 0
+ primary-for std::out_of_range (0x0x7f234c5d9208)
+ std::exception (0x0x7f234c5da120) 0 nearly-empty
+ primary-for std::logic_error (0x0x7f234c5d9270)
+
+Vtable for std::runtime_error
+std::runtime_error::_ZTVSt13runtime_error: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTISt13runtime_error)
+16 (int (*)(...))std::runtime_error::~runtime_error
+24 (int (*)(...))std::runtime_error::~runtime_error
+32 (int (*)(...))std::runtime_error::what
+
+Class std::runtime_error
+ size=16 align=8
+ base size=16 base align=8
+std::runtime_error (0x0x7f234c5d92d8) 0
+ vptr=((& std::runtime_error::_ZTVSt13runtime_error) + 16)
+ std::exception (0x0x7f234c5da180) 0 nearly-empty
+ primary-for std::runtime_error (0x0x7f234c5d92d8)
+
+Vtable for std::range_error
+std::range_error::_ZTVSt11range_error: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTISt11range_error)
+16 (int (*)(...))std::range_error::~range_error
+24 (int (*)(...))std::range_error::~range_error
+32 (int (*)(...))std::runtime_error::what
+
+Class std::range_error
+ size=16 align=8
+ base size=16 base align=8
+std::range_error (0x0x7f234c5d9340) 0
+ vptr=((& std::range_error::_ZTVSt11range_error) + 16)
+ std::runtime_error (0x0x7f234c5d93a8) 0
+ primary-for std::range_error (0x0x7f234c5d9340)
+ std::exception (0x0x7f234c5da1e0) 0 nearly-empty
+ primary-for std::runtime_error (0x0x7f234c5d93a8)
+
+Vtable for std::overflow_error
+std::overflow_error::_ZTVSt14overflow_error: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTISt14overflow_error)
+16 (int (*)(...))std::overflow_error::~overflow_error
+24 (int (*)(...))std::overflow_error::~overflow_error
+32 (int (*)(...))std::runtime_error::what
+
+Class std::overflow_error
+ size=16 align=8
+ base size=16 base align=8
+std::overflow_error (0x0x7f234c5d9410) 0
+ vptr=((& std::overflow_error::_ZTVSt14overflow_error) + 16)
+ std::runtime_error (0x0x7f234c5d9478) 0
+ primary-for std::overflow_error (0x0x7f234c5d9410)
+ std::exception (0x0x7f234c5da240) 0 nearly-empty
+ primary-for std::runtime_error (0x0x7f234c5d9478)
+
+Vtable for std::underflow_error
+std::underflow_error::_ZTVSt15underflow_error: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTISt15underflow_error)
+16 (int (*)(...))std::underflow_error::~underflow_error
+24 (int (*)(...))std::underflow_error::~underflow_error
+32 (int (*)(...))std::runtime_error::what
+
+Class std::underflow_error
+ size=16 align=8
+ base size=16 base align=8
+std::underflow_error (0x0x7f234c5d94e0) 0
+ vptr=((& std::underflow_error::_ZTVSt15underflow_error) + 16)
+ std::runtime_error (0x0x7f234c5d9548) 0
+ primary-for std::underflow_error (0x0x7f234c5d94e0)
+ std::exception (0x0x7f234c5da2a0) 0 nearly-empty
+ primary-for std::runtime_error (0x0x7f234c5d9548)
+
+Vtable for std::_V2::error_category
+std::_V2::error_category::_ZTVNSt3_V214error_categoryE: 10 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTINSt3_V214error_categoryE)
+16 0
+24 0
+32 (int (*)(...))__cxa_pure_virtual
+40 (int (*)(...))std::_V2::error_category::_M_message
+48 (int (*)(...))__cxa_pure_virtual
+56 (int (*)(...))std::_V2::error_category::default_error_condition
+64 (int (*)(...))std::_V2::error_category::equivalent
+72 (int (*)(...))std::_V2::error_category::equivalent
+
+Class std::_V2::error_category
+ size=8 align=8
+ base size=8 base align=8
+std::_V2::error_category (0x0x7f234c5da420) 0 nearly-empty
+ vptr=((& std::_V2::error_category::_ZTVNSt3_V214error_categoryE) + 16)
+
+Class std::error_code
+ size=16 align=8
+ base size=16 base align=8
+std::error_code (0x0x7f234c5da780) 0
+
+Class std::error_condition
+ size=16 align=8
+ base size=16 base align=8
+std::error_condition (0x0x7f234c623000) 0
+
+Vtable for std::system_error
+std::system_error::_ZTVSt12system_error: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTISt12system_error)
+16 (int (*)(...))std::system_error::~system_error
+24 (int (*)(...))std::system_error::~system_error
+32 (int (*)(...))std::runtime_error::what
+
+Class std::system_error
+ size=32 align=8
+ base size=32 base align=8
+std::system_error (0x0x7f234c5d9958) 0
+ vptr=((& std::system_error::_ZTVSt12system_error) + 16)
+ std::runtime_error (0x0x7f234c5d99c0) 0
+ primary-for std::system_error (0x0x7f234c5d9958)
+ std::exception (0x0x7f234c623ba0) 0 nearly-empty
+ primary-for std::runtime_error (0x0x7f234c5d99c0)
+
+Vtable for std::ios_base::failure
+std::ios_base::failure::_ZTVNSt8ios_base7failureB5cxx11E: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTINSt8ios_base7failureB5cxx11E)
+16 (int (*)(...))std::ios_base::failure::~failure
+24 (int (*)(...))std::ios_base::failure::~failure
+32 (int (*)(...))std::ios_base::failure::what
+
+Class std::ios_base::failure
+ size=32 align=8
+ base size=32 base align=8
+std::ios_base::failure (0x0x7f234c5d9c30) 0
+ vptr=((& std::ios_base::failure::_ZTVNSt8ios_base7failureB5cxx11E) + 16)
+ std::system_error (0x0x7f234c5d9c98) 0
+ primary-for std::ios_base::failure (0x0x7f234c5d9c30)
+ std::runtime_error (0x0x7f234c5d9d00) 0
+ primary-for std::system_error (0x0x7f234c5d9c98)
+ std::exception (0x0x7f234c680180) 0 nearly-empty
+ primary-for std::runtime_error (0x0x7f234c5d9d00)
+
+Class std::ios_base::_Callback_list
+ size=24 align=8
+ base size=24 base align=8
+std::ios_base::_Callback_list (0x0x7f234c6801e0) 0
+
+Class std::ios_base::_Words
+ size=16 align=8
+ base size=16 base align=8
+std::ios_base::_Words (0x0x7f234c680240) 0
+
+Class std::ios_base::Init
+ size=1 align=1
+ base size=0 base align=1
+std::ios_base::Init (0x0x7f234c6802a0) 0 empty
+
+Vtable for std::ios_base
+std::ios_base::_ZTVSt8ios_base: 4 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTISt8ios_base)
+16 (int (*)(...))std::ios_base::~ios_base
+24 (int (*)(...))std::ios_base::~ios_base
+
+Class std::ios_base
+ size=216 align=8
+ base size=216 base align=8
+std::ios_base (0x0x7f234c680120) 0
+ vptr=((& std::ios_base::_ZTVSt8ios_base) + 16)
+
+Class std::ctype_base
+ size=1 align=1
+ base size=0 base align=1
+std::ctype_base (0x0x7f234c34cba0) 0 empty
+
+Class std::__num_base
+ size=1 align=1
+ base size=0 base align=1
+std::__num_base (0x0x7f234c3f4d80) 0 empty
+
+VTT for std::basic_ostream<char>
+std::basic_ostream<char>::_ZTTSo: 2 entries
+0 ((& std::basic_ostream<char>::_ZTVSo) + 24)
+8 ((& std::basic_ostream<char>::_ZTVSo) + 64)
+
+VTT for std::basic_ostream<wchar_t>
+std::basic_ostream<wchar_t>::_ZTTSt13basic_ostreamIwSt11char_traitsIwEE: 2 entries
+0 ((& std::basic_ostream<wchar_t>::_ZTVSt13basic_ostreamIwSt11char_traitsIwEE) + 24)
+8 ((& std::basic_ostream<wchar_t>::_ZTVSt13basic_ostreamIwSt11char_traitsIwEE) + 64)
+
+VTT for std::basic_istream<char>
+std::basic_istream<char>::_ZTTSi: 2 entries
+0 ((& std::basic_istream<char>::_ZTVSi) + 24)
+8 ((& std::basic_istream<char>::_ZTVSi) + 64)
+
+VTT for std::basic_istream<wchar_t>
+std::basic_istream<wchar_t>::_ZTTSt13basic_istreamIwSt11char_traitsIwEE: 2 entries
+0 ((& std::basic_istream<wchar_t>::_ZTVSt13basic_istreamIwSt11char_traitsIwEE) + 24)
+8 ((& std::basic_istream<wchar_t>::_ZTVSt13basic_istreamIwSt11char_traitsIwEE) + 64)
+
+Construction vtable for std::basic_istream<char> (0x0x7f234bfc9410 instance) in std::basic_iostream<char>
+std::basic_iostream<char>::_ZTCSd0_Si: 10 entries
+0 24
+8 (int (*)(...))0
+16 (int (*)(...))(& _ZTISi)
+24 0
+32 0
+40 18446744073709551592
+48 (int (*)(...))-24
+56 (int (*)(...))(& _ZTISi)
+64 0
+72 0
+
+Construction vtable for std::basic_ostream<char> (0x0x7f234bfc94e0 instance) in std::basic_iostream<char>
+std::basic_iostream<char>::_ZTCSd16_So: 10 entries
+0 8
+8 (int (*)(...))0
+16 (int (*)(...))(& _ZTISo)
+24 0
+32 0
+40 18446744073709551608
+48 (int (*)(...))-8
+56 (int (*)(...))(& _ZTISo)
+64 0
+72 0
+
+VTT for std::basic_iostream<char>
+std::basic_iostream<char>::_ZTTSd: 7 entries
+0 ((& std::basic_iostream<char>::_ZTVSd) + 24)
+8 ((& std::basic_iostream<char>::_ZTCSd0_Si) + 24)
+16 ((& std::basic_iostream<char>::_ZTCSd0_Si) + 64)
+24 ((& std::basic_iostream<char>::_ZTCSd16_So) + 24)
+32 ((& std::basic_iostream<char>::_ZTCSd16_So) + 64)
+40 ((& std::basic_iostream<char>::_ZTVSd) + 104)
+48 ((& std::basic_iostream<char>::_ZTVSd) + 64)
+
+Construction vtable for std::basic_istream<wchar_t> (0x0x7f234c00b1a0 instance) in std::basic_iostream<wchar_t>
+std::basic_iostream<wchar_t>::_ZTCSt14basic_iostreamIwSt11char_traitsIwEE0_St13basic_istreamIwS1_E: 10 entries
+0 24
+8 (int (*)(...))0
+16 (int (*)(...))(& _ZTISt13basic_istreamIwSt11char_traitsIwEE)
+24 0
+32 0
+40 18446744073709551592
+48 (int (*)(...))-24
+56 (int (*)(...))(& _ZTISt13basic_istreamIwSt11char_traitsIwEE)
+64 0
+72 0
+
+Construction vtable for std::basic_ostream<wchar_t> (0x0x7f234c00b270 instance) in std::basic_iostream<wchar_t>
+std::basic_iostream<wchar_t>::_ZTCSt14basic_iostreamIwSt11char_traitsIwEE16_St13basic_ostreamIwS1_E: 10 entries
+0 8
+8 (int (*)(...))0
+16 (int (*)(...))(& _ZTISt13basic_ostreamIwSt11char_traitsIwEE)
+24 0
+32 0
+40 18446744073709551608
+48 (int (*)(...))-8
+56 (int (*)(...))(& _ZTISt13basic_ostreamIwSt11char_traitsIwEE)
+64 0
+72 0
+
+VTT for std::basic_iostream<wchar_t>
+std::basic_iostream<wchar_t>::_ZTTSt14basic_iostreamIwSt11char_traitsIwEE: 7 entries
+0 ((& std::basic_iostream<wchar_t>::_ZTVSt14basic_iostreamIwSt11char_traitsIwEE) + 24)
+8 ((& std::basic_iostream<wchar_t>::_ZTCSt14basic_iostreamIwSt11char_traitsIwEE0_St13basic_istreamIwS1_E) + 24)
+16 ((& std::basic_iostream<wchar_t>::_ZTCSt14basic_iostreamIwSt11char_traitsIwEE0_St13basic_istreamIwS1_E) + 64)
+24 ((& std::basic_iostream<wchar_t>::_ZTCSt14basic_iostreamIwSt11char_traitsIwEE16_St13basic_ostreamIwS1_E) + 24)
+32 ((& std::basic_iostream<wchar_t>::_ZTCSt14basic_iostreamIwSt11char_traitsIwEE16_St13basic_ostreamIwS1_E) + 64)
+40 ((& std::basic_iostream<wchar_t>::_ZTVSt14basic_iostreamIwSt11char_traitsIwEE) + 104)
+48 ((& std::basic_iostream<wchar_t>::_ZTVSt14basic_iostreamIwSt11char_traitsIwEE) + 64)
+
+Class QByteArrayDataPtr
+ size=8 align=8
+ base size=8 base align=8
+QByteArrayDataPtr (0x0x7f234c02b720) 0
+
+Class QByteArray
+ size=8 align=8
+ base size=8 base align=8
+QByteArray (0x0x7f234c02b780) 0
+
+Class QByteRef
+ size=16 align=8
+ base size=12 base align=8
+QByteRef (0x0x7f234bd47b40) 0
+
+Class QStringDataPtr
+ size=8 align=8
+ base size=8 base align=8
+QStringDataPtr (0x0x7f234bdec9c0) 0
+
+Class QStringView
+ size=16 align=8
+ base size=16 base align=8
+QStringView (0x0x7f234bdece40) 0
+
+Class QLatin1String
+ size=16 align=8
+ base size=16 base align=8
+QLatin1String (0x0x7f234bebdc00) 0
+
+Class QString::Null
+ size=1 align=1
+ base size=0 base align=1
+QString::Null (0x0x7f234bb4d660) 0 empty
+
+Class QString
+ size=8 align=8
+ base size=8 base align=8
+QString (0x0x7f234bb4d600) 0
+
+Class QCharRef
+ size=16 align=8
+ base size=12 base align=8
+QCharRef (0x0x7f234b9317e0) 0
+
+Class QStringRef
+ size=16 align=8
+ base size=16 base align=8
+QStringRef (0x0x7f234bad2060) 0
+
+Class QtPrivate::QHashCombine
+ size=1 align=1
+ base size=0 base align=1
+QtPrivate::QHashCombine (0x0x7f234b8eb360) 0 empty
+
+Class QtPrivate::QHashCombineCommutative
+ size=1 align=1
+ base size=0 base align=1
+QtPrivate::QHashCombineCommutative (0x0x7f234b8eb420) 0 empty
+
+Class std::_Bit_reference
+ size=16 align=8
+ base size=16 base align=8
+std::_Bit_reference (0x0x7f234b59a900) 0
+
+Class std::_Bit_iterator_base
+ size=16 align=8
+ base size=12 base align=8
+std::_Bit_iterator_base (0x0x7f234b8bf5b0) 0
+ std::iterator<std::random_access_iterator_tag, bool> (0x0x7f234b5bd060) 0 empty
+
+Class std::_Bit_iterator
+ size=16 align=8
+ base size=12 base align=8
+std::_Bit_iterator (0x0x7f234b8bf6e8) 0
+ std::_Bit_iterator_base (0x0x7f234b8bf750) 0
+ std::iterator<std::random_access_iterator_tag, bool> (0x0x7f234b5bd6c0) 0 empty
+
+Class std::_Bit_const_iterator
+ size=16 align=8
+ base size=12 base align=8
+std::_Bit_const_iterator (0x0x7f234b8bf7b8) 0
+ std::_Bit_iterator_base (0x0x7f234b8bf820) 0
+ std::iterator<std::random_access_iterator_tag, bool> (0x0x7f234b5bdea0) 0 empty
+
+Class std::__detail::_List_node_base
+ size=16 align=8
+ base size=16 base align=8
+std::__detail::_List_node_base (0x0x7f234b3d5540) 0
+
+Class QListData::NotArrayCompatibleLayout
+ size=1 align=1
+ base size=0 base align=1
+QListData::NotArrayCompatibleLayout (0x0x7f234b4a1300) 0 empty
+
+Class QListData::NotIndirectLayout
+ size=1 align=1
+ base size=0 base align=1
+QListData::NotIndirectLayout (0x0x7f234b4a1360) 0 empty
+
+Class QListData::ArrayCompatibleLayout
+ size=1 align=1
+ base size=1 base align=1
+QListData::ArrayCompatibleLayout (0x0x7f234b3aa270) 0 empty
+ QListData::NotIndirectLayout (0x0x7f234b4a13c0) 0 empty
+
+Class QListData::InlineWithPaddingLayout
+ size=1 align=1
+ base size=1 base align=1
+QListData::InlineWithPaddingLayout (0x0x7f234b32ee70) 0 empty
+ QListData::NotArrayCompatibleLayout (0x0x7f234b4a1420) 0 empty
+ QListData::NotIndirectLayout (0x0x7f234b4a1480) 0 empty
+
+Class QListData::IndirectLayout
+ size=1 align=1
+ base size=1 base align=1
+QListData::IndirectLayout (0x0x7f234b3aa2d8) 0 empty
+ QListData::NotArrayCompatibleLayout (0x0x7f234b4a14e0) 0 empty
+
+Class QListData::Data
+ size=24 align=8
+ base size=24 base align=8
+QListData::Data (0x0x7f234b4a1540) 0
+
+Class QListData
+ size=8 align=8
+ base size=8 base align=8
+QListData (0x0x7f234b4a12a0) 0
+
+Class QRegExp
+ size=8 align=8
+ base size=8 base align=8
+QRegExp (0x0x7f234b18e720) 0
+
+Class QStringMatcher::Data
+ size=272 align=8
+ base size=272 base align=8
+QStringMatcher::Data (0x0x7f234b26cd80) 0
+
+Class QStringMatcher
+ size=1048 align=8
+ base size=1048 base align=8
+QStringMatcher (0x0x7f234b26cd20) 0
+
+Class QStringList
+ size=8 align=8
+ base size=8 base align=8
+QStringList (0x0x7f234b2bb000) 0
+ QList<QString> (0x0x7f234b2bb068) 0
+ QListSpecialMethods<QString> (0x0x7f234b2bc000) 0 empty
+
+Class QScopedPointerPodDeleter
+ size=1 align=1
+ base size=0 base align=1
+QScopedPointerPodDeleter (0x0x7f234af29b40) 0 empty
+
+Class std::_Rb_tree_node_base
+ size=32 align=8
+ base size=32 base align=8
+std::_Rb_tree_node_base (0x0x7f234afbec60) 0
+
+Class std::_Rb_tree_header
+ size=40 align=8
+ base size=40 base align=8
+std::_Rb_tree_header (0x0x7f234afe1000) 0
+
+Class std::__erased_type
+ size=1 align=1
+ base size=0 base align=1
+std::__erased_type (0x0x7f234adb85a0) 0 empty
+
+Class std::allocator_arg_t
+ size=1 align=1
+ base size=0 base align=1
+std::allocator_arg_t (0x0x7f234adb8600) 0 empty
+
+Class std::__uses_alloc_base
+ size=1 align=1
+ base size=0 base align=1
+std::__uses_alloc_base (0x0x7f234adb8780) 0 empty
+
+Class std::__uses_alloc0::_Sink
+ size=1 align=1
+ base size=0 base align=1
+std::__uses_alloc0::_Sink (0x0x7f234adb8840) 0 empty
+
+Class std::__uses_alloc0
+ size=1 align=1
+ base size=1 base align=1
+std::__uses_alloc0 (0x0x7f234ad4b3a8) 0
+ std::__uses_alloc_base (0x0x7f234adb87e0) 0 empty
+
+Class std::_Swallow_assign
+ size=1 align=1
+ base size=0 base align=1
+std::_Swallow_assign (0x0x7f234aa9dba0) 0 empty
+
+Class QtPrivate::AbstractDebugStreamFunction
+ size=16 align=8
+ base size=16 base align=8
+QtPrivate::AbstractDebugStreamFunction (0x0x7f234ab63060) 0
+
+Class QtPrivate::AbstractComparatorFunction
+ size=24 align=8
+ base size=24 base align=8
+QtPrivate::AbstractComparatorFunction (0x0x7f234ab633c0) 0
+
+Class QtPrivate::AbstractConverterFunction
+ size=8 align=8
+ base size=8 base align=8
+QtPrivate::AbstractConverterFunction (0x0x7f234ab63900) 0
+
+Class QMetaType
+ size=80 align=8
+ base size=80 base align=8
+QMetaType (0x0x7f234ab63e40) 0
+
+Class QtMetaTypePrivate::VariantData
+ size=24 align=8
+ base size=20 base align=8
+QtMetaTypePrivate::VariantData (0x0x7f234abee060) 0
+
+Class QtMetaTypePrivate::VectorBoolElements
+ size=1 align=1
+ base size=0 base align=1
+QtMetaTypePrivate::VectorBoolElements (0x0x7f234abee720) 0 empty
+
+Class QtMetaTypePrivate::QSequentialIterableImpl
+ size=104 align=8
+ base size=104 base align=8
+QtMetaTypePrivate::QSequentialIterableImpl (0x0x7f234ac855a0) 0
+
+Class QtMetaTypePrivate::QAssociativeIterableImpl
+ size=112 align=8
+ base size=112 base align=8
+QtMetaTypePrivate::QAssociativeIterableImpl (0x0x7f234a8dcc60) 0
+
+Class QtMetaTypePrivate::QPairVariantInterfaceImpl
+ size=40 align=8
+ base size=40 base align=8
+QtMetaTypePrivate::QPairVariantInterfaceImpl (0x0x7f234a9551e0) 0
+
+Class std::chrono::_V2::system_clock
+ size=1 align=1
+ base size=0 base align=1
+std::chrono::_V2::system_clock (0x0x7f234a7a4000) 0 empty
+
+Class std::chrono::_V2::steady_clock
+ size=1 align=1
+ base size=0 base align=1
+std::chrono::_V2::steady_clock (0x0x7f234a49ea80) 0 empty
+
+Vtable for QObjectData
+QObjectData::_ZTV11QObjectData: 4 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI11QObjectData)
+16 (int (*)(...))__cxa_pure_virtual
+24 (int (*)(...))__cxa_pure_virtual
+
+Class QObjectData
+ size=48 align=8
+ base size=48 base align=8
+QObjectData (0x0x7f234a49eae0) 0
+ vptr=((& QObjectData::_ZTV11QObjectData) + 16)
+
+Class QObject::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QObject::QPrivateSignal (0x0x7f234a49ecc0) 0 empty
+
+Vtable for QObject
+QObject::_ZTV7QObject: 14 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI7QObject)
+16 (int (*)(...))QObject::metaObject
+24 (int (*)(...))QObject::qt_metacast
+32 (int (*)(...))QObject::qt_metacall
+40 (int (*)(...))QObject::~QObject
+48 (int (*)(...))QObject::~QObject
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+
+Class QObject
+ size=16 align=8
+ base size=16 base align=8
+QObject (0x0x7f234a49ec60) 0
+ vptr=((& QObject::_ZTV7QObject) + 16)
+
+Vtable for QObjectUserData
+QObjectUserData::_ZTV15QObjectUserData: 4 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI15QObjectUserData)
+16 (int (*)(...))QObjectUserData::~QObjectUserData
+24 (int (*)(...))QObjectUserData::~QObjectUserData
+
+Class QObjectUserData
+ size=8 align=8
+ base size=8 base align=8
+QObjectUserData (0x0x7f234a578ae0) 0 nearly-empty
+ vptr=((& QObjectUserData::_ZTV15QObjectUserData) + 16)
+
+Class QSignalBlocker
+ size=16 align=8
+ base size=10 base align=8
+QSignalBlocker (0x0x7f234a578c60) 0
+
+Class QAbstractAnimation::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QAbstractAnimation::QPrivateSignal (0x0x7f234a599540) 0 empty
+
+Vtable for QAbstractAnimation
+QAbstractAnimation::_ZTV18QAbstractAnimation: 18 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI18QAbstractAnimation)
+16 (int (*)(...))QAbstractAnimation::metaObject
+24 (int (*)(...))QAbstractAnimation::qt_metacast
+32 (int (*)(...))QAbstractAnimation::qt_metacall
+40 0
+48 0
+56 (int (*)(...))QAbstractAnimation::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))__cxa_pure_virtual
+120 (int (*)(...))__cxa_pure_virtual
+128 (int (*)(...))QAbstractAnimation::updateState
+136 (int (*)(...))QAbstractAnimation::updateDirection
+
+Class QAbstractAnimation
+ size=16 align=8
+ base size=16 base align=8
+QAbstractAnimation (0x0x7f234a57d5b0) 0
+ vptr=((& QAbstractAnimation::_ZTV18QAbstractAnimation) + 16)
+ QObject (0x0x7f234a5994e0) 0
+ primary-for QAbstractAnimation (0x0x7f234a57d5b0)
+
+Class QAnimationDriver::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QAnimationDriver::QPrivateSignal (0x0x7f234a599900) 0 empty
+
+Vtable for QAnimationDriver
+QAnimationDriver::_ZTV16QAnimationDriver: 18 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI16QAnimationDriver)
+16 (int (*)(...))QAnimationDriver::metaObject
+24 (int (*)(...))QAnimationDriver::qt_metacast
+32 (int (*)(...))QAnimationDriver::qt_metacall
+40 (int (*)(...))QAnimationDriver::~QAnimationDriver
+48 (int (*)(...))QAnimationDriver::~QAnimationDriver
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QAnimationDriver::advance
+120 (int (*)(...))QAnimationDriver::elapsed
+128 (int (*)(...))QAnimationDriver::start
+136 (int (*)(...))QAnimationDriver::stop
+
+Class QAnimationDriver
+ size=16 align=8
+ base size=16 base align=8
+QAnimationDriver (0x0x7f234a57d618) 0
+ vptr=((& QAnimationDriver::_ZTV16QAnimationDriver) + 16)
+ QObject (0x0x7f234a5998a0) 0
+ primary-for QAnimationDriver (0x0x7f234a57d618)
+
+Class QEventLoop::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QEventLoop::QPrivateSignal (0x0x7f234a599b40) 0 empty
+
+Vtable for QEventLoop
+QEventLoop::_ZTV10QEventLoop: 14 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI10QEventLoop)
+16 (int (*)(...))QEventLoop::metaObject
+24 (int (*)(...))QEventLoop::qt_metacast
+32 (int (*)(...))QEventLoop::qt_metacall
+40 (int (*)(...))QEventLoop::~QEventLoop
+48 (int (*)(...))QEventLoop::~QEventLoop
+56 (int (*)(...))QEventLoop::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+
+Class QEventLoop
+ size=16 align=8
+ base size=16 base align=8
+QEventLoop (0x0x7f234a57d680) 0
+ vptr=((& QEventLoop::_ZTV10QEventLoop) + 16)
+ QObject (0x0x7f234a599ae0) 0
+ primary-for QEventLoop (0x0x7f234a57d680)
+
+Class QEventLoopLocker
+ size=8 align=8
+ base size=8 base align=8
+QEventLoopLocker (0x0x7f234a5ef420) 0
+
+Class QAbstractEventDispatcher::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QAbstractEventDispatcher::QPrivateSignal (0x0x7f234a5ef4e0) 0 empty
+
+Class QAbstractEventDispatcher::TimerInfo
+ size=12 align=4
+ base size=12 base align=4
+QAbstractEventDispatcher::TimerInfo (0x0x7f234a5ef540) 0
+
+Vtable for QAbstractEventDispatcher
+QAbstractEventDispatcher::_ZTV24QAbstractEventDispatcher: 28 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI24QAbstractEventDispatcher)
+16 (int (*)(...))QAbstractEventDispatcher::metaObject
+24 (int (*)(...))QAbstractEventDispatcher::qt_metacast
+32 (int (*)(...))QAbstractEventDispatcher::qt_metacall
+40 0
+48 0
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))__cxa_pure_virtual
+120 (int (*)(...))__cxa_pure_virtual
+128 (int (*)(...))__cxa_pure_virtual
+136 (int (*)(...))__cxa_pure_virtual
+144 (int (*)(...))__cxa_pure_virtual
+152 (int (*)(...))__cxa_pure_virtual
+160 (int (*)(...))__cxa_pure_virtual
+168 (int (*)(...))__cxa_pure_virtual
+176 (int (*)(...))__cxa_pure_virtual
+184 (int (*)(...))__cxa_pure_virtual
+192 (int (*)(...))__cxa_pure_virtual
+200 (int (*)(...))__cxa_pure_virtual
+208 (int (*)(...))QAbstractEventDispatcher::startingUp
+216 (int (*)(...))QAbstractEventDispatcher::closingDown
+
+Class QAbstractEventDispatcher
+ size=16 align=8
+ base size=16 base align=8
+QAbstractEventDispatcher (0x0x7f234a57d7b8) 0
+ vptr=((& QAbstractEventDispatcher::_ZTV24QAbstractEventDispatcher) + 16)
+ QObject (0x0x7f234a5ef480) 0
+ primary-for QAbstractEventDispatcher (0x0x7f234a57d7b8)
+
+Vtable for std::bad_function_call
+std::bad_function_call::_ZTVSt17bad_function_call: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTISt17bad_function_call)
+16 (int (*)(...))std::bad_function_call::~bad_function_call
+24 (int (*)(...))std::bad_function_call::~bad_function_call
+32 (int (*)(...))std::bad_function_call::what
+
+Class std::bad_function_call
+ size=8 align=8
+ base size=8 base align=8
+std::bad_function_call (0x0x7f234a297138) 0 nearly-empty
+ vptr=((& std::bad_function_call::_ZTVSt17bad_function_call) + 16)
+ std::exception (0x0x7f234a27fba0) 0 nearly-empty
+ primary-for std::bad_function_call (0x0x7f234a297138)
+
+Class std::_Nocopy_types
+ size=16 align=8
+ base size=16 base align=8
+std::_Nocopy_types (0x0x7f234a27fc60) 0
+
+Class std::_Any_data
+ size=16 align=8
+ base size=16 base align=8
+std::_Any_data (0x0x7f234a27fcc0) 0
+
+Class std::_Function_base
+ size=24 align=8
+ base size=24 base align=8
+std::_Function_base (0x0x7f234a2b5000) 0
+
+Class QMapNodeBase
+ size=24 align=8
+ base size=24 base align=8
+QMapNodeBase (0x0x7f234a06bf60) 0
+
+Class QMapDataBase
+ size=40 align=8
+ base size=40 base align=8
+QMapDataBase (0x0x7f234a0b7c00) 0
+
+Class QHashData::Node
+ size=16 align=8
+ base size=16 base align=8
+QHashData::Node (0x0x7f234a1a75a0) 0
+
+Class QHashData
+ size=48 align=8
+ base size=44 base align=8
+QHashData (0x0x7f234a1a7540) 0
+
+Class QHashDummyValue
+ size=1 align=1
+ base size=0 base align=1
+QHashDummyValue (0x0x7f234a1a7840) 0 empty
+
+Class QVariant::PrivateShared
+ size=16 align=8
+ base size=12 base align=8
+QVariant::PrivateShared (0x0x7f2349eafde0) 0
+
+Class QVariant::Private::Data
+ size=8 align=8
+ base size=8 base align=8
+QVariant::Private::Data (0x0x7f2349eafea0) 0
+
+Class QVariant::Private
+ size=16 align=8
+ base size=12 base align=8
+QVariant::Private (0x0x7f2349eafe40) 0
+
+Class QVariant::Handler
+ size=72 align=8
+ base size=72 base align=8
+QVariant::Handler (0x0x7f2349eaff00) 0
+
+Class QVariant
+ size=16 align=8
+ base size=16 base align=8
+QVariant (0x0x7f2349eafd80) 0
+
+Class QVariantComparisonHelper
+ size=8 align=8
+ base size=8 base align=8
+QVariantComparisonHelper (0x0x7f2349c2b1e0) 0
+
+Class QSequentialIterable::const_iterator
+ size=112 align=8
+ base size=112 base align=8
+QSequentialIterable::const_iterator (0x0x7f2349c6d840) 0
+
+Class QSequentialIterable
+ size=104 align=8
+ base size=104 base align=8
+QSequentialIterable (0x0x7f2349c6d7e0) 0
+
+Class QAssociativeIterable::const_iterator
+ size=120 align=8
+ base size=120 base align=8
+QAssociativeIterable::const_iterator (0x0x7f2349c6d960) 0
+
+Class QAssociativeIterable
+ size=112 align=8
+ base size=112 base align=8
+QAssociativeIterable (0x0x7f2349c6d900) 0
+
+Class QModelIndex
+ size=24 align=8
+ base size=24 base align=8
+QModelIndex (0x0x7f2349d37ae0) 0
+
+Class QPersistentModelIndex
+ size=8 align=8
+ base size=8 base align=8
+QPersistentModelIndex (0x0x7f2349daa720) 0
+
+Class QAbstractItemModel::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QAbstractItemModel::QPrivateSignal (0x0x7f2349a7b540) 0 empty
+
+Vtable for QAbstractItemModel
+QAbstractItemModel::_ZTV18QAbstractItemModel: 48 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI18QAbstractItemModel)
+16 (int (*)(...))QAbstractItemModel::metaObject
+24 (int (*)(...))QAbstractItemModel::qt_metacast
+32 (int (*)(...))QAbstractItemModel::qt_metacall
+40 0
+48 0
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))__cxa_pure_virtual
+120 (int (*)(...))__cxa_pure_virtual
+128 (int (*)(...))QAbstractItemModel::sibling
+136 (int (*)(...))__cxa_pure_virtual
+144 (int (*)(...))__cxa_pure_virtual
+152 (int (*)(...))QAbstractItemModel::hasChildren
+160 (int (*)(...))__cxa_pure_virtual
+168 (int (*)(...))QAbstractItemModel::setData
+176 (int (*)(...))QAbstractItemModel::headerData
+184 (int (*)(...))QAbstractItemModel::setHeaderData
+192 (int (*)(...))QAbstractItemModel::itemData
+200 (int (*)(...))QAbstractItemModel::setItemData
+208 (int (*)(...))QAbstractItemModel::mimeTypes
+216 (int (*)(...))QAbstractItemModel::mimeData
+224 (int (*)(...))QAbstractItemModel::canDropMimeData
+232 (int (*)(...))QAbstractItemModel::dropMimeData
+240 (int (*)(...))QAbstractItemModel::supportedDropActions
+248 (int (*)(...))QAbstractItemModel::supportedDragActions
+256 (int (*)(...))QAbstractItemModel::insertRows
+264 (int (*)(...))QAbstractItemModel::insertColumns
+272 (int (*)(...))QAbstractItemModel::removeRows
+280 (int (*)(...))QAbstractItemModel::removeColumns
+288 (int (*)(...))QAbstractItemModel::moveRows
+296 (int (*)(...))QAbstractItemModel::moveColumns
+304 (int (*)(...))QAbstractItemModel::fetchMore
+312 (int (*)(...))QAbstractItemModel::canFetchMore
+320 (int (*)(...))QAbstractItemModel::flags
+328 (int (*)(...))QAbstractItemModel::sort
+336 (int (*)(...))QAbstractItemModel::buddy
+344 (int (*)(...))QAbstractItemModel::match
+352 (int (*)(...))QAbstractItemModel::span
+360 (int (*)(...))QAbstractItemModel::roleNames
+368 (int (*)(...))QAbstractItemModel::submit
+376 (int (*)(...))QAbstractItemModel::revert
+
+Class QAbstractItemModel
+ size=16 align=8
+ base size=16 base align=8
+QAbstractItemModel (0x0x7f2349a6cd00) 0
+ vptr=((& QAbstractItemModel::_ZTV18QAbstractItemModel) + 16)
+ QObject (0x0x7f2349a7b4e0) 0
+ primary-for QAbstractItemModel (0x0x7f2349a6cd00)
+
+Class QAbstractTableModel::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QAbstractTableModel::QPrivateSignal (0x0x7f2349b32900) 0 empty
+
+Vtable for QAbstractTableModel
+QAbstractTableModel::_ZTV19QAbstractTableModel: 48 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI19QAbstractTableModel)
+16 (int (*)(...))QAbstractTableModel::metaObject
+24 (int (*)(...))QAbstractTableModel::qt_metacast
+32 (int (*)(...))QAbstractTableModel::qt_metacall
+40 0
+48 0
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QAbstractTableModel::index
+120 (int (*)(...))QAbstractTableModel::parent
+128 (int (*)(...))QAbstractTableModel::sibling
+136 (int (*)(...))__cxa_pure_virtual
+144 (int (*)(...))__cxa_pure_virtual
+152 (int (*)(...))QAbstractTableModel::hasChildren
+160 (int (*)(...))__cxa_pure_virtual
+168 (int (*)(...))QAbstractItemModel::setData
+176 (int (*)(...))QAbstractItemModel::headerData
+184 (int (*)(...))QAbstractItemModel::setHeaderData
+192 (int (*)(...))QAbstractItemModel::itemData
+200 (int (*)(...))QAbstractItemModel::setItemData
+208 (int (*)(...))QAbstractItemModel::mimeTypes
+216 (int (*)(...))QAbstractItemModel::mimeData
+224 (int (*)(...))QAbstractItemModel::canDropMimeData
+232 (int (*)(...))QAbstractTableModel::dropMimeData
+240 (int (*)(...))QAbstractItemModel::supportedDropActions
+248 (int (*)(...))QAbstractItemModel::supportedDragActions
+256 (int (*)(...))QAbstractItemModel::insertRows
+264 (int (*)(...))QAbstractItemModel::insertColumns
+272 (int (*)(...))QAbstractItemModel::removeRows
+280 (int (*)(...))QAbstractItemModel::removeColumns
+288 (int (*)(...))QAbstractItemModel::moveRows
+296 (int (*)(...))QAbstractItemModel::moveColumns
+304 (int (*)(...))QAbstractItemModel::fetchMore
+312 (int (*)(...))QAbstractItemModel::canFetchMore
+320 (int (*)(...))QAbstractTableModel::flags
+328 (int (*)(...))QAbstractItemModel::sort
+336 (int (*)(...))QAbstractItemModel::buddy
+344 (int (*)(...))QAbstractItemModel::match
+352 (int (*)(...))QAbstractItemModel::span
+360 (int (*)(...))QAbstractItemModel::roleNames
+368 (int (*)(...))QAbstractItemModel::submit
+376 (int (*)(...))QAbstractItemModel::revert
+
+Class QAbstractTableModel
+ size=16 align=8
+ base size=16 base align=8
+QAbstractTableModel (0x0x7f2349ac2340) 0
+ vptr=((& QAbstractTableModel::_ZTV19QAbstractTableModel) + 16)
+ QAbstractItemModel (0x0x7f2349ac23a8) 0
+ primary-for QAbstractTableModel (0x0x7f2349ac2340)
+ QObject (0x0x7f2349b328a0) 0
+ primary-for QAbstractItemModel (0x0x7f2349ac23a8)
+
+Class QAbstractListModel::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QAbstractListModel::QPrivateSignal (0x0x7f2349b32a80) 0 empty
+
+Vtable for QAbstractListModel
+QAbstractListModel::_ZTV18QAbstractListModel: 48 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI18QAbstractListModel)
+16 (int (*)(...))QAbstractListModel::metaObject
+24 (int (*)(...))QAbstractListModel::qt_metacast
+32 (int (*)(...))QAbstractListModel::qt_metacall
+40 0
+48 0
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QAbstractListModel::index
+120 (int (*)(...))QAbstractListModel::parent
+128 (int (*)(...))QAbstractListModel::sibling
+136 (int (*)(...))__cxa_pure_virtual
+144 (int (*)(...))QAbstractListModel::columnCount
+152 (int (*)(...))QAbstractListModel::hasChildren
+160 (int (*)(...))__cxa_pure_virtual
+168 (int (*)(...))QAbstractItemModel::setData
+176 (int (*)(...))QAbstractItemModel::headerData
+184 (int (*)(...))QAbstractItemModel::setHeaderData
+192 (int (*)(...))QAbstractItemModel::itemData
+200 (int (*)(...))QAbstractItemModel::setItemData
+208 (int (*)(...))QAbstractItemModel::mimeTypes
+216 (int (*)(...))QAbstractItemModel::mimeData
+224 (int (*)(...))QAbstractItemModel::canDropMimeData
+232 (int (*)(...))QAbstractListModel::dropMimeData
+240 (int (*)(...))QAbstractItemModel::supportedDropActions
+248 (int (*)(...))QAbstractItemModel::supportedDragActions
+256 (int (*)(...))QAbstractItemModel::insertRows
+264 (int (*)(...))QAbstractItemModel::insertColumns
+272 (int (*)(...))QAbstractItemModel::removeRows
+280 (int (*)(...))QAbstractItemModel::removeColumns
+288 (int (*)(...))QAbstractItemModel::moveRows
+296 (int (*)(...))QAbstractItemModel::moveColumns
+304 (int (*)(...))QAbstractItemModel::fetchMore
+312 (int (*)(...))QAbstractItemModel::canFetchMore
+320 (int (*)(...))QAbstractListModel::flags
+328 (int (*)(...))QAbstractItemModel::sort
+336 (int (*)(...))QAbstractItemModel::buddy
+344 (int (*)(...))QAbstractItemModel::match
+352 (int (*)(...))QAbstractItemModel::span
+360 (int (*)(...))QAbstractItemModel::roleNames
+368 (int (*)(...))QAbstractItemModel::submit
+376 (int (*)(...))QAbstractItemModel::revert
+
+Class QAbstractListModel
+ size=16 align=8
+ base size=16 base align=8
+QAbstractListModel (0x0x7f2349ac2410) 0
+ vptr=((& QAbstractListModel::_ZTV18QAbstractListModel) + 16)
+ QAbstractItemModel (0x0x7f2349ac2478) 0
+ primary-for QAbstractListModel (0x0x7f2349ac2410)
+ QObject (0x0x7f2349b32a20) 0
+ primary-for QAbstractItemModel (0x0x7f2349ac2478)
+
+Vtable for QAbstractNativeEventFilter
+QAbstractNativeEventFilter::_ZTV26QAbstractNativeEventFilter: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI26QAbstractNativeEventFilter)
+16 0
+24 0
+32 (int (*)(...))__cxa_pure_virtual
+
+Class QAbstractNativeEventFilter
+ size=16 align=8
+ base size=16 base align=8
+QAbstractNativeEventFilter (0x0x7f2349b771e0) 0
+ vptr=((& QAbstractNativeEventFilter::_ZTV26QAbstractNativeEventFilter) + 16)
+
+Class QAbstractProxyModel::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QAbstractProxyModel::QPrivateSignal (0x0x7f2349b772a0) 0 empty
+
+Vtable for QAbstractProxyModel
+QAbstractProxyModel::_ZTV19QAbstractProxyModel: 53 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI19QAbstractProxyModel)
+16 (int (*)(...))QAbstractProxyModel::metaObject
+24 (int (*)(...))QAbstractProxyModel::qt_metacast
+32 (int (*)(...))QAbstractProxyModel::qt_metacall
+40 0
+48 0
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))__cxa_pure_virtual
+120 (int (*)(...))__cxa_pure_virtual
+128 (int (*)(...))QAbstractProxyModel::sibling
+136 (int (*)(...))__cxa_pure_virtual
+144 (int (*)(...))__cxa_pure_virtual
+152 (int (*)(...))QAbstractProxyModel::hasChildren
+160 (int (*)(...))QAbstractProxyModel::data
+168 (int (*)(...))QAbstractProxyModel::setData
+176 (int (*)(...))QAbstractProxyModel::headerData
+184 (int (*)(...))QAbstractProxyModel::setHeaderData
+192 (int (*)(...))QAbstractProxyModel::itemData
+200 (int (*)(...))QAbstractProxyModel::setItemData
+208 (int (*)(...))QAbstractProxyModel::mimeTypes
+216 (int (*)(...))QAbstractProxyModel::mimeData
+224 (int (*)(...))QAbstractProxyModel::canDropMimeData
+232 (int (*)(...))QAbstractProxyModel::dropMimeData
+240 (int (*)(...))QAbstractProxyModel::supportedDropActions
+248 (int (*)(...))QAbstractProxyModel::supportedDragActions
+256 (int (*)(...))QAbstractItemModel::insertRows
+264 (int (*)(...))QAbstractItemModel::insertColumns
+272 (int (*)(...))QAbstractItemModel::removeRows
+280 (int (*)(...))QAbstractItemModel::removeColumns
+288 (int (*)(...))QAbstractItemModel::moveRows
+296 (int (*)(...))QAbstractItemModel::moveColumns
+304 (int (*)(...))QAbstractProxyModel::fetchMore
+312 (int (*)(...))QAbstractProxyModel::canFetchMore
+320 (int (*)(...))QAbstractProxyModel::flags
+328 (int (*)(...))QAbstractProxyModel::sort
+336 (int (*)(...))QAbstractProxyModel::buddy
+344 (int (*)(...))QAbstractItemModel::match
+352 (int (*)(...))QAbstractProxyModel::span
+360 (int (*)(...))QAbstractItemModel::roleNames
+368 (int (*)(...))QAbstractProxyModel::submit
+376 (int (*)(...))QAbstractProxyModel::revert
+384 (int (*)(...))QAbstractProxyModel::setSourceModel
+392 (int (*)(...))__cxa_pure_virtual
+400 (int (*)(...))__cxa_pure_virtual
+408 (int (*)(...))QAbstractProxyModel::mapSelectionToSource
+416 (int (*)(...))QAbstractProxyModel::mapSelectionFromSource
+
+Class QAbstractProxyModel
+ size=16 align=8
+ base size=16 base align=8
+QAbstractProxyModel (0x0x7f2349ac2548) 0
+ vptr=((& QAbstractProxyModel::_ZTV19QAbstractProxyModel) + 16)
+ QAbstractItemModel (0x0x7f2349ac25b0) 0
+ primary-for QAbstractProxyModel (0x0x7f2349ac2548)
+ QObject (0x0x7f2349b77240) 0
+ primary-for QAbstractItemModel (0x0x7f2349ac25b0)
+
+Class QAbstractState::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QAbstractState::QPrivateSignal (0x0x7f2349b774e0) 0 empty
+
+Vtable for QAbstractState
+QAbstractState::_ZTV14QAbstractState: 16 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI14QAbstractState)
+16 (int (*)(...))QAbstractState::metaObject
+24 (int (*)(...))QAbstractState::qt_metacast
+32 (int (*)(...))QAbstractState::qt_metacall
+40 0
+48 0
+56 (int (*)(...))QAbstractState::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))__cxa_pure_virtual
+120 (int (*)(...))__cxa_pure_virtual
+
+Class QAbstractState
+ size=16 align=8
+ base size=16 base align=8
+QAbstractState (0x0x7f2349ac2618) 0
+ vptr=((& QAbstractState::_ZTV14QAbstractState) + 16)
+ QObject (0x0x7f2349b77480) 0
+ primary-for QAbstractState (0x0x7f2349ac2618)
+
+Class QAbstractTransition::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QAbstractTransition::QPrivateSignal (0x0x7f2349b77720) 0 empty
+
+Vtable for QAbstractTransition
+QAbstractTransition::_ZTV19QAbstractTransition: 16 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI19QAbstractTransition)
+16 (int (*)(...))QAbstractTransition::metaObject
+24 (int (*)(...))QAbstractTransition::qt_metacast
+32 (int (*)(...))QAbstractTransition::qt_metacall
+40 0
+48 0
+56 (int (*)(...))QAbstractTransition::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))__cxa_pure_virtual
+120 (int (*)(...))__cxa_pure_virtual
+
+Class QAbstractTransition
+ size=16 align=8
+ base size=16 base align=8
+QAbstractTransition (0x0x7f2349ac2680) 0
+ vptr=((& QAbstractTransition::_ZTV19QAbstractTransition) + 16)
+ QObject (0x0x7f2349b776c0) 0
+ primary-for QAbstractTransition (0x0x7f2349ac2680)
+
+Class QAnimationGroup::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QAnimationGroup::QPrivateSignal (0x0x7f2349b77a20) 0 empty
+
+Vtable for QAnimationGroup
+QAnimationGroup::_ZTV15QAnimationGroup: 18 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI15QAnimationGroup)
+16 (int (*)(...))QAnimationGroup::metaObject
+24 (int (*)(...))QAnimationGroup::qt_metacast
+32 (int (*)(...))QAnimationGroup::qt_metacall
+40 0
+48 0
+56 (int (*)(...))QAnimationGroup::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))__cxa_pure_virtual
+120 (int (*)(...))__cxa_pure_virtual
+128 (int (*)(...))QAbstractAnimation::updateState
+136 (int (*)(...))QAbstractAnimation::updateDirection
+
+Class QAnimationGroup
+ size=16 align=8
+ base size=16 base align=8
+QAnimationGroup (0x0x7f2349ac26e8) 0
+ vptr=((& QAnimationGroup::_ZTV15QAnimationGroup) + 16)
+ QAbstractAnimation (0x0x7f2349ac2750) 0
+ primary-for QAnimationGroup (0x0x7f2349ac26e8)
+ QObject (0x0x7f2349b779c0) 0
+ primary-for QAbstractAnimation (0x0x7f2349ac2750)
+
+Class QBasicTimer
+ size=4 align=4
+ base size=4 base align=4
+QBasicTimer (0x0x7f234981fd80) 0
+
+Class QBitArray
+ size=8 align=8
+ base size=8 base align=8
+QBitArray (0x0x7f234987d180) 0
+
+Class QBitRef
+ size=16 align=8
+ base size=12 base align=8
+QBitRef (0x0x7f23498de600) 0
+
+Class QIODevice::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QIODevice::QPrivateSignal (0x0x7f23499289c0) 0 empty
+
+Vtable for QIODevice
+QIODevice::_ZTV9QIODevice: 30 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI9QIODevice)
+16 (int (*)(...))QIODevice::metaObject
+24 (int (*)(...))QIODevice::qt_metacast
+32 (int (*)(...))QIODevice::qt_metacall
+40 0
+48 0
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QIODevice::isSequential
+120 (int (*)(...))QIODevice::open
+128 (int (*)(...))QIODevice::close
+136 (int (*)(...))QIODevice::pos
+144 (int (*)(...))QIODevice::size
+152 (int (*)(...))QIODevice::seek
+160 (int (*)(...))QIODevice::atEnd
+168 (int (*)(...))QIODevice::reset
+176 (int (*)(...))QIODevice::bytesAvailable
+184 (int (*)(...))QIODevice::bytesToWrite
+192 (int (*)(...))QIODevice::canReadLine
+200 (int (*)(...))QIODevice::waitForReadyRead
+208 (int (*)(...))QIODevice::waitForBytesWritten
+216 (int (*)(...))__cxa_pure_virtual
+224 (int (*)(...))QIODevice::readLineData
+232 (int (*)(...))__cxa_pure_virtual
+
+Class QIODevice
+ size=16 align=8
+ base size=16 base align=8
+QIODevice (0x0x7f2349921c98) 0
+ vptr=((& QIODevice::_ZTV9QIODevice) + 16)
+ QObject (0x0x7f2349928960) 0
+ primary-for QIODevice (0x0x7f2349921c98)
+
+Class QBuffer::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QBuffer::QPrivateSignal (0x0x7f2349973360) 0 empty
+
+Vtable for QBuffer
+QBuffer::_ZTV7QBuffer: 30 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI7QBuffer)
+16 (int (*)(...))QBuffer::metaObject
+24 (int (*)(...))QBuffer::qt_metacast
+32 (int (*)(...))QBuffer::qt_metacall
+40 (int (*)(...))QBuffer::~QBuffer
+48 (int (*)(...))QBuffer::~QBuffer
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QBuffer::connectNotify
+104 (int (*)(...))QBuffer::disconnectNotify
+112 (int (*)(...))QIODevice::isSequential
+120 (int (*)(...))QBuffer::open
+128 (int (*)(...))QBuffer::close
+136 (int (*)(...))QBuffer::pos
+144 (int (*)(...))QBuffer::size
+152 (int (*)(...))QBuffer::seek
+160 (int (*)(...))QBuffer::atEnd
+168 (int (*)(...))QIODevice::reset
+176 (int (*)(...))QIODevice::bytesAvailable
+184 (int (*)(...))QIODevice::bytesToWrite
+192 (int (*)(...))QBuffer::canReadLine
+200 (int (*)(...))QIODevice::waitForReadyRead
+208 (int (*)(...))QIODevice::waitForBytesWritten
+216 (int (*)(...))QBuffer::readData
+224 (int (*)(...))QIODevice::readLineData
+232 (int (*)(...))QBuffer::writeData
+
+Class QBuffer
+ size=16 align=8
+ base size=16 base align=8
+QBuffer (0x0x7f2349921dd0) 0
+ vptr=((& QBuffer::_ZTV7QBuffer) + 16)
+ QIODevice (0x0x7f2349921e38) 0
+ primary-for QBuffer (0x0x7f2349921dd0)
+ QObject (0x0x7f2349973300) 0
+ primary-for QIODevice (0x0x7f2349921e38)
+
+Class QByteArrayMatcher::Data
+ size=272 align=8
+ base size=272 base align=8
+QByteArrayMatcher::Data (0x0x7f2349973600) 0
+
+Class QByteArrayMatcher
+ size=1040 align=8
+ base size=1040 base align=8
+QByteArrayMatcher (0x0x7f23499735a0) 0
+
+Class QStaticByteArrayMatcherBase::Skiptable
+ size=256 align=1
+ base size=256 base align=1
+QStaticByteArrayMatcherBase::Skiptable (0x0x7f2349973780) 0
+
+Class QStaticByteArrayMatcherBase
+ size=256 align=16
+ base size=256 base align=16
+QStaticByteArrayMatcherBase (0x0x7f2349973720) 0
+
+Class QSharedData
+ size=4 align=4
+ base size=4 base align=4
+QSharedData (0x0x7f23499bf660) 0
+
+Class QDate
+ size=8 align=8
+ base size=8 base align=8
+QDate (0x0x7f2349a00600) 0
+
+Class QTime
+ size=4 align=4
+ base size=4 base align=4
+QTime (0x0x7f2349656ea0) 0
+
+Class QDateTime::ShortData
+ size=8 align=8
+ base size=8 base align=8
+QDateTime::ShortData (0x0x7f23496bfb40) 0
+
+Class QDateTime::Data
+ size=8 align=8
+ base size=8 base align=8
+QDateTime::Data (0x0x7f23496bfba0) 0
+
+Class QDateTime
+ size=8 align=8
+ base size=8 base align=8
+QDateTime (0x0x7f23496bfae0) 0
+
+Class QLocale
+ size=8 align=8
+ base size=8 base align=8
+QLocale (0x0x7f23497b12a0) 0
+
+Vtable for QTextStream
+QTextStream::_ZTV11QTextStream: 4 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI11QTextStream)
+16 (int (*)(...))QTextStream::~QTextStream
+24 (int (*)(...))QTextStream::~QTextStream
+
+Class QTextStream
+ size=16 align=8
+ base size=16 base align=8
+QTextStream (0x0x7f23494ad840) 0
+ vptr=((& QTextStream::_ZTV11QTextStream) + 16)
+
+Class QTextStreamManipulator
+ size=40 align=8
+ base size=38 base align=8
+QTextStreamManipulator (0x0x7f2349514120) 0
+
+Class QContiguousCacheData
+ size=24 align=4
+ base size=24 base align=4
+QContiguousCacheData (0x0x7f2349587c00) 0
+
+Class QtSharedPointer::NormalDeleter
+ size=1 align=1
+ base size=0 base align=1
+QtSharedPointer::NormalDeleter (0x0x7f23495d28a0) 0 empty
+
+Class QtSharedPointer::ExternalRefCountData
+ size=16 align=8
+ base size=16 base align=8
+QtSharedPointer::ExternalRefCountData (0x0x7f23495d2a20) 0
+
+Class QDebug::Stream
+ size=80 align=8
+ base size=76 base align=8
+QDebug::Stream (0x0x7f234928d660) 0
+
+Class QDebug
+ size=8 align=8
+ base size=8 base align=8
+QDebug (0x0x7f234928d600) 0
+
+Class QDebugStateSaver
+ size=8 align=8
+ base size=8 base align=8
+QDebugStateSaver (0x0x7f234902e6c0) 0
+
+Class QNoDebug
+ size=1 align=1
+ base size=0 base align=1
+QNoDebug (0x0x7f234902e780) 0 empty
+
+Class QCborError
+ size=4 align=4
+ base size=4 base align=4
+QCborError (0x0x7f23490ada80) 0
+
+Class QRegularExpression
+ size=8 align=8
+ base size=8 base align=8
+QRegularExpression (0x0x7f23490e0240) 0
+
+Class QRegularExpressionMatch
+ size=8 align=8
+ base size=8 base align=8
+QRegularExpressionMatch (0x0x7f2349191120) 0
+
+Class QRegularExpressionMatchIterator
+ size=8 align=8
+ base size=8 base align=8
+QRegularExpressionMatchIterator (0x0x7f23491ceea0) 0
+
+Class QUrl
+ size=8 align=8
+ base size=8 base align=8
+QUrl (0x0x7f2348e51900) 0
+
+Class QUuid
+ size=16 align=4
+ base size=16 base align=4
+QUuid (0x0x7f2348f948a0) 0
+
+Class QCborParserError
+ size=16 align=8
+ base size=12 base align=8
+QCborParserError (0x0x7f2348c1c420) 0
+
+Class QCborValue
+ size=24 align=8
+ base size=20 base align=8
+QCborValue (0x0x7f2348c1c4e0) 0
+
+Class QCborValueRef
+ size=16 align=8
+ base size=16 base align=8
+QCborValueRef (0x0x7f2348a954e0) 0
+
+Class QCborArray::Iterator
+ size=16 align=8
+ base size=16 base align=8
+QCborArray::Iterator (0x0x7f2348b02f00) 0
+
+Class QCborArray::ConstIterator
+ size=16 align=8
+ base size=16 base align=8
+QCborArray::ConstIterator (0x0x7f2348b02f60) 0
+
+Class QCborArray
+ size=8 align=8
+ base size=8 base align=8
+QCborArray (0x0x7f2348b02ea0) 0
+
+Class QCborMap::Iterator
+ size=16 align=8
+ base size=16 base align=8
+QCborMap::Iterator (0x0x7f234881c960) 0
+
+Class QCborMap::ConstIterator
+ size=16 align=8
+ base size=16 base align=8
+QCborMap::ConstIterator (0x0x7f234881c9c0) 0
+
+Class QCborMap
+ size=8 align=8
+ base size=8 base align=8
+QCborMap (0x0x7f234881c900) 0
+
+Class qfloat16
+ size=2 align=2
+ base size=2 base align=2
+qfloat16 (0x0x7f234862e120) 0
+
+Class QCborStreamWriter
+ size=8 align=8
+ base size=8 base align=8
+QCborStreamWriter (0x0x7f23486f00c0) 0
+
+Class QCborStreamReader
+ size=24 align=8
+ base size=20 base align=8
+QCborStreamReader (0x0x7f23486f0de0) 0
+
+Class QCollatorSortKey
+ size=8 align=8
+ base size=8 base align=8
+QCollatorSortKey (0x0x7f2348786f00) 0
+
+Class QCollator
+ size=8 align=8
+ base size=8 base align=8
+QCollator (0x0x7f23487b0120) 0
+
+Class QCommandLineOption
+ size=8 align=8
+ base size=8 base align=8
+QCommandLineOption (0x0x7f234849c6c0) 0
+
+Vtable for QEvent
+QEvent::_ZTV6QEvent: 4 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI6QEvent)
+16 (int (*)(...))QEvent::~QEvent
+24 (int (*)(...))QEvent::~QEvent
+
+Class QEvent
+ size=24 align=8
+ base size=20 base align=8
+QEvent (0x0x7f23484f3de0) 0
+ vptr=((& QEvent::_ZTV6QEvent) + 16)
+
+Vtable for QTimerEvent
+QTimerEvent::_ZTV11QTimerEvent: 4 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI11QTimerEvent)
+16 (int (*)(...))QTimerEvent::~QTimerEvent
+24 (int (*)(...))QTimerEvent::~QTimerEvent
+
+Class QTimerEvent
+ size=24 align=8
+ base size=24 base align=8
+QTimerEvent (0x0x7f234853b000) 0
+ vptr=((& QTimerEvent::_ZTV11QTimerEvent) + 16)
+ QEvent (0x0x7f23485371e0) 0
+ primary-for QTimerEvent (0x0x7f234853b000)
+
+Vtable for QChildEvent
+QChildEvent::_ZTV11QChildEvent: 4 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI11QChildEvent)
+16 (int (*)(...))QChildEvent::~QChildEvent
+24 (int (*)(...))QChildEvent::~QChildEvent
+
+Class QChildEvent
+ size=32 align=8
+ base size=32 base align=8
+QChildEvent (0x0x7f234853b068) 0
+ vptr=((& QChildEvent::_ZTV11QChildEvent) + 16)
+ QEvent (0x0x7f23485372a0) 0
+ primary-for QChildEvent (0x0x7f234853b068)
+
+Vtable for QDynamicPropertyChangeEvent
+QDynamicPropertyChangeEvent::_ZTV27QDynamicPropertyChangeEvent: 4 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI27QDynamicPropertyChangeEvent)
+16 (int (*)(...))QDynamicPropertyChangeEvent::~QDynamicPropertyChangeEvent
+24 (int (*)(...))QDynamicPropertyChangeEvent::~QDynamicPropertyChangeEvent
+
+Class QDynamicPropertyChangeEvent
+ size=32 align=8
+ base size=32 base align=8
+QDynamicPropertyChangeEvent (0x0x7f234853b5b0) 0
+ vptr=((& QDynamicPropertyChangeEvent::_ZTV27QDynamicPropertyChangeEvent) + 16)
+ QEvent (0x0x7f2348537900) 0
+ primary-for QDynamicPropertyChangeEvent (0x0x7f234853b5b0)
+
+Vtable for QDeferredDeleteEvent
+QDeferredDeleteEvent::_ZTV20QDeferredDeleteEvent: 4 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI20QDeferredDeleteEvent)
+16 (int (*)(...))QDeferredDeleteEvent::~QDeferredDeleteEvent
+24 (int (*)(...))QDeferredDeleteEvent::~QDeferredDeleteEvent
+
+Class QDeferredDeleteEvent
+ size=24 align=8
+ base size=24 base align=8
+QDeferredDeleteEvent (0x0x7f234853b618) 0
+ vptr=((& QDeferredDeleteEvent::_ZTV20QDeferredDeleteEvent) + 16)
+ QEvent (0x0x7f23485379c0) 0
+ primary-for QDeferredDeleteEvent (0x0x7f234853b618)
+
+Class QCoreApplication::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QCoreApplication::QPrivateSignal (0x0x7f2348537ae0) 0 empty
+
+Vtable for QCoreApplication
+QCoreApplication::_ZTV16QCoreApplication: 16 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI16QCoreApplication)
+16 (int (*)(...))QCoreApplication::metaObject
+24 (int (*)(...))QCoreApplication::qt_metacast
+32 (int (*)(...))QCoreApplication::qt_metacall
+40 (int (*)(...))QCoreApplication::~QCoreApplication
+48 (int (*)(...))QCoreApplication::~QCoreApplication
+56 (int (*)(...))QCoreApplication::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QCoreApplication::notify
+120 (int (*)(...))QCoreApplication::compressEvent
+
+Class QCoreApplication
+ size=16 align=8
+ base size=16 base align=8
+QCoreApplication (0x0x7f234853b680) 0
+ vptr=((& QCoreApplication::_ZTV16QCoreApplication) + 16)
+ QObject (0x0x7f2348537a80) 0
+ primary-for QCoreApplication (0x0x7f234853b680)
+
+Class QCommandLineParser
+ size=8 align=8
+ base size=8 base align=8
+QCommandLineParser (0x0x7f2348537d20) 0
+
+Class QConcatenateTablesProxyModel::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QConcatenateTablesProxyModel::QPrivateSignal (0x0x7f2348537ea0) 0 empty
+
+Vtable for QConcatenateTablesProxyModel
+QConcatenateTablesProxyModel::_ZTV28QConcatenateTablesProxyModel: 48 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI28QConcatenateTablesProxyModel)
+16 (int (*)(...))QConcatenateTablesProxyModel::metaObject
+24 (int (*)(...))QConcatenateTablesProxyModel::qt_metacast
+32 (int (*)(...))QConcatenateTablesProxyModel::qt_metacall
+40 (int (*)(...))QConcatenateTablesProxyModel::~QConcatenateTablesProxyModel
+48 (int (*)(...))QConcatenateTablesProxyModel::~QConcatenateTablesProxyModel
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QConcatenateTablesProxyModel::index
+120 (int (*)(...))QConcatenateTablesProxyModel::parent
+128 (int (*)(...))QAbstractItemModel::sibling
+136 (int (*)(...))QConcatenateTablesProxyModel::rowCount
+144 (int (*)(...))QConcatenateTablesProxyModel::columnCount
+152 (int (*)(...))QAbstractItemModel::hasChildren
+160 (int (*)(...))QConcatenateTablesProxyModel::data
+168 (int (*)(...))QConcatenateTablesProxyModel::setData
+176 (int (*)(...))QConcatenateTablesProxyModel::headerData
+184 (int (*)(...))QAbstractItemModel::setHeaderData
+192 (int (*)(...))QConcatenateTablesProxyModel::itemData
+200 (int (*)(...))QConcatenateTablesProxyModel::setItemData
+208 (int (*)(...))QConcatenateTablesProxyModel::mimeTypes
+216 (int (*)(...))QConcatenateTablesProxyModel::mimeData
+224 (int (*)(...))QConcatenateTablesProxyModel::canDropMimeData
+232 (int (*)(...))QConcatenateTablesProxyModel::dropMimeData
+240 (int (*)(...))QAbstractItemModel::supportedDropActions
+248 (int (*)(...))QAbstractItemModel::supportedDragActions
+256 (int (*)(...))QAbstractItemModel::insertRows
+264 (int (*)(...))QAbstractItemModel::insertColumns
+272 (int (*)(...))QAbstractItemModel::removeRows
+280 (int (*)(...))QAbstractItemModel::removeColumns
+288 (int (*)(...))QAbstractItemModel::moveRows
+296 (int (*)(...))QAbstractItemModel::moveColumns
+304 (int (*)(...))QAbstractItemModel::fetchMore
+312 (int (*)(...))QAbstractItemModel::canFetchMore
+320 (int (*)(...))QConcatenateTablesProxyModel::flags
+328 (int (*)(...))QAbstractItemModel::sort
+336 (int (*)(...))QAbstractItemModel::buddy
+344 (int (*)(...))QAbstractItemModel::match
+352 (int (*)(...))QConcatenateTablesProxyModel::span
+360 (int (*)(...))QAbstractItemModel::roleNames
+368 (int (*)(...))QAbstractItemModel::submit
+376 (int (*)(...))QAbstractItemModel::revert
+
+Class QConcatenateTablesProxyModel
+ size=16 align=8
+ base size=16 base align=8
+QConcatenateTablesProxyModel (0x0x7f234853b6e8) 0
+ vptr=((& QConcatenateTablesProxyModel::_ZTV28QConcatenateTablesProxyModel) + 16)
+ QAbstractItemModel (0x0x7f234853b750) 0
+ primary-for QConcatenateTablesProxyModel (0x0x7f234853b6e8)
+ QObject (0x0x7f2348537e40) 0
+ primary-for QAbstractItemModel (0x0x7f234853b750)
+
+Class QCryptographicHash
+ size=8 align=8
+ base size=8 base align=8
+QCryptographicHash (0x0x7f234859d0c0) 0
+
+Class QDataStream
+ size=32 align=8
+ base size=32 base align=8
+QDataStream (0x0x7f234859d1e0) 0
+
+Class QtPrivate::StreamStateSaver
+ size=16 align=8
+ base size=12 base align=8
+QtPrivate::StreamStateSaver (0x0x7f234859d360) 0
+
+Class QElapsedTimer
+ size=16 align=8
+ base size=16 base align=8
+QElapsedTimer (0x0x7f23485f9a80) 0
+
+Class QDeadlineTimer
+ size=16 align=8
+ base size=16 base align=8
+QDeadlineTimer (0x0x7f234822b1e0) 0
+
+Class QFileDevice::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QFileDevice::QPrivateSignal (0x0x7f2348349f00) 0 empty
+
+Vtable for QFileDevice
+QFileDevice::_ZTV11QFileDevice: 34 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI11QFileDevice)
+16 (int (*)(...))QFileDevice::metaObject
+24 (int (*)(...))QFileDevice::qt_metacast
+32 (int (*)(...))QFileDevice::qt_metacall
+40 (int (*)(...))QFileDevice::~QFileDevice
+48 (int (*)(...))QFileDevice::~QFileDevice
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QFileDevice::isSequential
+120 (int (*)(...))QIODevice::open
+128 (int (*)(...))QFileDevice::close
+136 (int (*)(...))QFileDevice::pos
+144 (int (*)(...))QFileDevice::size
+152 (int (*)(...))QFileDevice::seek
+160 (int (*)(...))QFileDevice::atEnd
+168 (int (*)(...))QIODevice::reset
+176 (int (*)(...))QIODevice::bytesAvailable
+184 (int (*)(...))QIODevice::bytesToWrite
+192 (int (*)(...))QIODevice::canReadLine
+200 (int (*)(...))QIODevice::waitForReadyRead
+208 (int (*)(...))QIODevice::waitForBytesWritten
+216 (int (*)(...))QFileDevice::readData
+224 (int (*)(...))QFileDevice::readLineData
+232 (int (*)(...))QFileDevice::writeData
+240 (int (*)(...))QFileDevice::fileName
+248 (int (*)(...))QFileDevice::resize
+256 (int (*)(...))QFileDevice::permissions
+264 (int (*)(...))QFileDevice::setPermissions
+
+Class QFileDevice
+ size=16 align=8
+ base size=16 base align=8
+QFileDevice (0x0x7f2348353958) 0
+ vptr=((& QFileDevice::_ZTV11QFileDevice) + 16)
+ QIODevice (0x0x7f23483539c0) 0
+ primary-for QFileDevice (0x0x7f2348353958)
+ QObject (0x0x7f2348349ea0) 0
+ primary-for QIODevice (0x0x7f23483539c0)
+
+Class QFile::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QFile::QPrivateSignal (0x0x7f2348380840) 0 empty
+
+Vtable for QFile
+QFile::_ZTV5QFile: 34 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI5QFile)
+16 (int (*)(...))QFile::metaObject
+24 (int (*)(...))QFile::qt_metacast
+32 (int (*)(...))QFile::qt_metacall
+40 (int (*)(...))QFile::~QFile
+48 (int (*)(...))QFile::~QFile
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QFileDevice::isSequential
+120 (int (*)(...))QFile::open
+128 (int (*)(...))QFileDevice::close
+136 (int (*)(...))QFileDevice::pos
+144 (int (*)(...))QFile::size
+152 (int (*)(...))QFileDevice::seek
+160 (int (*)(...))QFileDevice::atEnd
+168 (int (*)(...))QIODevice::reset
+176 (int (*)(...))QIODevice::bytesAvailable
+184 (int (*)(...))QIODevice::bytesToWrite
+192 (int (*)(...))QIODevice::canReadLine
+200 (int (*)(...))QIODevice::waitForReadyRead
+208 (int (*)(...))QIODevice::waitForBytesWritten
+216 (int (*)(...))QFileDevice::readData
+224 (int (*)(...))QFileDevice::readLineData
+232 (int (*)(...))QFileDevice::writeData
+240 (int (*)(...))QFile::fileName
+248 (int (*)(...))QFile::resize
+256 (int (*)(...))QFile::permissions
+264 (int (*)(...))QFile::setPermissions
+
+Class QFile
+ size=16 align=8
+ base size=16 base align=8
+QFile (0x0x7f2348353af8) 0
+ vptr=((& QFile::_ZTV5QFile) + 16)
+ QFileDevice (0x0x7f2348353b60) 0
+ primary-for QFile (0x0x7f2348353af8)
+ QIODevice (0x0x7f2348353bc8) 0
+ primary-for QFileDevice (0x0x7f2348353b60)
+ QObject (0x0x7f23483807e0) 0
+ primary-for QIODevice (0x0x7f2348353bc8)
+
+Class QFileInfo
+ size=8 align=8
+ base size=8 base align=8
+QFileInfo (0x0x7f2348380ea0) 0
+
+Class QDir
+ size=8 align=8
+ base size=8 base align=8
+QDir (0x0x7f23480352a0) 0
+
+Class QDirIterator
+ size=8 align=8
+ base size=8 base align=8
+QDirIterator (0x0x7f23480df600) 0
+
+Class QEasingCurve
+ size=8 align=8
+ base size=8 base align=8
+QEasingCurve (0x0x7f23480dfd80) 0
+
+Class QEventTransition::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QEventTransition::QPrivateSignal (0x0x7f2347dd6ea0) 0 empty
+
+Vtable for QEventTransition
+QEventTransition::_ZTV16QEventTransition: 16 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI16QEventTransition)
+16 (int (*)(...))QEventTransition::metaObject
+24 (int (*)(...))QEventTransition::qt_metacast
+32 (int (*)(...))QEventTransition::qt_metacall
+40 (int (*)(...))QEventTransition::~QEventTransition
+48 (int (*)(...))QEventTransition::~QEventTransition
+56 (int (*)(...))QEventTransition::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QEventTransition::eventTest
+120 (int (*)(...))QEventTransition::onTransition
+
+Class QEventTransition
+ size=16 align=8
+ base size=16 base align=8
+QEventTransition (0x0x7f23481e0e38) 0
+ vptr=((& QEventTransition::_ZTV16QEventTransition) + 16)
+ QAbstractTransition (0x0x7f23481e0ea0) 0
+ primary-for QEventTransition (0x0x7f23481e0e38)
+ QObject (0x0x7f2347dd6e40) 0
+ primary-for QAbstractTransition (0x0x7f23481e0ea0)
+
+Vtable for QException
+QException::_ZTV10QException: 7 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI10QException)
+16 (int (*)(...))QException::~QException
+24 (int (*)(...))QException::~QException
+32 (int (*)(...))std::exception::what
+40 (int (*)(...))QException::raise
+48 (int (*)(...))QException::clone
+
+Class QException
+ size=8 align=8
+ base size=8 base align=8
+QException (0x0x7f23481e0f08) 0 nearly-empty
+ vptr=((& QException::_ZTV10QException) + 16)
+ std::exception (0x0x7f2347e0e0c0) 0 nearly-empty
+ primary-for QException (0x0x7f23481e0f08)
+
+Vtable for QUnhandledException
+QUnhandledException::_ZTV19QUnhandledException: 7 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI19QUnhandledException)
+16 (int (*)(...))QUnhandledException::~QUnhandledException
+24 (int (*)(...))QUnhandledException::~QUnhandledException
+32 (int (*)(...))std::exception::what
+40 (int (*)(...))QUnhandledException::raise
+48 (int (*)(...))QUnhandledException::clone
+
+Class QUnhandledException
+ size=8 align=8
+ base size=8 base align=8
+QUnhandledException (0x0x7f23481e0f70) 0 nearly-empty
+ vptr=((& QUnhandledException::_ZTV19QUnhandledException) + 16)
+ QException (0x0x7f2347e13000) 0 nearly-empty
+ primary-for QUnhandledException (0x0x7f23481e0f70)
+ std::exception (0x0x7f2347e0e120) 0 nearly-empty
+ primary-for QException (0x0x7f2347e13000)
+
+Class QtPrivate::ExceptionHolder
+ size=8 align=8
+ base size=8 base align=8
+QtPrivate::ExceptionHolder (0x0x7f2347e0e180) 0
+
+Class QtPrivate::ExceptionStore
+ size=8 align=8
+ base size=8 base align=8
+QtPrivate::ExceptionStore (0x0x7f2347e0e240) 0
+
+Vtable for QFactoryInterface
+QFactoryInterface::_ZTV17QFactoryInterface: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI17QFactoryInterface)
+16 0
+24 0
+32 (int (*)(...))__cxa_pure_virtual
+
+Class QFactoryInterface
+ size=8 align=8
+ base size=8 base align=8
+QFactoryInterface (0x0x7f2347e0e2a0) 0 nearly-empty
+ vptr=((& QFactoryInterface::_ZTV17QFactoryInterface) + 16)
+
+Class QFileSelector::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QFileSelector::QPrivateSignal (0x0x7f2347e0e4e0) 0 empty
+
+Vtable for QFileSelector
+QFileSelector::_ZTV13QFileSelector: 14 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI13QFileSelector)
+16 (int (*)(...))QFileSelector::metaObject
+24 (int (*)(...))QFileSelector::qt_metacast
+32 (int (*)(...))QFileSelector::qt_metacall
+40 (int (*)(...))QFileSelector::~QFileSelector
+48 (int (*)(...))QFileSelector::~QFileSelector
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+
+Class QFileSelector
+ size=16 align=8
+ base size=16 base align=8
+QFileSelector (0x0x7f2347e13068) 0
+ vptr=((& QFileSelector::_ZTV13QFileSelector) + 16)
+ QObject (0x0x7f2347e0e480) 0
+ primary-for QFileSelector (0x0x7f2347e13068)
+
+Class QFileSystemWatcher::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QFileSystemWatcher::QPrivateSignal (0x0x7f2347e0e720) 0 empty
+
+Vtable for QFileSystemWatcher
+QFileSystemWatcher::_ZTV18QFileSystemWatcher: 14 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI18QFileSystemWatcher)
+16 (int (*)(...))QFileSystemWatcher::metaObject
+24 (int (*)(...))QFileSystemWatcher::qt_metacast
+32 (int (*)(...))QFileSystemWatcher::qt_metacall
+40 (int (*)(...))QFileSystemWatcher::~QFileSystemWatcher
+48 (int (*)(...))QFileSystemWatcher::~QFileSystemWatcher
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+
+Class QFileSystemWatcher
+ size=16 align=8
+ base size=16 base align=8
+QFileSystemWatcher (0x0x7f2347e130d0) 0
+ vptr=((& QFileSystemWatcher::_ZTV18QFileSystemWatcher) + 16)
+ QObject (0x0x7f2347e0e6c0) 0
+ primary-for QFileSystemWatcher (0x0x7f2347e130d0)
+
+Class QFinalState::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QFinalState::QPrivateSignal (0x0x7f2347e0e960) 0 empty
+
+Vtable for QFinalState
+QFinalState::_ZTV11QFinalState: 16 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI11QFinalState)
+16 (int (*)(...))QFinalState::metaObject
+24 (int (*)(...))QFinalState::qt_metacast
+32 (int (*)(...))QFinalState::qt_metacall
+40 (int (*)(...))QFinalState::~QFinalState
+48 (int (*)(...))QFinalState::~QFinalState
+56 (int (*)(...))QFinalState::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QFinalState::onEntry
+120 (int (*)(...))QFinalState::onExit
+
+Class QFinalState
+ size=16 align=8
+ base size=16 base align=8
+QFinalState (0x0x7f2347e13138) 0
+ vptr=((& QFinalState::_ZTV11QFinalState) + 16)
+ QAbstractState (0x0x7f2347e131a0) 0
+ primary-for QFinalState (0x0x7f2347e13138)
+ QObject (0x0x7f2347e0e900) 0
+ primary-for QAbstractState (0x0x7f2347e131a0)
+
+Vtable for QRunnable
+QRunnable::_ZTV9QRunnable: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI9QRunnable)
+16 (int (*)(...))__cxa_pure_virtual
+24 0
+32 0
+
+Class QRunnable
+ size=16 align=8
+ base size=12 base align=8
+QRunnable (0x0x7f2347e0eb40) 0
+ vptr=((& QRunnable::_ZTV9QRunnable) + 16)
+
+Class QBasicMutex
+ size=8 align=8
+ base size=8 base align=8
+QBasicMutex (0x0x7f2347e0ede0) 0
+
+Class QMutex
+ size=8 align=8
+ base size=8 base align=8
+QMutex (0x0x7f2347e13270) 0
+ QBasicMutex (0x0x7f2347ebea80) 0
+
+Class QMutexLocker
+ size=8 align=8
+ base size=8 base align=8
+QMutexLocker (0x0x7f2347ebecc0) 0
+
+Class QtPrivate::ResultItem
+ size=16 align=8
+ base size=16 base align=8
+QtPrivate::ResultItem (0x0x7f2347ee2180) 0
+
+Class QtPrivate::ResultIteratorBase
+ size=16 align=8
+ base size=12 base align=8
+QtPrivate::ResultIteratorBase (0x0x7f2347ee2780) 0
+
+Vtable for QtPrivate::ResultStoreBase
+QtPrivate::ResultStoreBase::_ZTVN9QtPrivate15ResultStoreBaseE: 4 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTIN9QtPrivate15ResultStoreBaseE)
+16 (int (*)(...))QtPrivate::ResultStoreBase::~ResultStoreBase
+24 (int (*)(...))QtPrivate::ResultStoreBase::~ResultStoreBase
+
+Class QtPrivate::ResultStoreBase
+ size=48 align=8
+ base size=44 base align=8
+QtPrivate::ResultStoreBase (0x0x7f2347ee2960) 0
+ vptr=((& QtPrivate::ResultStoreBase::_ZTVN9QtPrivate15ResultStoreBaseE) + 16)
+
+Vtable for QFutureInterfaceBase
+QFutureInterfaceBase::_ZTV20QFutureInterfaceBase: 4 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI20QFutureInterfaceBase)
+16 (int (*)(...))QFutureInterfaceBase::~QFutureInterfaceBase
+24 (int (*)(...))QFutureInterfaceBase::~QFutureInterfaceBase
+
+Class QFutureInterfaceBase
+ size=16 align=8
+ base size=16 base align=8
+QFutureInterfaceBase (0x0x7f2347f6f180) 0
+ vptr=((& QFutureInterfaceBase::_ZTV20QFutureInterfaceBase) + 16)
+
+Class QFutureWatcherBase::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QFutureWatcherBase::QPrivateSignal (0x0x7f2347c1b480) 0 empty
+
+Vtable for QFutureWatcherBase
+QFutureWatcherBase::_ZTV18QFutureWatcherBase: 16 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI18QFutureWatcherBase)
+16 (int (*)(...))QFutureWatcherBase::metaObject
+24 (int (*)(...))QFutureWatcherBase::qt_metacast
+32 (int (*)(...))QFutureWatcherBase::qt_metacall
+40 0
+48 0
+56 (int (*)(...))QFutureWatcherBase::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QFutureWatcherBase::connectNotify
+104 (int (*)(...))QFutureWatcherBase::disconnectNotify
+112 (int (*)(...))__cxa_pure_virtual
+120 (int (*)(...))__cxa_pure_virtual
+
+Class QFutureWatcherBase
+ size=16 align=8
+ base size=16 base align=8
+QFutureWatcherBase (0x0x7f2347fa4888) 0
+ vptr=((& QFutureWatcherBase::_ZTV18QFutureWatcherBase) + 16)
+ QObject (0x0x7f2347c1b420) 0
+ primary-for QFutureWatcherBase (0x0x7f2347fa4888)
+
+Class QHistoryState::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QHistoryState::QPrivateSignal (0x0x7f2347c437e0) 0 empty
+
+Vtable for QHistoryState
+QHistoryState::_ZTV13QHistoryState: 16 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI13QHistoryState)
+16 (int (*)(...))QHistoryState::metaObject
+24 (int (*)(...))QHistoryState::qt_metacast
+32 (int (*)(...))QHistoryState::qt_metacall
+40 (int (*)(...))QHistoryState::~QHistoryState
+48 (int (*)(...))QHistoryState::~QHistoryState
+56 (int (*)(...))QHistoryState::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QHistoryState::onEntry
+120 (int (*)(...))QHistoryState::onExit
+
+Class QHistoryState
+ size=16 align=8
+ base size=16 base align=8
+QHistoryState (0x0x7f2347c4d0d0) 0
+ vptr=((& QHistoryState::_ZTV13QHistoryState) + 16)
+ QAbstractState (0x0x7f2347c4d138) 0
+ primary-for QHistoryState (0x0x7f2347c4d0d0)
+ QObject (0x0x7f2347c43780) 0
+ primary-for QAbstractState (0x0x7f2347c4d138)
+
+Class QIdentityProxyModel::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QIdentityProxyModel::QPrivateSignal (0x0x7f2347c43ae0) 0 empty
+
+Vtable for QIdentityProxyModel
+QIdentityProxyModel::_ZTV19QIdentityProxyModel: 53 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI19QIdentityProxyModel)
+16 (int (*)(...))QIdentityProxyModel::metaObject
+24 (int (*)(...))QIdentityProxyModel::qt_metacast
+32 (int (*)(...))QIdentityProxyModel::qt_metacall
+40 (int (*)(...))QIdentityProxyModel::~QIdentityProxyModel
+48 (int (*)(...))QIdentityProxyModel::~QIdentityProxyModel
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QIdentityProxyModel::index
+120 (int (*)(...))QIdentityProxyModel::parent
+128 (int (*)(...))QIdentityProxyModel::sibling
+136 (int (*)(...))QIdentityProxyModel::rowCount
+144 (int (*)(...))QIdentityProxyModel::columnCount
+152 (int (*)(...))QAbstractProxyModel::hasChildren
+160 (int (*)(...))QAbstractProxyModel::data
+168 (int (*)(...))QAbstractProxyModel::setData
+176 (int (*)(...))QIdentityProxyModel::headerData
+184 (int (*)(...))QAbstractProxyModel::setHeaderData
+192 (int (*)(...))QAbstractProxyModel::itemData
+200 (int (*)(...))QAbstractProxyModel::setItemData
+208 (int (*)(...))QAbstractProxyModel::mimeTypes
+216 (int (*)(...))QAbstractProxyModel::mimeData
+224 (int (*)(...))QAbstractProxyModel::canDropMimeData
+232 (int (*)(...))QIdentityProxyModel::dropMimeData
+240 (int (*)(...))QAbstractProxyModel::supportedDropActions
+248 (int (*)(...))QAbstractProxyModel::supportedDragActions
+256 (int (*)(...))QIdentityProxyModel::insertRows
+264 (int (*)(...))QIdentityProxyModel::insertColumns
+272 (int (*)(...))QIdentityProxyModel::removeRows
+280 (int (*)(...))QIdentityProxyModel::removeColumns
+288 (int (*)(...))QAbstractItemModel::moveRows
+296 (int (*)(...))QAbstractItemModel::moveColumns
+304 (int (*)(...))QAbstractProxyModel::fetchMore
+312 (int (*)(...))QAbstractProxyModel::canFetchMore
+320 (int (*)(...))QAbstractProxyModel::flags
+328 (int (*)(...))QAbstractProxyModel::sort
+336 (int (*)(...))QAbstractProxyModel::buddy
+344 (int (*)(...))QIdentityProxyModel::match
+352 (int (*)(...))QAbstractProxyModel::span
+360 (int (*)(...))QAbstractItemModel::roleNames
+368 (int (*)(...))QAbstractProxyModel::submit
+376 (int (*)(...))QAbstractProxyModel::revert
+384 (int (*)(...))QIdentityProxyModel::setSourceModel
+392 (int (*)(...))QIdentityProxyModel::mapToSource
+400 (int (*)(...))QIdentityProxyModel::mapFromSource
+408 (int (*)(...))QIdentityProxyModel::mapSelectionToSource
+416 (int (*)(...))QIdentityProxyModel::mapSelectionFromSource
+
+Class QIdentityProxyModel
+ size=16 align=8
+ base size=16 base align=8
+QIdentityProxyModel (0x0x7f2347c4d1a0) 0
+ vptr=((& QIdentityProxyModel::_ZTV19QIdentityProxyModel) + 16)
+ QAbstractProxyModel (0x0x7f2347c4d208) 0
+ primary-for QIdentityProxyModel (0x0x7f2347c4d1a0)
+ QAbstractItemModel (0x0x7f2347c4d270) 0
+ primary-for QAbstractProxyModel (0x0x7f2347c4d208)
+ QObject (0x0x7f2347c43a80) 0
+ primary-for QAbstractItemModel (0x0x7f2347c4d270)
+
+Class QItemSelectionRange
+ size=16 align=8
+ base size=16 base align=8
+QItemSelectionRange (0x0x7f2347c43cc0) 0
+
+Class QItemSelectionModel::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QItemSelectionModel::QPrivateSignal (0x0x7f2347d2b600) 0 empty
+
+Vtable for QItemSelectionModel
+QItemSelectionModel::_ZTV19QItemSelectionModel: 20 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI19QItemSelectionModel)
+16 (int (*)(...))QItemSelectionModel::metaObject
+24 (int (*)(...))QItemSelectionModel::qt_metacast
+32 (int (*)(...))QItemSelectionModel::qt_metacall
+40 (int (*)(...))QItemSelectionModel::~QItemSelectionModel
+48 (int (*)(...))QItemSelectionModel::~QItemSelectionModel
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QItemSelectionModel::setCurrentIndex
+120 (int (*)(...))QItemSelectionModel::select
+128 (int (*)(...))QItemSelectionModel::select
+136 (int (*)(...))QItemSelectionModel::clear
+144 (int (*)(...))QItemSelectionModel::reset
+152 (int (*)(...))QItemSelectionModel::clearCurrentIndex
+
+Class QItemSelectionModel
+ size=16 align=8
+ base size=16 base align=8
+QItemSelectionModel (0x0x7f2347d20bc8) 0
+ vptr=((& QItemSelectionModel::_ZTV19QItemSelectionModel) + 16)
+ QObject (0x0x7f2347d2b5a0) 0
+ primary-for QItemSelectionModel (0x0x7f2347d20bc8)
+
+Class QItemSelection
+ size=8 align=8
+ base size=8 base align=8
+QItemSelection (0x0x7f2347d20d68) 0
+ QList<QItemSelectionRange> (0x0x7f2347d20dd0) 0
+ QListSpecialMethods<QItemSelectionRange> (0x0x7f2347d73120) 0 empty
+
+Class QJsonValue
+ size=24 align=8
+ base size=20 base align=8
+QJsonValue (0x0x7f23479d7a20) 0
+
+Class QJsonValueRef
+ size=16 align=8
+ base size=12 base align=8
+QJsonValueRef (0x0x7f2347b29c00) 0
+
+Class QJsonValuePtr
+ size=24 align=8
+ base size=24 base align=8
+QJsonValuePtr (0x0x7f2347b62ba0) 0
+
+Class QJsonValueRefPtr
+ size=16 align=8
+ base size=16 base align=8
+QJsonValueRefPtr (0x0x7f2347b62e40) 0
+
+Class QJsonArray::iterator
+ size=16 align=8
+ base size=12 base align=8
+QJsonArray::iterator (0x0x7f23477db1e0) 0
+
+Class QJsonArray::const_iterator
+ size=16 align=8
+ base size=12 base align=8
+QJsonArray::const_iterator (0x0x7f23477db240) 0
+
+Class QJsonArray
+ size=16 align=8
+ base size=16 base align=8
+QJsonArray (0x0x7f23477db180) 0
+
+Class QJsonParseError
+ size=8 align=4
+ base size=8 base align=4
+QJsonParseError (0x0x7f2347907120) 0
+
+Class QJsonDocument
+ size=8 align=8
+ base size=8 base align=8
+QJsonDocument (0x0x7f2347907180) 0
+
+Class QJsonObject::iterator
+ size=16 align=8
+ base size=12 base align=8
+QJsonObject::iterator (0x0x7f234795c960) 0
+
+Class QJsonObject::const_iterator
+ size=16 align=8
+ base size=12 base align=8
+QJsonObject::const_iterator (0x0x7f234795c9c0) 0
+
+Class QJsonObject
+ size=16 align=8
+ base size=16 base align=8
+QJsonObject (0x0x7f234795c900) 0
+
+Class QLibrary::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QLibrary::QPrivateSignal (0x0x7f234766bd20) 0 empty
+
+Vtable for QLibrary
+QLibrary::_ZTV8QLibrary: 14 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI8QLibrary)
+16 (int (*)(...))QLibrary::metaObject
+24 (int (*)(...))QLibrary::qt_metacast
+32 (int (*)(...))QLibrary::qt_metacall
+40 (int (*)(...))QLibrary::~QLibrary
+48 (int (*)(...))QLibrary::~QLibrary
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+
+Class QLibrary
+ size=32 align=8
+ base size=25 base align=8
+QLibrary (0x0x7f234766ae38) 0
+ vptr=((& QLibrary::_ZTV8QLibrary) + 16)
+ QObject (0x0x7f234766bcc0) 0
+ primary-for QLibrary (0x0x7f234766ae38)
+
+Class QVersionNumber::SegmentStorage
+ size=8 align=8
+ base size=8 base align=8
+QVersionNumber::SegmentStorage (0x0x7f234769dba0) 0
+
+Class QVersionNumber
+ size=8 align=8
+ base size=8 base align=8
+QVersionNumber (0x0x7f234769d6c0) 0
+
+Class QLibraryInfo
+ size=1 align=1
+ base size=0 base align=1
+QLibraryInfo (0x0x7f234776e300) 0 empty
+
+Class QPoint
+ size=8 align=4
+ base size=8 base align=4
+QPoint (0x0x7f234776e360) 0
+
+Class QPointF
+ size=16 align=8
+ base size=16 base align=8
+QPointF (0x0x7f23473e3180) 0
+
+Class QLine
+ size=16 align=4
+ base size=16 base align=4
+QLine (0x0x7f2347456300) 0
+
+Class QLineF
+ size=32 align=8
+ base size=32 base align=8
+QLineF (0x0x7f23474be6c0) 0
+
+Class QLinkedListData
+ size=32 align=8
+ base size=25 base align=8
+QLinkedListData (0x0x7f2347539960) 0
+
+Class QLockFile
+ size=8 align=8
+ base size=8 base align=8
+QLockFile (0x0x7f23471dcae0) 0
+
+Class QLoggingCategory::AtomicBools
+ size=4 align=1
+ base size=4 base align=1
+QLoggingCategory::AtomicBools (0x0x7f23471dcd20) 0
+
+Class QLoggingCategory
+ size=24 align=8
+ base size=24 base align=8
+QLoggingCategory (0x0x7f23471dccc0) 0
+
+Class QMargins
+ size=16 align=4
+ base size=16 base align=4
+QMargins (0x0x7f234724b180) 0
+
+Class QMarginsF
+ size=32 align=8
+ base size=32 base align=8
+QMarginsF (0x0x7f23472c70c0) 0
+
+Class QMessageAuthenticationCode
+ size=8 align=8
+ base size=8 base align=8
+QMessageAuthenticationCode (0x0x7f234707a8a0) 0
+
+Class QMetaMethod
+ size=16 align=8
+ base size=12 base align=8
+QMetaMethod (0x0x7f234707a900) 0
+
+Class QMetaEnum
+ size=16 align=8
+ base size=12 base align=8
+QMetaEnum (0x0x7f2347105180) 0
+
+Class QMetaProperty
+ size=32 align=8
+ base size=32 base align=8
+QMetaProperty (0x0x7f2346d483c0) 0
+
+Class QMetaClassInfo
+ size=16 align=8
+ base size=12 base align=8
+QMetaClassInfo (0x0x7f2346d484e0) 0
+
+Class QMimeData::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QMimeData::QPrivateSignal (0x0x7f2346d88a80) 0 empty
+
+Vtable for QMimeData
+QMimeData::_ZTV9QMimeData: 17 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI9QMimeData)
+16 (int (*)(...))QMimeData::metaObject
+24 (int (*)(...))QMimeData::qt_metacast
+32 (int (*)(...))QMimeData::qt_metacall
+40 (int (*)(...))QMimeData::~QMimeData
+48 (int (*)(...))QMimeData::~QMimeData
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QMimeData::hasFormat
+120 (int (*)(...))QMimeData::formats
+128 (int (*)(...))QMimeData::retrieveData
+
+Class QMimeData
+ size=16 align=8
+ base size=16 base align=8
+QMimeData (0x0x7f2346d8ca90) 0
+ vptr=((& QMimeData::_ZTV9QMimeData) + 16)
+ QObject (0x0x7f2346d88a20) 0
+ primary-for QMimeData (0x0x7f2346d8ca90)
+
+Class QMimeType
+ size=8 align=8
+ base size=8 base align=8
+QMimeType (0x0x7f2346d88c60) 0
+
+Class QMimeDatabase
+ size=8 align=8
+ base size=8 base align=8
+QMimeDatabase (0x0x7f2346de2d80) 0
+
+Class QObjectCleanupHandler::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QObjectCleanupHandler::QPrivateSignal (0x0x7f2346de2e40) 0 empty
+
+Vtable for QObjectCleanupHandler
+QObjectCleanupHandler::_ZTV21QObjectCleanupHandler: 14 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI21QObjectCleanupHandler)
+16 (int (*)(...))QObjectCleanupHandler::metaObject
+24 (int (*)(...))QObjectCleanupHandler::qt_metacast
+32 (int (*)(...))QObjectCleanupHandler::qt_metacall
+40 (int (*)(...))QObjectCleanupHandler::~QObjectCleanupHandler
+48 (int (*)(...))QObjectCleanupHandler::~QObjectCleanupHandler
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+
+Class QObjectCleanupHandler
+ size=24 align=8
+ base size=24 base align=8
+QObjectCleanupHandler (0x0x7f2346de8dd0) 0
+ vptr=((& QObjectCleanupHandler::_ZTV21QObjectCleanupHandler) + 16)
+ QObject (0x0x7f2346de2de0) 0
+ primary-for QObjectCleanupHandler (0x0x7f2346de8dd0)
+
+Class QOperatingSystemVersion
+ size=16 align=4
+ base size=16 base align=4
+QOperatingSystemVersion (0x0x7f2346de2f60) 0
+
+Class QParallelAnimationGroup::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QParallelAnimationGroup::QPrivateSignal (0x0x7f2346e71720) 0 empty
+
+Vtable for QParallelAnimationGroup
+QParallelAnimationGroup::_ZTV23QParallelAnimationGroup: 18 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI23QParallelAnimationGroup)
+16 (int (*)(...))QParallelAnimationGroup::metaObject
+24 (int (*)(...))QParallelAnimationGroup::qt_metacast
+32 (int (*)(...))QParallelAnimationGroup::qt_metacall
+40 (int (*)(...))QParallelAnimationGroup::~QParallelAnimationGroup
+48 (int (*)(...))QParallelAnimationGroup::~QParallelAnimationGroup
+56 (int (*)(...))QParallelAnimationGroup::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QParallelAnimationGroup::duration
+120 (int (*)(...))QParallelAnimationGroup::updateCurrentTime
+128 (int (*)(...))QParallelAnimationGroup::updateState
+136 (int (*)(...))QParallelAnimationGroup::updateDirection
+
+Class QParallelAnimationGroup
+ size=16 align=8
+ base size=16 base align=8
+QParallelAnimationGroup (0x0x7f2346e75680) 0
+ vptr=((& QParallelAnimationGroup::_ZTV23QParallelAnimationGroup) + 16)
+ QAnimationGroup (0x0x7f2346e756e8) 0
+ primary-for QParallelAnimationGroup (0x0x7f2346e75680)
+ QAbstractAnimation (0x0x7f2346e75750) 0
+ primary-for QAnimationGroup (0x0x7f2346e756e8)
+ QObject (0x0x7f2346e716c0) 0
+ primary-for QAbstractAnimation (0x0x7f2346e75750)
+
+Class QPauseAnimation::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QPauseAnimation::QPrivateSignal (0x0x7f2346e71960) 0 empty
+
+Vtable for QPauseAnimation
+QPauseAnimation::_ZTV15QPauseAnimation: 18 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI15QPauseAnimation)
+16 (int (*)(...))QPauseAnimation::metaObject
+24 (int (*)(...))QPauseAnimation::qt_metacast
+32 (int (*)(...))QPauseAnimation::qt_metacall
+40 (int (*)(...))QPauseAnimation::~QPauseAnimation
+48 (int (*)(...))QPauseAnimation::~QPauseAnimation
+56 (int (*)(...))QPauseAnimation::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QPauseAnimation::duration
+120 (int (*)(...))QPauseAnimation::updateCurrentTime
+128 (int (*)(...))QAbstractAnimation::updateState
+136 (int (*)(...))QAbstractAnimation::updateDirection
+
+Class QPauseAnimation
+ size=16 align=8
+ base size=16 base align=8
+QPauseAnimation (0x0x7f2346e757b8) 0
+ vptr=((& QPauseAnimation::_ZTV15QPauseAnimation) + 16)
+ QAbstractAnimation (0x0x7f2346e75820) 0
+ primary-for QPauseAnimation (0x0x7f2346e757b8)
+ QObject (0x0x7f2346e71900) 0
+ primary-for QAbstractAnimation (0x0x7f2346e75820)
+
+Class QStaticPlugin
+ size=16 align=8
+ base size=16 base align=8
+QStaticPlugin (0x0x7f2346ea35a0) 0
+
+Class QPluginLoader::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QPluginLoader::QPrivateSignal (0x0x7f2346eea720) 0 empty
+
+Vtable for QPluginLoader
+QPluginLoader::_ZTV13QPluginLoader: 14 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI13QPluginLoader)
+16 (int (*)(...))QPluginLoader::metaObject
+24 (int (*)(...))QPluginLoader::qt_metacast
+32 (int (*)(...))QPluginLoader::qt_metacall
+40 (int (*)(...))QPluginLoader::~QPluginLoader
+48 (int (*)(...))QPluginLoader::~QPluginLoader
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+
+Class QPluginLoader
+ size=32 align=8
+ base size=25 base align=8
+QPluginLoader (0x0x7f2346edeb60) 0
+ vptr=((& QPluginLoader::_ZTV13QPluginLoader) + 16)
+ QObject (0x0x7f2346eea6c0) 0
+ primary-for QPluginLoader (0x0x7f2346edeb60)
+
+Class QProcessEnvironment
+ size=8 align=8
+ base size=8 base align=8
+QProcessEnvironment (0x0x7f2346eea840) 0
+
+Class QProcess::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QProcess::QPrivateSignal (0x0x7f2346b45ea0) 0 empty
+
+Vtable for QProcess
+QProcess::_ZTV8QProcess: 31 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI8QProcess)
+16 (int (*)(...))QProcess::metaObject
+24 (int (*)(...))QProcess::qt_metacast
+32 (int (*)(...))QProcess::qt_metacall
+40 (int (*)(...))QProcess::~QProcess
+48 (int (*)(...))QProcess::~QProcess
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QProcess::isSequential
+120 (int (*)(...))QProcess::open
+128 (int (*)(...))QProcess::close
+136 (int (*)(...))QIODevice::pos
+144 (int (*)(...))QIODevice::size
+152 (int (*)(...))QIODevice::seek
+160 (int (*)(...))QProcess::atEnd
+168 (int (*)(...))QIODevice::reset
+176 (int (*)(...))QProcess::bytesAvailable
+184 (int (*)(...))QProcess::bytesToWrite
+192 (int (*)(...))QProcess::canReadLine
+200 (int (*)(...))QProcess::waitForReadyRead
+208 (int (*)(...))QProcess::waitForBytesWritten
+216 (int (*)(...))QProcess::readData
+224 (int (*)(...))QIODevice::readLineData
+232 (int (*)(...))QProcess::writeData
+240 (int (*)(...))QProcess::setupChildProcess
+
+Class QProcess
+ size=16 align=8
+ base size=16 base align=8
+QProcess (0x0x7f2346b4f7b8) 0
+ vptr=((& QProcess::_ZTV8QProcess) + 16)
+ QIODevice (0x0x7f2346b4f820) 0
+ primary-for QProcess (0x0x7f2346b4f7b8)
+ QObject (0x0x7f2346b45e40) 0
+ primary-for QIODevice (0x0x7f2346b4f820)
+
+Class QVariantAnimation::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QVariantAnimation::QPrivateSignal (0x0x7f2346b885a0) 0 empty
+
+Vtable for QVariantAnimation
+QVariantAnimation::_ZTV17QVariantAnimation: 20 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI17QVariantAnimation)
+16 (int (*)(...))QVariantAnimation::metaObject
+24 (int (*)(...))QVariantAnimation::qt_metacast
+32 (int (*)(...))QVariantAnimation::qt_metacall
+40 (int (*)(...))QVariantAnimation::~QVariantAnimation
+48 (int (*)(...))QVariantAnimation::~QVariantAnimation
+56 (int (*)(...))QVariantAnimation::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QVariantAnimation::duration
+120 (int (*)(...))QVariantAnimation::updateCurrentTime
+128 (int (*)(...))QVariantAnimation::updateState
+136 (int (*)(...))QAbstractAnimation::updateDirection
+144 (int (*)(...))QVariantAnimation::updateCurrentValue
+152 (int (*)(...))QVariantAnimation::interpolated
+
+Class QVariantAnimation
+ size=16 align=8
+ base size=16 base align=8
+QVariantAnimation (0x0x7f2346b4f888) 0
+ vptr=((& QVariantAnimation::_ZTV17QVariantAnimation) + 16)
+ QAbstractAnimation (0x0x7f2346b4f8f0) 0
+ primary-for QVariantAnimation (0x0x7f2346b4f888)
+ QObject (0x0x7f2346b88540) 0
+ primary-for QAbstractAnimation (0x0x7f2346b4f8f0)
+
+Class QPropertyAnimation::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QPropertyAnimation::QPrivateSignal (0x0x7f2346b88840) 0 empty
+
+Vtable for QPropertyAnimation
+QPropertyAnimation::_ZTV18QPropertyAnimation: 20 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI18QPropertyAnimation)
+16 (int (*)(...))QPropertyAnimation::metaObject
+24 (int (*)(...))QPropertyAnimation::qt_metacast
+32 (int (*)(...))QPropertyAnimation::qt_metacall
+40 (int (*)(...))QPropertyAnimation::~QPropertyAnimation
+48 (int (*)(...))QPropertyAnimation::~QPropertyAnimation
+56 (int (*)(...))QPropertyAnimation::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QVariantAnimation::duration
+120 (int (*)(...))QVariantAnimation::updateCurrentTime
+128 (int (*)(...))QPropertyAnimation::updateState
+136 (int (*)(...))QAbstractAnimation::updateDirection
+144 (int (*)(...))QPropertyAnimation::updateCurrentValue
+152 (int (*)(...))QVariantAnimation::interpolated
+
+Class QPropertyAnimation
+ size=16 align=8
+ base size=16 base align=8
+QPropertyAnimation (0x0x7f2346b4f9c0) 0
+ vptr=((& QPropertyAnimation::_ZTV18QPropertyAnimation) + 16)
+ QVariantAnimation (0x0x7f2346b4fa28) 0
+ primary-for QPropertyAnimation (0x0x7f2346b4f9c0)
+ QAbstractAnimation (0x0x7f2346b4fa90) 0
+ primary-for QVariantAnimation (0x0x7f2346b4fa28)
+ QObject (0x0x7f2346b887e0) 0
+ primary-for QAbstractAnimation (0x0x7f2346b4fa90)
+
+Class std::random_device
+ size=5000 align=8
+ base size=5000 base align=8
+std::random_device (0x0x7f2346c07f60) 0
+
+Class std::bernoulli_distribution::param_type
+ size=8 align=8
+ base size=8 base align=8
+std::bernoulli_distribution::param_type (0x0x7f2346d07cc0) 0
+
+Class std::bernoulli_distribution
+ size=8 align=8
+ base size=8 base align=8
+std::bernoulli_distribution (0x0x7f2346d07c60) 0
+
+Class std::seed_seq
+ size=24 align=8
+ base size=24 base align=8
+std::seed_seq (0x0x7f2346b06a20) 0
+
+Class QRandomGenerator::Storage
+ size=2504 align=8
+ base size=2504 base align=8
+QRandomGenerator::Storage (0x0x7f23469316c0) 0
+
+Class QRandomGenerator
+ size=2512 align=8
+ base size=2512 base align=8
+QRandomGenerator (0x0x7f2346931660) 0
+
+Class QRandomGenerator64
+ size=2512 align=8
+ base size=2512 base align=8
+QRandomGenerator64 (0x0x7f234652e750) 0
+ QRandomGenerator (0x0x7f23465531e0) 0
+
+Class QReadWriteLock
+ size=8 align=8
+ base size=8 base align=8
+QReadWriteLock (0x0x7f2346553d80) 0
+
+Class QReadLocker
+ size=8 align=8
+ base size=8 base align=8
+QReadLocker (0x0x7f23465d9060) 0
+
+Class QWriteLocker
+ size=8 align=8
+ base size=8 base align=8
+QWriteLocker (0x0x7f23465d9540) 0
+
+Class QSize
+ size=8 align=4
+ base size=8 base align=4
+QSize (0x0x7f23465d9a20) 0
+
+Class QSizeF
+ size=16 align=8
+ base size=16 base align=8
+QSizeF (0x0x7f2346648840) 0
+
+Class QRect
+ size=16 align=4
+ base size=16 base align=4
+QRect (0x0x7f23466bf7e0) 0
+
+Class QRectF
+ size=32 align=8
+ base size=32 base align=8
+QRectF (0x0x7f2346372840) 0
+
+Class QResource
+ size=8 align=8
+ base size=8 base align=8
+QResource (0x0x7f2346432960) 0
+
+Class QSaveFile::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QSaveFile::QPrivateSignal (0x0x7f2346432c00) 0 empty
+
+Vtable for QSaveFile
+QSaveFile::_ZTV9QSaveFile: 34 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI9QSaveFile)
+16 (int (*)(...))QSaveFile::metaObject
+24 (int (*)(...))QSaveFile::qt_metacast
+32 (int (*)(...))QSaveFile::qt_metacall
+40 (int (*)(...))QSaveFile::~QSaveFile
+48 (int (*)(...))QSaveFile::~QSaveFile
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QFileDevice::isSequential
+120 (int (*)(...))QSaveFile::open
+128 (int (*)(...))QSaveFile::close
+136 (int (*)(...))QFileDevice::pos
+144 (int (*)(...))QFileDevice::size
+152 (int (*)(...))QFileDevice::seek
+160 (int (*)(...))QFileDevice::atEnd
+168 (int (*)(...))QIODevice::reset
+176 (int (*)(...))QIODevice::bytesAvailable
+184 (int (*)(...))QIODevice::bytesToWrite
+192 (int (*)(...))QIODevice::canReadLine
+200 (int (*)(...))QIODevice::waitForReadyRead
+208 (int (*)(...))QIODevice::waitForBytesWritten
+216 (int (*)(...))QFileDevice::readData
+224 (int (*)(...))QFileDevice::readLineData
+232 (int (*)(...))QSaveFile::writeData
+240 (int (*)(...))QSaveFile::fileName
+248 (int (*)(...))QFileDevice::resize
+256 (int (*)(...))QFileDevice::permissions
+264 (int (*)(...))QFileDevice::setPermissions
+
+Class QSaveFile
+ size=16 align=8
+ base size=16 base align=8
+QSaveFile (0x0x7f23463fc138) 0
+ vptr=((& QSaveFile::_ZTV9QSaveFile) + 16)
+ QFileDevice (0x0x7f23463fc1a0) 0
+ primary-for QSaveFile (0x0x7f23463fc138)
+ QIODevice (0x0x7f23463fc208) 0
+ primary-for QFileDevice (0x0x7f23463fc1a0)
+ QObject (0x0x7f2346432ba0) 0
+ primary-for QIODevice (0x0x7f23463fc208)
+
+Class QSemaphore
+ size=8 align=8
+ base size=8 base align=8
+QSemaphore (0x0x7f2346489240) 0
+
+Class QSemaphoreReleaser
+ size=16 align=8
+ base size=12 base align=8
+QSemaphoreReleaser (0x0x7f23464893c0) 0
+
+Class QSequentialAnimationGroup::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QSequentialAnimationGroup::QPrivateSignal (0x0x7f2346196660) 0 empty
+
+Vtable for QSequentialAnimationGroup
+QSequentialAnimationGroup::_ZTV25QSequentialAnimationGroup: 18 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI25QSequentialAnimationGroup)
+16 (int (*)(...))QSequentialAnimationGroup::metaObject
+24 (int (*)(...))QSequentialAnimationGroup::qt_metacast
+32 (int (*)(...))QSequentialAnimationGroup::qt_metacall
+40 (int (*)(...))QSequentialAnimationGroup::~QSequentialAnimationGroup
+48 (int (*)(...))QSequentialAnimationGroup::~QSequentialAnimationGroup
+56 (int (*)(...))QSequentialAnimationGroup::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QSequentialAnimationGroup::duration
+120 (int (*)(...))QSequentialAnimationGroup::updateCurrentTime
+128 (int (*)(...))QSequentialAnimationGroup::updateState
+136 (int (*)(...))QSequentialAnimationGroup::updateDirection
+
+Class QSequentialAnimationGroup
+ size=16 align=8
+ base size=16 base align=8
+QSequentialAnimationGroup (0x0x7f2346190f08) 0
+ vptr=((& QSequentialAnimationGroup::_ZTV25QSequentialAnimationGroup) + 16)
+ QAnimationGroup (0x0x7f2346190f70) 0
+ primary-for QSequentialAnimationGroup (0x0x7f2346190f08)
+ QAbstractAnimation (0x0x7f234619e000) 0
+ primary-for QAnimationGroup (0x0x7f2346190f70)
+ QObject (0x0x7f2346196600) 0
+ primary-for QAbstractAnimation (0x0x7f234619e000)
+
+Class QSettings::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QSettings::QPrivateSignal (0x0x7f23461968a0) 0 empty
+
+Vtable for QSettings
+QSettings::_ZTV9QSettings: 14 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI9QSettings)
+16 (int (*)(...))QSettings::metaObject
+24 (int (*)(...))QSettings::qt_metacast
+32 (int (*)(...))QSettings::qt_metacall
+40 (int (*)(...))QSettings::~QSettings
+48 (int (*)(...))QSettings::~QSettings
+56 (int (*)(...))QSettings::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+
+Class QSettings
+ size=16 align=8
+ base size=16 base align=8
+QSettings (0x0x7f234619e068) 0
+ vptr=((& QSettings::_ZTV9QSettings) + 16)
+ QObject (0x0x7f2346196840) 0
+ primary-for QSettings (0x0x7f234619e068)
+
+Class QSharedMemory::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QSharedMemory::QPrivateSignal (0x0x7f2346196d20) 0 empty
+
+Vtable for QSharedMemory
+QSharedMemory::_ZTV13QSharedMemory: 14 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI13QSharedMemory)
+16 (int (*)(...))QSharedMemory::metaObject
+24 (int (*)(...))QSharedMemory::qt_metacast
+32 (int (*)(...))QSharedMemory::qt_metacall
+40 (int (*)(...))QSharedMemory::~QSharedMemory
+48 (int (*)(...))QSharedMemory::~QSharedMemory
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+
+Class QSharedMemory
+ size=16 align=8
+ base size=16 base align=8
+QSharedMemory (0x0x7f234619e0d0) 0
+ vptr=((& QSharedMemory::_ZTV13QSharedMemory) + 16)
+ QObject (0x0x7f2346196cc0) 0
+ primary-for QSharedMemory (0x0x7f234619e0d0)
+
+Class QSignalMapper::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QSignalMapper::QPrivateSignal (0x0x7f2346196f60) 0 empty
+
+Vtable for QSignalMapper
+QSignalMapper::_ZTV13QSignalMapper: 14 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI13QSignalMapper)
+16 (int (*)(...))QSignalMapper::metaObject
+24 (int (*)(...))QSignalMapper::qt_metacast
+32 (int (*)(...))QSignalMapper::qt_metacall
+40 (int (*)(...))QSignalMapper::~QSignalMapper
+48 (int (*)(...))QSignalMapper::~QSignalMapper
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+
+Class QSignalMapper
+ size=16 align=8
+ base size=16 base align=8
+QSignalMapper (0x0x7f234619e138) 0
+ vptr=((& QSignalMapper::_ZTV13QSignalMapper) + 16)
+ QObject (0x0x7f2346196f00) 0
+ primary-for QSignalMapper (0x0x7f234619e138)
+
+Class QSignalTransition::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QSignalTransition::QPrivateSignal (0x0x7f23461ee1e0) 0 empty
+
+Vtable for QSignalTransition
+QSignalTransition::_ZTV17QSignalTransition: 16 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI17QSignalTransition)
+16 (int (*)(...))QSignalTransition::metaObject
+24 (int (*)(...))QSignalTransition::qt_metacast
+32 (int (*)(...))QSignalTransition::qt_metacall
+40 (int (*)(...))QSignalTransition::~QSignalTransition
+48 (int (*)(...))QSignalTransition::~QSignalTransition
+56 (int (*)(...))QSignalTransition::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QSignalTransition::eventTest
+120 (int (*)(...))QSignalTransition::onTransition
+
+Class QSignalTransition
+ size=16 align=8
+ base size=16 base align=8
+QSignalTransition (0x0x7f234619e1a0) 0
+ vptr=((& QSignalTransition::_ZTV17QSignalTransition) + 16)
+ QAbstractTransition (0x0x7f234619e208) 0
+ primary-for QSignalTransition (0x0x7f234619e1a0)
+ QObject (0x0x7f23461ee180) 0
+ primary-for QAbstractTransition (0x0x7f234619e208)
+
+Class QSocketNotifier::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QSocketNotifier::QPrivateSignal (0x0x7f23461ee480) 0 empty
+
+Vtable for QSocketNotifier
+QSocketNotifier::_ZTV15QSocketNotifier: 14 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI15QSocketNotifier)
+16 (int (*)(...))QSocketNotifier::metaObject
+24 (int (*)(...))QSocketNotifier::qt_metacast
+32 (int (*)(...))QSocketNotifier::qt_metacall
+40 (int (*)(...))QSocketNotifier::~QSocketNotifier
+48 (int (*)(...))QSocketNotifier::~QSocketNotifier
+56 (int (*)(...))QSocketNotifier::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+
+Class QSocketNotifier
+ size=16 align=8
+ base size=16 base align=8
+QSocketNotifier (0x0x7f234619e270) 0
+ vptr=((& QSocketNotifier::_ZTV15QSocketNotifier) + 16)
+ QObject (0x0x7f23461ee420) 0
+ primary-for QSocketNotifier (0x0x7f234619e270)
+
+Class QSortFilterProxyModel::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QSortFilterProxyModel::QPrivateSignal (0x0x7f23461ee6c0) 0 empty
+
+Vtable for QSortFilterProxyModel
+QSortFilterProxyModel::_ZTV21QSortFilterProxyModel: 56 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI21QSortFilterProxyModel)
+16 (int (*)(...))QSortFilterProxyModel::metaObject
+24 (int (*)(...))QSortFilterProxyModel::qt_metacast
+32 (int (*)(...))QSortFilterProxyModel::qt_metacall
+40 (int (*)(...))QSortFilterProxyModel::~QSortFilterProxyModel
+48 (int (*)(...))QSortFilterProxyModel::~QSortFilterProxyModel
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QSortFilterProxyModel::index
+120 (int (*)(...))QSortFilterProxyModel::parent
+128 (int (*)(...))QSortFilterProxyModel::sibling
+136 (int (*)(...))QSortFilterProxyModel::rowCount
+144 (int (*)(...))QSortFilterProxyModel::columnCount
+152 (int (*)(...))QSortFilterProxyModel::hasChildren
+160 (int (*)(...))QSortFilterProxyModel::data
+168 (int (*)(...))QSortFilterProxyModel::setData
+176 (int (*)(...))QSortFilterProxyModel::headerData
+184 (int (*)(...))QSortFilterProxyModel::setHeaderData
+192 (int (*)(...))QAbstractProxyModel::itemData
+200 (int (*)(...))QAbstractProxyModel::setItemData
+208 (int (*)(...))QSortFilterProxyModel::mimeTypes
+216 (int (*)(...))QSortFilterProxyModel::mimeData
+224 (int (*)(...))QAbstractProxyModel::canDropMimeData
+232 (int (*)(...))QSortFilterProxyModel::dropMimeData
+240 (int (*)(...))QSortFilterProxyModel::supportedDropActions
+248 (int (*)(...))QAbstractProxyModel::supportedDragActions
+256 (int (*)(...))QSortFilterProxyModel::insertRows
+264 (int (*)(...))QSortFilterProxyModel::insertColumns
+272 (int (*)(...))QSortFilterProxyModel::removeRows
+280 (int (*)(...))QSortFilterProxyModel::removeColumns
+288 (int (*)(...))QAbstractItemModel::moveRows
+296 (int (*)(...))QAbstractItemModel::moveColumns
+304 (int (*)(...))QSortFilterProxyModel::fetchMore
+312 (int (*)(...))QSortFilterProxyModel::canFetchMore
+320 (int (*)(...))QSortFilterProxyModel::flags
+328 (int (*)(...))QSortFilterProxyModel::sort
+336 (int (*)(...))QSortFilterProxyModel::buddy
+344 (int (*)(...))QSortFilterProxyModel::match
+352 (int (*)(...))QSortFilterProxyModel::span
+360 (int (*)(...))QAbstractItemModel::roleNames
+368 (int (*)(...))QAbstractProxyModel::submit
+376 (int (*)(...))QAbstractProxyModel::revert
+384 (int (*)(...))QSortFilterProxyModel::setSourceModel
+392 (int (*)(...))QSortFilterProxyModel::mapToSource
+400 (int (*)(...))QSortFilterProxyModel::mapFromSource
+408 (int (*)(...))QSortFilterProxyModel::mapSelectionToSource
+416 (int (*)(...))QSortFilterProxyModel::mapSelectionFromSource
+424 (int (*)(...))QSortFilterProxyModel::filterAcceptsRow
+432 (int (*)(...))QSortFilterProxyModel::filterAcceptsColumn
+440 (int (*)(...))QSortFilterProxyModel::lessThan
+
+Class QSortFilterProxyModel
+ size=16 align=8
+ base size=16 base align=8
+QSortFilterProxyModel (0x0x7f234619e2d8) 0
+ vptr=((& QSortFilterProxyModel::_ZTV21QSortFilterProxyModel) + 16)
+ QAbstractProxyModel (0x0x7f234619e340) 0
+ primary-for QSortFilterProxyModel (0x0x7f234619e2d8)
+ QAbstractItemModel (0x0x7f234619e3a8) 0
+ primary-for QAbstractProxyModel (0x0x7f234619e340)
+ QObject (0x0x7f23461ee660) 0
+ primary-for QAbstractItemModel (0x0x7f234619e3a8)
+
+Class QStandardPaths
+ size=1 align=1
+ base size=0 base align=1
+QStandardPaths (0x0x7f23461eeae0) 0 empty
+
+Class QState::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QState::QPrivateSignal (0x0x7f234625e420) 0 empty
+
+Vtable for QState
+QState::_ZTV6QState: 16 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI6QState)
+16 (int (*)(...))QState::metaObject
+24 (int (*)(...))QState::qt_metacast
+32 (int (*)(...))QState::qt_metacall
+40 (int (*)(...))QState::~QState
+48 (int (*)(...))QState::~QState
+56 (int (*)(...))QState::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QState::onEntry
+120 (int (*)(...))QState::onExit
+
+Class QState
+ size=16 align=8
+ base size=16 base align=8
+QState (0x0x7f234619e548) 0
+ vptr=((& QState::_ZTV6QState) + 16)
+ QAbstractState (0x0x7f234619e5b0) 0
+ primary-for QState (0x0x7f234619e548)
+ QObject (0x0x7f234625e3c0) 0
+ primary-for QAbstractState (0x0x7f234619e5b0)
+
+Class QStateMachine::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QStateMachine::QPrivateSignal (0x0x7f234625e8a0) 0 empty
+
+Vtable for QStateMachine::SignalEvent
+QStateMachine::SignalEvent::_ZTVN13QStateMachine11SignalEventE: 4 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTIN13QStateMachine11SignalEventE)
+16 (int (*)(...))QStateMachine::SignalEvent::~SignalEvent
+24 (int (*)(...))QStateMachine::SignalEvent::~SignalEvent
+
+Class QStateMachine::SignalEvent
+ size=48 align=8
+ base size=48 base align=8
+QStateMachine::SignalEvent (0x0x7f234619e750) 0
+ vptr=((& QStateMachine::SignalEvent::_ZTVN13QStateMachine11SignalEventE) + 16)
+ QEvent (0x0x7f234625e900) 0
+ primary-for QStateMachine::SignalEvent (0x0x7f234619e750)
+
+Vtable for QStateMachine::WrappedEvent
+QStateMachine::WrappedEvent::_ZTVN13QStateMachine12WrappedEventE: 4 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTIN13QStateMachine12WrappedEventE)
+16 (int (*)(...))QStateMachine::WrappedEvent::~WrappedEvent
+24 (int (*)(...))QStateMachine::WrappedEvent::~WrappedEvent
+
+Class QStateMachine::WrappedEvent
+ size=40 align=8
+ base size=40 base align=8
+QStateMachine::WrappedEvent (0x0x7f234619e7b8) 0
+ vptr=((& QStateMachine::WrappedEvent::_ZTVN13QStateMachine12WrappedEventE) + 16)
+ QEvent (0x0x7f234625e960) 0
+ primary-for QStateMachine::WrappedEvent (0x0x7f234619e7b8)
+
+Vtable for QStateMachine
+QStateMachine::_ZTV13QStateMachine: 20 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI13QStateMachine)
+16 (int (*)(...))QStateMachine::metaObject
+24 (int (*)(...))QStateMachine::qt_metacast
+32 (int (*)(...))QStateMachine::qt_metacall
+40 (int (*)(...))QStateMachine::~QStateMachine
+48 (int (*)(...))QStateMachine::~QStateMachine
+56 (int (*)(...))QStateMachine::event
+64 (int (*)(...))QStateMachine::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QStateMachine::onEntry
+120 (int (*)(...))QStateMachine::onExit
+128 (int (*)(...))QStateMachine::beginSelectTransitions
+136 (int (*)(...))QStateMachine::endSelectTransitions
+144 (int (*)(...))QStateMachine::beginMicrostep
+152 (int (*)(...))QStateMachine::endMicrostep
+
+Class QStateMachine
+ size=16 align=8
+ base size=16 base align=8
+QStateMachine (0x0x7f234619e618) 0
+ vptr=((& QStateMachine::_ZTV13QStateMachine) + 16)
+ QState (0x0x7f234619e680) 0
+ primary-for QStateMachine (0x0x7f234619e618)
+ QAbstractState (0x0x7f234619e6e8) 0
+ primary-for QState (0x0x7f234619e680)
+ QObject (0x0x7f234625e840) 0
+ primary-for QAbstractState (0x0x7f234619e6e8)
+
+Class QStorageInfo
+ size=8 align=8
+ base size=8 base align=8
+QStorageInfo (0x0x7f234625ed20) 0
+
+Class QAbstractConcatenable
+ size=1 align=1
+ base size=0 base align=1
+QAbstractConcatenable (0x0x7f2345f15d20) 0 empty
+
+Class QStringListModel::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QStringListModel::QPrivateSignal (0x0x7f2345fcb0c0) 0 empty
+
+Vtable for QStringListModel
+QStringListModel::_ZTV16QStringListModel: 48 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI16QStringListModel)
+16 (int (*)(...))QStringListModel::metaObject
+24 (int (*)(...))QStringListModel::qt_metacast
+32 (int (*)(...))QStringListModel::qt_metacall
+40 (int (*)(...))QStringListModel::~QStringListModel
+48 (int (*)(...))QStringListModel::~QStringListModel
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QAbstractListModel::index
+120 (int (*)(...))QAbstractListModel::parent
+128 (int (*)(...))QStringListModel::sibling
+136 (int (*)(...))QStringListModel::rowCount
+144 (int (*)(...))QAbstractListModel::columnCount
+152 (int (*)(...))QAbstractListModel::hasChildren
+160 (int (*)(...))QStringListModel::data
+168 (int (*)(...))QStringListModel::setData
+176 (int (*)(...))QAbstractItemModel::headerData
+184 (int (*)(...))QAbstractItemModel::setHeaderData
+192 (int (*)(...))QStringListModel::itemData
+200 (int (*)(...))QStringListModel::setItemData
+208 (int (*)(...))QAbstractItemModel::mimeTypes
+216 (int (*)(...))QAbstractItemModel::mimeData
+224 (int (*)(...))QAbstractItemModel::canDropMimeData
+232 (int (*)(...))QAbstractListModel::dropMimeData
+240 (int (*)(...))QStringListModel::supportedDropActions
+248 (int (*)(...))QAbstractItemModel::supportedDragActions
+256 (int (*)(...))QStringListModel::insertRows
+264 (int (*)(...))QAbstractItemModel::insertColumns
+272 (int (*)(...))QStringListModel::removeRows
+280 (int (*)(...))QAbstractItemModel::removeColumns
+288 (int (*)(...))QStringListModel::moveRows
+296 (int (*)(...))QAbstractItemModel::moveColumns
+304 (int (*)(...))QAbstractItemModel::fetchMore
+312 (int (*)(...))QAbstractItemModel::canFetchMore
+320 (int (*)(...))QStringListModel::flags
+328 (int (*)(...))QStringListModel::sort
+336 (int (*)(...))QAbstractItemModel::buddy
+344 (int (*)(...))QAbstractItemModel::match
+352 (int (*)(...))QAbstractItemModel::span
+360 (int (*)(...))QAbstractItemModel::roleNames
+368 (int (*)(...))QAbstractItemModel::submit
+376 (int (*)(...))QAbstractItemModel::revert
+
+Class QStringListModel
+ size=24 align=8
+ base size=24 base align=8
+QStringListModel (0x0x7f2345fa48f0) 0
+ vptr=((& QStringListModel::_ZTV16QStringListModel) + 16)
+ QAbstractListModel (0x0x7f2345fa4958) 0
+ primary-for QStringListModel (0x0x7f2345fa48f0)
+ QAbstractItemModel (0x0x7f2345fa49c0) 0
+ primary-for QAbstractListModel (0x0x7f2345fa4958)
+ QObject (0x0x7f2345fcb060) 0
+ primary-for QAbstractItemModel (0x0x7f2345fa49c0)
+
+Class QSystemSemaphore
+ size=8 align=8
+ base size=8 base align=8
+QSystemSemaphore (0x0x7f2345fcb1e0) 0
+
+Class QTemporaryDir
+ size=8 align=8
+ base size=8 base align=8
+QTemporaryDir (0x0x7f2345fcb2a0) 0
+
+Class QTemporaryFile::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QTemporaryFile::QPrivateSignal (0x0x7f2345fcb3c0) 0 empty
+
+Vtable for QTemporaryFile
+QTemporaryFile::_ZTV14QTemporaryFile: 34 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI14QTemporaryFile)
+16 (int (*)(...))QTemporaryFile::metaObject
+24 (int (*)(...))QTemporaryFile::qt_metacast
+32 (int (*)(...))QTemporaryFile::qt_metacall
+40 (int (*)(...))QTemporaryFile::~QTemporaryFile
+48 (int (*)(...))QTemporaryFile::~QTemporaryFile
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QFileDevice::isSequential
+120 (int (*)(...))QTemporaryFile::open
+128 (int (*)(...))QFileDevice::close
+136 (int (*)(...))QFileDevice::pos
+144 (int (*)(...))QFile::size
+152 (int (*)(...))QFileDevice::seek
+160 (int (*)(...))QFileDevice::atEnd
+168 (int (*)(...))QIODevice::reset
+176 (int (*)(...))QIODevice::bytesAvailable
+184 (int (*)(...))QIODevice::bytesToWrite
+192 (int (*)(...))QIODevice::canReadLine
+200 (int (*)(...))QIODevice::waitForReadyRead
+208 (int (*)(...))QIODevice::waitForBytesWritten
+216 (int (*)(...))QFileDevice::readData
+224 (int (*)(...))QFileDevice::readLineData
+232 (int (*)(...))QFileDevice::writeData
+240 (int (*)(...))QTemporaryFile::fileName
+248 (int (*)(...))QFile::resize
+256 (int (*)(...))QFile::permissions
+264 (int (*)(...))QFile::setPermissions
+
+Class QTemporaryFile
+ size=16 align=8
+ base size=16 base align=8
+QTemporaryFile (0x0x7f2345fa4a28) 0
+ vptr=((& QTemporaryFile::_ZTV14QTemporaryFile) + 16)
+ QFile (0x0x7f2345fa4a90) 0
+ primary-for QTemporaryFile (0x0x7f2345fa4a28)
+ QFileDevice (0x0x7f2345fa4af8) 0
+ primary-for QFile (0x0x7f2345fa4a90)
+ QIODevice (0x0x7f2345fa4b60) 0
+ primary-for QFileDevice (0x0x7f2345fa4af8)
+ QObject (0x0x7f2345fcb360) 0
+ primary-for QIODevice (0x0x7f2345fa4b60)
+
+Class QTextBoundaryFinder
+ size=48 align=8
+ base size=48 base align=8
+QTextBoundaryFinder (0x0x7f2345fcb720) 0
+
+Class QTextCodec::ConverterState
+ size=32 align=8
+ base size=32 base align=8
+QTextCodec::ConverterState (0x0x7f2345fcbf60) 0
+
+Vtable for QTextCodec
+QTextCodec::_ZTV10QTextCodec: 9 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI10QTextCodec)
+16 (int (*)(...))__cxa_pure_virtual
+24 (int (*)(...))QTextCodec::aliases
+32 (int (*)(...))__cxa_pure_virtual
+40 (int (*)(...))__cxa_pure_virtual
+48 (int (*)(...))__cxa_pure_virtual
+56 0
+64 0
+
+Class QTextCodec
+ size=8 align=8
+ base size=8 base align=8
+QTextCodec (0x0x7f2345fcbf00) 0 nearly-empty
+ vptr=((& QTextCodec::_ZTV10QTextCodec) + 16)
+
+Class QTextEncoder
+ size=40 align=8
+ base size=40 base align=8
+QTextEncoder (0x0x7f2346048960) 0
+
+Class QTextDecoder
+ size=40 align=8
+ base size=40 base align=8
+QTextDecoder (0x0x7f2346048b40) 0
+
+Class std::__mutex_base
+ size=40 align=8
+ base size=40 base align=8
+std::__mutex_base (0x0x7f2346048d20) 0
+
+Class std::mutex
+ size=40 align=8
+ base size=40 base align=8
+std::mutex (0x0x7f2345fa4d68) 0
+ std::__mutex_base (0x0x7f2346048d80) 0
+
+Class std::defer_lock_t
+ size=1 align=1
+ base size=0 base align=1
+std::defer_lock_t (0x0x7f2346048f60) 0 empty
+
+Class std::try_to_lock_t
+ size=1 align=1
+ base size=0 base align=1
+std::try_to_lock_t (0x0x7f23460a1000) 0 empty
+
+Class std::adopt_lock_t
+ size=1 align=1
+ base size=0 base align=1
+std::adopt_lock_t (0x0x7f23460a1060) 0 empty
+
+Class std::__recursive_mutex_base
+ size=40 align=8
+ base size=40 base align=8
+std::__recursive_mutex_base (0x0x7f23460a1a80) 0
+
+Class std::recursive_mutex
+ size=40 align=8
+ base size=40 base align=8
+std::recursive_mutex (0x0x7f2345fa4dd0) 0
+ std::__recursive_mutex_base (0x0x7f23460a1ae0) 0
+
+Class std::timed_mutex
+ size=40 align=8
+ base size=40 base align=8
+std::timed_mutex (0x0x7f2346095cb0) 0
+ std::__mutex_base (0x0x7f23460a1ea0) 0
+ std::__timed_mutex_impl<std::timed_mutex> (0x0x7f23460a1f00) 0 empty
+
+Class std::recursive_timed_mutex
+ size=40 align=8
+ base size=40 base align=8
+std::recursive_timed_mutex (0x0x7f2345cf0000) 0
+ std::__recursive_mutex_base (0x0x7f2345ce82a0) 0
+ std::__timed_mutex_impl<std::recursive_timed_mutex> (0x0x7f2345ce8300) 0 empty
+
+Class std::once_flag
+ size=4 align=4
+ base size=4 base align=4
+std::once_flag (0x0x7f2345ce8a20) 0
+
+Vtable for __gnu_cxx::__concurrence_lock_error
+__gnu_cxx::__concurrence_lock_error::_ZTVN9__gnu_cxx24__concurrence_lock_errorE: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTIN9__gnu_cxx24__concurrence_lock_errorE)
+16 (int (*)(...))__gnu_cxx::__concurrence_lock_error::~__concurrence_lock_error
+24 (int (*)(...))__gnu_cxx::__concurrence_lock_error::~__concurrence_lock_error
+32 (int (*)(...))__gnu_cxx::__concurrence_lock_error::what
+
+Class __gnu_cxx::__concurrence_lock_error
+ size=8 align=8
+ base size=8 base align=8
+__gnu_cxx::__concurrence_lock_error (0x0x7f2345fa4f08) 0 nearly-empty
+ vptr=((& __gnu_cxx::__concurrence_lock_error::_ZTVN9__gnu_cxx24__concurrence_lock_errorE) + 16)
+ std::exception (0x0x7f2345ce8f60) 0 nearly-empty
+ primary-for __gnu_cxx::__concurrence_lock_error (0x0x7f2345fa4f08)
+
+Vtable for __gnu_cxx::__concurrence_unlock_error
+__gnu_cxx::__concurrence_unlock_error::_ZTVN9__gnu_cxx26__concurrence_unlock_errorE: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTIN9__gnu_cxx26__concurrence_unlock_errorE)
+16 (int (*)(...))__gnu_cxx::__concurrence_unlock_error::~__concurrence_unlock_error
+24 (int (*)(...))__gnu_cxx::__concurrence_unlock_error::~__concurrence_unlock_error
+32 (int (*)(...))__gnu_cxx::__concurrence_unlock_error::what
+
+Class __gnu_cxx::__concurrence_unlock_error
+ size=8 align=8
+ base size=8 base align=8
+__gnu_cxx::__concurrence_unlock_error (0x0x7f2345fa4f70) 0 nearly-empty
+ vptr=((& __gnu_cxx::__concurrence_unlock_error::_ZTVN9__gnu_cxx26__concurrence_unlock_errorE) + 16)
+ std::exception (0x0x7f2345d1e0c0) 0 nearly-empty
+ primary-for __gnu_cxx::__concurrence_unlock_error (0x0x7f2345fa4f70)
+
+Vtable for __gnu_cxx::__concurrence_broadcast_error
+__gnu_cxx::__concurrence_broadcast_error::_ZTVN9__gnu_cxx29__concurrence_broadcast_errorE: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTIN9__gnu_cxx29__concurrence_broadcast_errorE)
+16 (int (*)(...))__gnu_cxx::__concurrence_broadcast_error::~__concurrence_broadcast_error
+24 (int (*)(...))__gnu_cxx::__concurrence_broadcast_error::~__concurrence_broadcast_error
+32 (int (*)(...))__gnu_cxx::__concurrence_broadcast_error::what
+
+Class __gnu_cxx::__concurrence_broadcast_error
+ size=8 align=8
+ base size=8 base align=8
+__gnu_cxx::__concurrence_broadcast_error (0x0x7f2345d25000) 0 nearly-empty
+ vptr=((& __gnu_cxx::__concurrence_broadcast_error::_ZTVN9__gnu_cxx29__concurrence_broadcast_errorE) + 16)
+ std::exception (0x0x7f2345d1e1e0) 0 nearly-empty
+ primary-for __gnu_cxx::__concurrence_broadcast_error (0x0x7f2345d25000)
+
+Vtable for __gnu_cxx::__concurrence_wait_error
+__gnu_cxx::__concurrence_wait_error::_ZTVN9__gnu_cxx24__concurrence_wait_errorE: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTIN9__gnu_cxx24__concurrence_wait_errorE)
+16 (int (*)(...))__gnu_cxx::__concurrence_wait_error::~__concurrence_wait_error
+24 (int (*)(...))__gnu_cxx::__concurrence_wait_error::~__concurrence_wait_error
+32 (int (*)(...))__gnu_cxx::__concurrence_wait_error::what
+
+Class __gnu_cxx::__concurrence_wait_error
+ size=8 align=8
+ base size=8 base align=8
+__gnu_cxx::__concurrence_wait_error (0x0x7f2345d250d0) 0 nearly-empty
+ vptr=((& __gnu_cxx::__concurrence_wait_error::_ZTVN9__gnu_cxx24__concurrence_wait_errorE) + 16)
+ std::exception (0x0x7f2345d1e300) 0 nearly-empty
+ primary-for __gnu_cxx::__concurrence_wait_error (0x0x7f2345d250d0)
+
+Class __gnu_cxx::__mutex
+ size=40 align=8
+ base size=40 base align=8
+__gnu_cxx::__mutex (0x0x7f2345d46360) 0
+
+Class __gnu_cxx::__recursive_mutex
+ size=40 align=8
+ base size=40 base align=8
+__gnu_cxx::__recursive_mutex (0x0x7f2345d46660) 0
+
+Class __gnu_cxx::__scoped_lock
+ size=8 align=8
+ base size=8 base align=8
+__gnu_cxx::__scoped_lock (0x0x7f2345d46960) 0
+
+Class __gnu_cxx::__cond
+ size=48 align=8
+ base size=48 base align=8
+__gnu_cxx::__cond (0x0x7f2345d46cc0) 0
+
+Vtable for std::bad_weak_ptr
+std::bad_weak_ptr::_ZTVSt12bad_weak_ptr: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTISt12bad_weak_ptr)
+16 (int (*)(...))std::bad_weak_ptr::~bad_weak_ptr
+24 (int (*)(...))std::bad_weak_ptr::~bad_weak_ptr
+32 (int (*)(...))std::bad_weak_ptr::what
+
+Class std::bad_weak_ptr
+ size=8 align=8
+ base size=8 base align=8
+std::bad_weak_ptr (0x0x7f2345d25138) 0 nearly-empty
+ vptr=((& std::bad_weak_ptr::_ZTVSt12bad_weak_ptr) + 16)
+ std::exception (0x0x7f2345dc2ea0) 0 nearly-empty
+ primary-for std::bad_weak_ptr (0x0x7f2345d25138)
+
+Class std::_Sp_make_shared_tag
+ size=1 align=1
+ base size=0 base align=1
+std::_Sp_make_shared_tag (0x0x7f2345e24e40) 0 empty
+
+Class std::__sp_array_delete
+ size=1 align=1
+ base size=0 base align=1
+std::__sp_array_delete (0x0x7f2345e522a0) 0 empty
+
+Class std::_Sp_locker
+ size=2 align=1
+ base size=2 base align=1
+std::_Sp_locker (0x0x7f2345b9a120) 0
+
+Vtable for std::thread::_State
+std::thread::_State::_ZTVNSt6thread6_StateE: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTINSt6thread6_StateE)
+16 0
+24 0
+32 (int (*)(...))__cxa_pure_virtual
+
+Class std::thread::_State
+ size=8 align=8
+ base size=8 base align=8
+std::thread::_State (0x0x7f2345bc55a0) 0 nearly-empty
+ vptr=((& std::thread::_State::_ZTVNSt6thread6_StateE) + 16)
+
+Class std::thread::id
+ size=8 align=8
+ base size=8 base align=8
+std::thread::id (0x0x7f2345bc5600) 0
+
+Class std::thread
+ size=8 align=8
+ base size=8 base align=8
+std::thread (0x0x7f2345bc5540) 0
+
+Class std::condition_variable
+ size=48 align=8
+ base size=48 base align=8
+std::condition_variable (0x0x7f2345a569c0) 0
+
+Class std::__at_thread_exit_elt
+ size=16 align=8
+ base size=16 base align=8
+std::__at_thread_exit_elt (0x0x7f2345a56d80) 0
+
+Class std::_V2::condition_variable_any
+ size=64 align=8
+ base size=64 base align=8
+std::_V2::condition_variable_any (0x0x7f2345a56de0) 0
+
+Class std::__atomic_futex_unsigned_base
+ size=1 align=1
+ base size=0 base align=1
+std::__atomic_futex_unsigned_base (0x0x7f2345812120) 0 empty
+
+Vtable for std::future_error
+std::future_error::_ZTVSt12future_error: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTISt12future_error)
+16 (int (*)(...))std::future_error::~future_error
+24 (int (*)(...))std::future_error::~future_error
+32 (int (*)(...))std::future_error::what
+
+Class std::future_error
+ size=32 align=8
+ base size=32 base align=8
+std::future_error (0x0x7f23457f89c0) 0
+ vptr=((& std::future_error::_ZTVSt12future_error) + 16)
+ std::logic_error (0x0x7f23457f8a28) 0
+ primary-for std::future_error (0x0x7f23457f89c0)
+ std::exception (0x0x7f2345812840) 0 nearly-empty
+ primary-for std::logic_error (0x0x7f23457f8a28)
+
+Class std::__future_base::_Result_base::_Deleter
+ size=1 align=1
+ base size=0 base align=1
+std::__future_base::_Result_base::_Deleter (0x0x7f2345812f60) 0 empty
+
+Vtable for std::__future_base::_Result_base
+std::__future_base::_Result_base::_ZTVNSt13__future_base12_Result_baseE: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTINSt13__future_base12_Result_baseE)
+16 (int (*)(...))__cxa_pure_virtual
+24 0
+32 0
+
+Class std::__future_base::_Result_base
+ size=16 align=8
+ base size=16 base align=8
+std::__future_base::_Result_base (0x0x7f2345812f00) 0
+ vptr=((& std::__future_base::_Result_base::_ZTVNSt13__future_base12_Result_baseE) + 16)
+
+Class std::__future_base::_State_baseV2::__exception_ptr_tag
+ size=1 align=1
+ base size=0 base align=1
+std::__future_base::_State_baseV2::__exception_ptr_tag (0x0x7f234561c6c0) 0 empty
+
+Class std::__future_base::_State_baseV2::_Make_ready
+ size=32 align=8
+ base size=32 base align=8
+std::__future_base::_State_baseV2::_Make_ready (0x0x7f234561f270) 0
+ std::__at_thread_exit_elt (0x0x7f234561c780) 0
+
+Vtable for std::__future_base::_State_baseV2
+std::__future_base::_State_baseV2::_ZTVNSt13__future_base13_State_baseV2E: 6 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTINSt13__future_base13_State_baseV2E)
+16 (int (*)(...))std::__future_base::_State_baseV2::~_State_baseV2
+24 (int (*)(...))std::__future_base::_State_baseV2::~_State_baseV2
+32 (int (*)(...))std::__future_base::_State_baseV2::_M_complete_async
+40 (int (*)(...))std::__future_base::_State_baseV2::_M_is_deferred_future
+
+Class std::__future_base::_State_baseV2
+ size=32 align=8
+ base size=28 base align=8
+std::__future_base::_State_baseV2 (0x0x7f2345846120) 0
+ vptr=((& std::__future_base::_State_baseV2::_ZTVNSt13__future_base13_State_baseV2E) + 16)
+
+Class std::__future_base
+ size=1 align=1
+ base size=0 base align=1
+std::__future_base (0x0x7f2345812ea0) 0 empty
+
+Vtable for std::__future_base::_Async_state_commonV2
+std::__future_base::_Async_state_commonV2::_ZTVNSt13__future_base21_Async_state_commonV2E: 6 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTINSt13__future_base21_Async_state_commonV2E)
+16 (int (*)(...))std::__future_base::_Async_state_commonV2::~_Async_state_commonV2
+24 (int (*)(...))std::__future_base::_Async_state_commonV2::~_Async_state_commonV2
+32 (int (*)(...))std::__future_base::_Async_state_commonV2::_M_complete_async
+40 (int (*)(...))std::__future_base::_State_baseV2::_M_is_deferred_future
+
+Class std::__future_base::_Async_state_commonV2
+ size=48 align=8
+ base size=44 base align=8
+std::__future_base::_Async_state_commonV2 (0x0x7f2344d7ef70) 0
+ vptr=((& std::__future_base::_Async_state_commonV2::_ZTVNSt13__future_base21_Async_state_commonV2E) + 16)
+ std::__future_base::_State_baseV2 (0x0x7f2344dcc780) 0
+ primary-for std::__future_base::_Async_state_commonV2 (0x0x7f2344d7ef70)
+
+Class QThread::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QThread::QPrivateSignal (0x0x7f2344df9060) 0 empty
+
+Vtable for QThread
+QThread::_ZTV7QThread: 15 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI7QThread)
+16 (int (*)(...))QThread::metaObject
+24 (int (*)(...))QThread::qt_metacast
+32 (int (*)(...))QThread::qt_metacall
+40 (int (*)(...))QThread::~QThread
+48 (int (*)(...))QThread::~QThread
+56 (int (*)(...))QThread::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QThread::run
+
+Class QThread
+ size=16 align=8
+ base size=16 base align=8
+QThread (0x0x7f2344de02d8) 0
+ vptr=((& QThread::_ZTV7QThread) + 16)
+ QObject (0x0x7f2344df9000) 0
+ primary-for QThread (0x0x7f2344de02d8)
+
+Class QThreadPool::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QThreadPool::QPrivateSignal (0x0x7f2344df9420) 0 empty
+
+Vtable for QThreadPool
+QThreadPool::_ZTV11QThreadPool: 14 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI11QThreadPool)
+16 (int (*)(...))QThreadPool::metaObject
+24 (int (*)(...))QThreadPool::qt_metacast
+32 (int (*)(...))QThreadPool::qt_metacall
+40 (int (*)(...))QThreadPool::~QThreadPool
+48 (int (*)(...))QThreadPool::~QThreadPool
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+
+Class QThreadPool
+ size=16 align=8
+ base size=16 base align=8
+QThreadPool (0x0x7f2344de0340) 0
+ vptr=((& QThreadPool::_ZTV11QThreadPool) + 16)
+ QObject (0x0x7f2344df93c0) 0
+ primary-for QThreadPool (0x0x7f2344de0340)
+
+Class QThreadStorageData
+ size=4 align=4
+ base size=4 base align=4
+QThreadStorageData (0x0x7f2344df9600) 0
+
+Class QTimeLine::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QTimeLine::QPrivateSignal (0x0x7f2344df9cc0) 0 empty
+
+Vtable for QTimeLine
+QTimeLine::_ZTV9QTimeLine: 15 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI9QTimeLine)
+16 (int (*)(...))QTimeLine::metaObject
+24 (int (*)(...))QTimeLine::qt_metacast
+32 (int (*)(...))QTimeLine::qt_metacall
+40 (int (*)(...))QTimeLine::~QTimeLine
+48 (int (*)(...))QTimeLine::~QTimeLine
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QTimeLine::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QTimeLine::valueForTime
+
+Class QTimeLine
+ size=16 align=8
+ base size=16 base align=8
+QTimeLine (0x0x7f2344de03a8) 0
+ vptr=((& QTimeLine::_ZTV9QTimeLine) + 16)
+ QObject (0x0x7f2344df9c60) 0
+ primary-for QTimeLine (0x0x7f2344de03a8)
+
+Class QTimer::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QTimer::QPrivateSignal (0x0x7f2344df9f00) 0 empty
+
+Vtable for QTimer
+QTimer::_ZTV6QTimer: 14 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI6QTimer)
+16 (int (*)(...))QTimer::metaObject
+24 (int (*)(...))QTimer::qt_metacast
+32 (int (*)(...))QTimer::qt_metacall
+40 (int (*)(...))QTimer::~QTimer
+48 (int (*)(...))QTimer::~QTimer
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QTimer::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+
+Class QTimer
+ size=32 align=8
+ base size=29 base align=8
+QTimer (0x0x7f2344de0410) 0
+ vptr=((& QTimer::_ZTV6QTimer) + 16)
+ QObject (0x0x7f2344df9ea0) 0
+ primary-for QTimer (0x0x7f2344de0410)
+
+Class QTimeZone::OffsetData
+ size=32 align=8
+ base size=28 base align=8
+QTimeZone::OffsetData (0x0x7f2344e7f8a0) 0
+
+Class QTimeZone
+ size=8 align=8
+ base size=8 base align=8
+QTimeZone (0x0x7f2344e7f840) 0
+
+Class QTranslator::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QTranslator::QPrivateSignal (0x0x7f2344b24960) 0 empty
+
+Vtable for QTranslator
+QTranslator::_ZTV11QTranslator: 16 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI11QTranslator)
+16 (int (*)(...))QTranslator::metaObject
+24 (int (*)(...))QTranslator::qt_metacast
+32 (int (*)(...))QTranslator::qt_metacall
+40 (int (*)(...))QTranslator::~QTranslator
+48 (int (*)(...))QTranslator::~QTranslator
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QTranslator::translate
+120 (int (*)(...))QTranslator::isEmpty
+
+Class QTranslator
+ size=16 align=8
+ base size=16 base align=8
+QTranslator (0x0x7f2344b21af8) 0
+ vptr=((& QTranslator::_ZTV11QTranslator) + 16)
+ QObject (0x0x7f2344b24900) 0
+ primary-for QTranslator (0x0x7f2344b21af8)
+
+Class QTransposeProxyModel::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QTransposeProxyModel::QPrivateSignal (0x0x7f2344b24ba0) 0 empty
+
+Vtable for QTransposeProxyModel
+QTransposeProxyModel::_ZTV20QTransposeProxyModel: 53 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI20QTransposeProxyModel)
+16 (int (*)(...))QTransposeProxyModel::metaObject
+24 (int (*)(...))QTransposeProxyModel::qt_metacast
+32 (int (*)(...))QTransposeProxyModel::qt_metacall
+40 (int (*)(...))QTransposeProxyModel::~QTransposeProxyModel
+48 (int (*)(...))QTransposeProxyModel::~QTransposeProxyModel
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QTransposeProxyModel::index
+120 (int (*)(...))QTransposeProxyModel::parent
+128 (int (*)(...))QAbstractProxyModel::sibling
+136 (int (*)(...))QTransposeProxyModel::rowCount
+144 (int (*)(...))QTransposeProxyModel::columnCount
+152 (int (*)(...))QAbstractProxyModel::hasChildren
+160 (int (*)(...))QAbstractProxyModel::data
+168 (int (*)(...))QAbstractProxyModel::setData
+176 (int (*)(...))QTransposeProxyModel::headerData
+184 (int (*)(...))QTransposeProxyModel::setHeaderData
+192 (int (*)(...))QTransposeProxyModel::itemData
+200 (int (*)(...))QTransposeProxyModel::setItemData
+208 (int (*)(...))QAbstractProxyModel::mimeTypes
+216 (int (*)(...))QAbstractProxyModel::mimeData
+224 (int (*)(...))QAbstractProxyModel::canDropMimeData
+232 (int (*)(...))QAbstractProxyModel::dropMimeData
+240 (int (*)(...))QAbstractProxyModel::supportedDropActions
+248 (int (*)(...))QAbstractProxyModel::supportedDragActions
+256 (int (*)(...))QTransposeProxyModel::insertRows
+264 (int (*)(...))QTransposeProxyModel::insertColumns
+272 (int (*)(...))QTransposeProxyModel::removeRows
+280 (int (*)(...))QTransposeProxyModel::removeColumns
+288 (int (*)(...))QTransposeProxyModel::moveRows
+296 (int (*)(...))QTransposeProxyModel::moveColumns
+304 (int (*)(...))QAbstractProxyModel::fetchMore
+312 (int (*)(...))QAbstractProxyModel::canFetchMore
+320 (int (*)(...))QAbstractProxyModel::flags
+328 (int (*)(...))QTransposeProxyModel::sort
+336 (int (*)(...))QAbstractProxyModel::buddy
+344 (int (*)(...))QAbstractItemModel::match
+352 (int (*)(...))QTransposeProxyModel::span
+360 (int (*)(...))QAbstractItemModel::roleNames
+368 (int (*)(...))QAbstractProxyModel::submit
+376 (int (*)(...))QAbstractProxyModel::revert
+384 (int (*)(...))QTransposeProxyModel::setSourceModel
+392 (int (*)(...))QTransposeProxyModel::mapToSource
+400 (int (*)(...))QTransposeProxyModel::mapFromSource
+408 (int (*)(...))QAbstractProxyModel::mapSelectionToSource
+416 (int (*)(...))QAbstractProxyModel::mapSelectionFromSource
+
+Class QTransposeProxyModel
+ size=16 align=8
+ base size=16 base align=8
+QTransposeProxyModel (0x0x7f2344b21b60) 0
+ vptr=((& QTransposeProxyModel::_ZTV20QTransposeProxyModel) + 16)
+ QAbstractProxyModel (0x0x7f2344b21bc8) 0
+ primary-for QTransposeProxyModel (0x0x7f2344b21b60)
+ QAbstractItemModel (0x0x7f2344b21c30) 0
+ primary-for QAbstractProxyModel (0x0x7f2344b21bc8)
+ QObject (0x0x7f2344b24b40) 0
+ primary-for QAbstractItemModel (0x0x7f2344b21c30)
+
+Class QUrlQuery
+ size=8 align=8
+ base size=8 base align=8
+QUrlQuery (0x0x7f2344b24d80) 0
+
+Class QWaitCondition
+ size=8 align=8
+ base size=8 base align=8
+QWaitCondition (0x0x7f2344bc6780) 0
+
+Class QXmlStreamStringRef
+ size=16 align=8
+ base size=16 base align=8
+QXmlStreamStringRef (0x0x7f2344bc68a0) 0
+
+Class QXmlStreamAttribute
+ size=80 align=8
+ base size=73 base align=8
+QXmlStreamAttribute (0x0x7f2344c55c60) 0
+
+Class QXmlStreamAttributes
+ size=8 align=8
+ base size=8 base align=8
+QXmlStreamAttributes (0x0x7f23448d32d8) 0
+ QVector<QXmlStreamAttribute> (0x0x7f23448d23c0) 0
+
+Class QXmlStreamNamespaceDeclaration
+ size=40 align=8
+ base size=40 base align=8
+QXmlStreamNamespaceDeclaration (0x0x7f23448d26c0) 0
+
+Class QXmlStreamNotationDeclaration
+ size=56 align=8
+ base size=56 base align=8
+QXmlStreamNotationDeclaration (0x0x7f2344956660) 0
+
+Class QXmlStreamEntityDeclaration
+ size=88 align=8
+ base size=88 base align=8
+QXmlStreamEntityDeclaration (0x0x7f23449b4660) 0
+
+Vtable for QXmlStreamEntityResolver
+QXmlStreamEntityResolver::_ZTV24QXmlStreamEntityResolver: 6 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI24QXmlStreamEntityResolver)
+16 (int (*)(...))QXmlStreamEntityResolver::~QXmlStreamEntityResolver
+24 (int (*)(...))QXmlStreamEntityResolver::~QXmlStreamEntityResolver
+32 (int (*)(...))QXmlStreamEntityResolver::resolveEntity
+40 (int (*)(...))QXmlStreamEntityResolver::resolveUndeclaredEntity
+
+Class QXmlStreamEntityResolver
+ size=8 align=8
+ base size=8 base align=8
+QXmlStreamEntityResolver (0x0x7f2344a1e720) 0 nearly-empty
+ vptr=((& QXmlStreamEntityResolver::_ZTV24QXmlStreamEntityResolver) + 16)
+
+Class QXmlStreamReader
+ size=8 align=8
+ base size=8 base align=8
+QXmlStreamReader (0x0x7f2344a1e780) 0
+
+Class QXmlStreamWriter
+ size=8 align=8
+ base size=8 base align=8
+QXmlStreamWriter (0x0x7f2344a7a660) 0
+
+Class QNetworkRequest
+ size=8 align=8
+ base size=8 base align=8
+QNetworkRequest (0x0x7f2344a7a840) 0
+
+Class QNetworkCacheMetaData
+ size=8 align=8
+ base size=8 base align=8
+QNetworkCacheMetaData (0x0x7f23447001e0) 0
+
+Class QAbstractNetworkCache::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QAbstractNetworkCache::QPrivateSignal (0x0x7f234475f780) 0 empty
+
+Vtable for QAbstractNetworkCache
+QAbstractNetworkCache::_ZTV21QAbstractNetworkCache: 22 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI21QAbstractNetworkCache)
+16 (int (*)(...))QAbstractNetworkCache::metaObject
+24 (int (*)(...))QAbstractNetworkCache::qt_metacast
+32 (int (*)(...))QAbstractNetworkCache::qt_metacall
+40 0
+48 0
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))__cxa_pure_virtual
+120 (int (*)(...))__cxa_pure_virtual
+128 (int (*)(...))__cxa_pure_virtual
+136 (int (*)(...))__cxa_pure_virtual
+144 (int (*)(...))__cxa_pure_virtual
+152 (int (*)(...))__cxa_pure_virtual
+160 (int (*)(...))__cxa_pure_virtual
+168 (int (*)(...))__cxa_pure_virtual
+
+Class QAbstractNetworkCache
+ size=16 align=8
+ base size=16 base align=8
+QAbstractNetworkCache (0x0x7f234474fb60) 0
+ vptr=((& QAbstractNetworkCache::_ZTV21QAbstractNetworkCache) + 16)
+ QObject (0x0x7f234475f720) 0
+ primary-for QAbstractNetworkCache (0x0x7f234474fb60)
+
+Class QAbstractSocket::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QAbstractSocket::QPrivateSignal (0x0x7f234475f9c0) 0 empty
+
+Vtable for QAbstractSocket
+QAbstractSocket::_ZTV15QAbstractSocket: 41 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI15QAbstractSocket)
+16 (int (*)(...))QAbstractSocket::metaObject
+24 (int (*)(...))QAbstractSocket::qt_metacast
+32 (int (*)(...))QAbstractSocket::qt_metacall
+40 (int (*)(...))QAbstractSocket::~QAbstractSocket
+48 (int (*)(...))QAbstractSocket::~QAbstractSocket
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QAbstractSocket::isSequential
+120 (int (*)(...))QIODevice::open
+128 (int (*)(...))QAbstractSocket::close
+136 (int (*)(...))QIODevice::pos
+144 (int (*)(...))QIODevice::size
+152 (int (*)(...))QIODevice::seek
+160 (int (*)(...))QAbstractSocket::atEnd
+168 (int (*)(...))QIODevice::reset
+176 (int (*)(...))QAbstractSocket::bytesAvailable
+184 (int (*)(...))QAbstractSocket::bytesToWrite
+192 (int (*)(...))QAbstractSocket::canReadLine
+200 (int (*)(...))QAbstractSocket::waitForReadyRead
+208 (int (*)(...))QAbstractSocket::waitForBytesWritten
+216 (int (*)(...))QAbstractSocket::readData
+224 (int (*)(...))QAbstractSocket::readLineData
+232 (int (*)(...))QAbstractSocket::writeData
+240 (int (*)(...))QAbstractSocket::resume
+248 (int (*)(...))QAbstractSocket::connectToHost
+256 (int (*)(...))QAbstractSocket::connectToHost
+264 (int (*)(...))QAbstractSocket::disconnectFromHost
+272 (int (*)(...))QAbstractSocket::setReadBufferSize
+280 (int (*)(...))QAbstractSocket::socketDescriptor
+288 (int (*)(...))QAbstractSocket::setSocketDescriptor
+296 (int (*)(...))QAbstractSocket::setSocketOption
+304 (int (*)(...))QAbstractSocket::socketOption
+312 (int (*)(...))QAbstractSocket::waitForConnected
+320 (int (*)(...))QAbstractSocket::waitForDisconnected
+
+Class QAbstractSocket
+ size=16 align=8
+ base size=16 base align=8
+QAbstractSocket (0x0x7f234474fbc8) 0
+ vptr=((& QAbstractSocket::_ZTV15QAbstractSocket) + 16)
+ QIODevice (0x0x7f234474fc30) 0
+ primary-for QAbstractSocket (0x0x7f234474fbc8)
+ QObject (0x0x7f234475f960) 0
+ primary-for QIODevice (0x0x7f234474fc30)
+
+Class QAuthenticator
+ size=8 align=8
+ base size=8 base align=8
+QAuthenticator (0x0x7f2344805120) 0
+
+Class QDnsDomainNameRecord
+ size=8 align=8
+ base size=8 base align=8
+QDnsDomainNameRecord (0x0x7f23448051e0) 0
+
+Class QDnsHostAddressRecord
+ size=8 align=8
+ base size=8 base align=8
+QDnsHostAddressRecord (0x0x7f234485b360) 0
+
+Class QDnsMailExchangeRecord
+ size=8 align=8
+ base size=8 base align=8
+QDnsMailExchangeRecord (0x0x7f23448a54e0) 0
+
+Class QDnsServiceRecord
+ size=8 align=8
+ base size=8 base align=8
+QDnsServiceRecord (0x0x7f23443f55a0) 0
+
+Class QDnsTextRecord
+ size=8 align=8
+ base size=8 base align=8
+QDnsTextRecord (0x0x7f234443f840) 0
+
+Class QDnsLookup::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QDnsLookup::QPrivateSignal (0x0x7f2344480d80) 0 empty
+
+Vtable for QDnsLookup
+QDnsLookup::_ZTV10QDnsLookup: 14 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI10QDnsLookup)
+16 (int (*)(...))QDnsLookup::metaObject
+24 (int (*)(...))QDnsLookup::qt_metacast
+32 (int (*)(...))QDnsLookup::qt_metacall
+40 (int (*)(...))QDnsLookup::~QDnsLookup
+48 (int (*)(...))QDnsLookup::~QDnsLookup
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+
+Class QDnsLookup
+ size=16 align=8
+ base size=16 base align=8
+QDnsLookup (0x0x7f2344496208) 0
+ vptr=((& QDnsLookup::_ZTV10QDnsLookup) + 16)
+ QObject (0x0x7f2344480d20) 0
+ primary-for QDnsLookup (0x0x7f2344496208)
+
+Class QTcpSocket::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QTcpSocket::QPrivateSignal (0x0x7f23444b1180) 0 empty
+
+Vtable for QTcpSocket
+QTcpSocket::_ZTV10QTcpSocket: 41 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI10QTcpSocket)
+16 (int (*)(...))QTcpSocket::metaObject
+24 (int (*)(...))QTcpSocket::qt_metacast
+32 (int (*)(...))QTcpSocket::qt_metacall
+40 (int (*)(...))QTcpSocket::~QTcpSocket
+48 (int (*)(...))QTcpSocket::~QTcpSocket
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QAbstractSocket::isSequential
+120 (int (*)(...))QIODevice::open
+128 (int (*)(...))QAbstractSocket::close
+136 (int (*)(...))QIODevice::pos
+144 (int (*)(...))QIODevice::size
+152 (int (*)(...))QIODevice::seek
+160 (int (*)(...))QAbstractSocket::atEnd
+168 (int (*)(...))QIODevice::reset
+176 (int (*)(...))QAbstractSocket::bytesAvailable
+184 (int (*)(...))QAbstractSocket::bytesToWrite
+192 (int (*)(...))QAbstractSocket::canReadLine
+200 (int (*)(...))QAbstractSocket::waitForReadyRead
+208 (int (*)(...))QAbstractSocket::waitForBytesWritten
+216 (int (*)(...))QAbstractSocket::readData
+224 (int (*)(...))QAbstractSocket::readLineData
+232 (int (*)(...))QAbstractSocket::writeData
+240 (int (*)(...))QAbstractSocket::resume
+248 (int (*)(...))QAbstractSocket::connectToHost
+256 (int (*)(...))QAbstractSocket::connectToHost
+264 (int (*)(...))QAbstractSocket::disconnectFromHost
+272 (int (*)(...))QAbstractSocket::setReadBufferSize
+280 (int (*)(...))QAbstractSocket::socketDescriptor
+288 (int (*)(...))QAbstractSocket::setSocketDescriptor
+296 (int (*)(...))QAbstractSocket::setSocketOption
+304 (int (*)(...))QAbstractSocket::socketOption
+312 (int (*)(...))QAbstractSocket::waitForConnected
+320 (int (*)(...))QAbstractSocket::waitForDisconnected
+
+Class QTcpSocket
+ size=16 align=8
+ base size=16 base align=8
+QTcpSocket (0x0x7f2344496270) 0
+ vptr=((& QTcpSocket::_ZTV10QTcpSocket) + 16)
+ QAbstractSocket (0x0x7f23444962d8) 0
+ primary-for QTcpSocket (0x0x7f2344496270)
+ QIODevice (0x0x7f2344496340) 0
+ primary-for QAbstractSocket (0x0x7f23444962d8)
+ QObject (0x0x7f23444b1120) 0
+ primary-for QIODevice (0x0x7f2344496340)
+
+Class QSslCertificate
+ size=8 align=8
+ base size=8 base align=8
+QSslCertificate (0x0x7f23444b1a20) 0
+
+Class QSslError
+ size=8 align=8
+ base size=8 base align=8
+QSslError (0x0x7f23445511e0) 0
+
+Class QSslSocket::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QSslSocket::QPrivateSignal (0x0x7f23442193c0) 0 empty
+
+Vtable for QSslSocket
+QSslSocket::_ZTV10QSslSocket: 41 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI10QSslSocket)
+16 (int (*)(...))QSslSocket::metaObject
+24 (int (*)(...))QSslSocket::qt_metacast
+32 (int (*)(...))QSslSocket::qt_metacall
+40 (int (*)(...))QSslSocket::~QSslSocket
+48 (int (*)(...))QSslSocket::~QSslSocket
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QAbstractSocket::isSequential
+120 (int (*)(...))QIODevice::open
+128 (int (*)(...))QSslSocket::close
+136 (int (*)(...))QIODevice::pos
+144 (int (*)(...))QIODevice::size
+152 (int (*)(...))QIODevice::seek
+160 (int (*)(...))QSslSocket::atEnd
+168 (int (*)(...))QIODevice::reset
+176 (int (*)(...))QSslSocket::bytesAvailable
+184 (int (*)(...))QSslSocket::bytesToWrite
+192 (int (*)(...))QSslSocket::canReadLine
+200 (int (*)(...))QSslSocket::waitForReadyRead
+208 (int (*)(...))QSslSocket::waitForBytesWritten
+216 (int (*)(...))QSslSocket::readData
+224 (int (*)(...))QAbstractSocket::readLineData
+232 (int (*)(...))QSslSocket::writeData
+240 (int (*)(...))QSslSocket::resume
+248 (int (*)(...))QSslSocket::connectToHost
+256 (int (*)(...))QAbstractSocket::connectToHost
+264 (int (*)(...))QSslSocket::disconnectFromHost
+272 (int (*)(...))QSslSocket::setReadBufferSize
+280 (int (*)(...))QAbstractSocket::socketDescriptor
+288 (int (*)(...))QSslSocket::setSocketDescriptor
+296 (int (*)(...))QSslSocket::setSocketOption
+304 (int (*)(...))QSslSocket::socketOption
+312 (int (*)(...))QSslSocket::waitForConnected
+320 (int (*)(...))QSslSocket::waitForDisconnected
+
+Class QSslSocket
+ size=16 align=8
+ base size=16 base align=8
+QSslSocket (0x0x7f234420e680) 0
+ vptr=((& QSslSocket::_ZTV10QSslSocket) + 16)
+ QTcpSocket (0x0x7f234420e6e8) 0
+ primary-for QSslSocket (0x0x7f234420e680)
+ QAbstractSocket (0x0x7f234420e750) 0
+ primary-for QTcpSocket (0x0x7f234420e6e8)
+ QIODevice (0x0x7f234420e7b8) 0
+ primary-for QAbstractSocket (0x0x7f234420e750)
+ QObject (0x0x7f2344219360) 0
+ primary-for QIODevice (0x0x7f234420e7b8)
+
+Class QDtlsClientVerifier::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QDtlsClientVerifier::QPrivateSignal (0x0x7f2344219600) 0 empty
+
+Class QDtlsClientVerifier::GeneratorParameters
+ size=16 align=8
+ base size=16 base align=8
+QDtlsClientVerifier::GeneratorParameters (0x0x7f2344219660) 0
+
+Vtable for QDtlsClientVerifier
+QDtlsClientVerifier::_ZTV19QDtlsClientVerifier: 14 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI19QDtlsClientVerifier)
+16 (int (*)(...))QDtlsClientVerifier::metaObject
+24 (int (*)(...))QDtlsClientVerifier::qt_metacast
+32 (int (*)(...))QDtlsClientVerifier::qt_metacall
+40 (int (*)(...))QDtlsClientVerifier::~QDtlsClientVerifier
+48 (int (*)(...))QDtlsClientVerifier::~QDtlsClientVerifier
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+
+Class QDtlsClientVerifier
+ size=16 align=8
+ base size=16 base align=8
+QDtlsClientVerifier (0x0x7f234420e820) 0
+ vptr=((& QDtlsClientVerifier::_ZTV19QDtlsClientVerifier) + 16)
+ QObject (0x0x7f23442195a0) 0
+ primary-for QDtlsClientVerifier (0x0x7f234420e820)
+
+Class QDtls::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QDtls::QPrivateSignal (0x0x7f23442198a0) 0 empty
+
+Vtable for QDtls
+QDtls::_ZTV5QDtls: 14 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI5QDtls)
+16 (int (*)(...))QDtls::metaObject
+24 (int (*)(...))QDtls::qt_metacast
+32 (int (*)(...))QDtls::qt_metacall
+40 (int (*)(...))QDtls::~QDtls
+48 (int (*)(...))QDtls::~QDtls
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+
+Class QDtls
+ size=16 align=8
+ base size=16 base align=8
+QDtls (0x0x7f234420e888) 0
+ vptr=((& QDtls::_ZTV5QDtls) + 16)
+ QObject (0x0x7f2344219840) 0
+ primary-for QDtls (0x0x7f234420e888)
+
+Class QIPv6Address
+ size=16 align=1
+ base size=16 base align=1
+QIPv6Address (0x0x7f2344219ae0) 0
+
+Class QHostAddress
+ size=8 align=8
+ base size=8 base align=8
+QHostAddress (0x0x7f2344219c00) 0
+
+Class QHostInfo
+ size=8 align=8
+ base size=8 base align=8
+QHostInfo (0x0x7f234431f9c0) 0
+
+Class QHstsPolicy
+ size=8 align=8
+ base size=8 base align=8
+QHstsPolicy (0x0x7f2343fef7e0) 0
+
+Class QHttpPart
+ size=8 align=8
+ base size=8 base align=8
+QHttpPart (0x0x7f234407e420) 0
+
+Class QHttpMultiPart::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QHttpMultiPart::QPrivateSignal (0x0x7f23440cf5a0) 0 empty
+
+Vtable for QHttpMultiPart
+QHttpMultiPart::_ZTV14QHttpMultiPart: 14 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI14QHttpMultiPart)
+16 (int (*)(...))QHttpMultiPart::metaObject
+24 (int (*)(...))QHttpMultiPart::qt_metacast
+32 (int (*)(...))QHttpMultiPart::qt_metacall
+40 (int (*)(...))QHttpMultiPart::~QHttpMultiPart
+48 (int (*)(...))QHttpMultiPart::~QHttpMultiPart
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+
+Class QHttpMultiPart
+ size=16 align=8
+ base size=16 base align=8
+QHttpMultiPart (0x0x7f23440cc680) 0
+ vptr=((& QHttpMultiPart::_ZTV14QHttpMultiPart) + 16)
+ QObject (0x0x7f23440cf540) 0
+ primary-for QHttpMultiPart (0x0x7f23440cc680)
+
+Class QLocalServer::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QLocalServer::QPrivateSignal (0x0x7f23440cf7e0) 0 empty
+
+Vtable for QLocalServer
+QLocalServer::_ZTV12QLocalServer: 17 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI12QLocalServer)
+16 (int (*)(...))QLocalServer::metaObject
+24 (int (*)(...))QLocalServer::qt_metacast
+32 (int (*)(...))QLocalServer::qt_metacall
+40 (int (*)(...))QLocalServer::~QLocalServer
+48 (int (*)(...))QLocalServer::~QLocalServer
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QLocalServer::hasPendingConnections
+120 (int (*)(...))QLocalServer::nextPendingConnection
+128 (int (*)(...))QLocalServer::incomingConnection
+
+Class QLocalServer
+ size=16 align=8
+ base size=16 base align=8
+QLocalServer (0x0x7f23440cc6e8) 0
+ vptr=((& QLocalServer::_ZTV12QLocalServer) + 16)
+ QObject (0x0x7f23440cf780) 0
+ primary-for QLocalServer (0x0x7f23440cc6e8)
+
+Class QLocalSocket::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QLocalSocket::QPrivateSignal (0x0x7f234411c2a0) 0 empty
+
+Vtable for QLocalSocket
+QLocalSocket::_ZTV12QLocalSocket: 30 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI12QLocalSocket)
+16 (int (*)(...))QLocalSocket::metaObject
+24 (int (*)(...))QLocalSocket::qt_metacast
+32 (int (*)(...))QLocalSocket::qt_metacall
+40 (int (*)(...))QLocalSocket::~QLocalSocket
+48 (int (*)(...))QLocalSocket::~QLocalSocket
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QLocalSocket::isSequential
+120 (int (*)(...))QLocalSocket::open
+128 (int (*)(...))QLocalSocket::close
+136 (int (*)(...))QIODevice::pos
+144 (int (*)(...))QIODevice::size
+152 (int (*)(...))QIODevice::seek
+160 (int (*)(...))QIODevice::atEnd
+168 (int (*)(...))QIODevice::reset
+176 (int (*)(...))QLocalSocket::bytesAvailable
+184 (int (*)(...))QLocalSocket::bytesToWrite
+192 (int (*)(...))QLocalSocket::canReadLine
+200 (int (*)(...))QLocalSocket::waitForReadyRead
+208 (int (*)(...))QLocalSocket::waitForBytesWritten
+216 (int (*)(...))QLocalSocket::readData
+224 (int (*)(...))QIODevice::readLineData
+232 (int (*)(...))QLocalSocket::writeData
+
+Class QLocalSocket
+ size=16 align=8
+ base size=16 base align=8
+QLocalSocket (0x0x7f23440cc888) 0
+ vptr=((& QLocalSocket::_ZTV12QLocalSocket) + 16)
+ QIODevice (0x0x7f23440cc8f0) 0
+ primary-for QLocalSocket (0x0x7f23440cc888)
+ QObject (0x0x7f234411c240) 0
+ primary-for QIODevice (0x0x7f23440cc8f0)
+
+Class QSslConfiguration
+ size=8 align=8
+ base size=8 base align=8
+QSslConfiguration (0x0x7f234411c480) 0
+
+Class QSslPreSharedKeyAuthenticator
+ size=8 align=8
+ base size=8 base align=8
+QSslPreSharedKeyAuthenticator (0x0x7f23441add20) 0
+
+Class QNetworkAccessManager::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QNetworkAccessManager::QPrivateSignal (0x0x7f2343e29300) 0 empty
+
+Vtable for QNetworkAccessManager
+QNetworkAccessManager::_ZTV21QNetworkAccessManager: 15 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI21QNetworkAccessManager)
+16 (int (*)(...))QNetworkAccessManager::metaObject
+24 (int (*)(...))QNetworkAccessManager::qt_metacast
+32 (int (*)(...))QNetworkAccessManager::qt_metacall
+40 (int (*)(...))QNetworkAccessManager::~QNetworkAccessManager
+48 (int (*)(...))QNetworkAccessManager::~QNetworkAccessManager
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QNetworkAccessManager::createRequest
+
+Class QNetworkAccessManager
+ size=16 align=8
+ base size=16 base align=8
+QNetworkAccessManager (0x0x7f2343e168f0) 0
+ vptr=((& QNetworkAccessManager::_ZTV21QNetworkAccessManager) + 16)
+ QObject (0x0x7f2343e292a0) 0
+ primary-for QNetworkAccessManager (0x0x7f2343e168f0)
+
+Class QNetworkConfiguration
+ size=8 align=8
+ base size=8 base align=8
+QNetworkConfiguration (0x0x7f2343e295a0) 0
+
+Class QNetworkConfigurationManager::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QNetworkConfigurationManager::QPrivateSignal (0x0x7f2343ea49c0) 0 empty
+
+Vtable for QNetworkConfigurationManager
+QNetworkConfigurationManager::_ZTV28QNetworkConfigurationManager: 14 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI28QNetworkConfigurationManager)
+16 (int (*)(...))QNetworkConfigurationManager::metaObject
+24 (int (*)(...))QNetworkConfigurationManager::qt_metacast
+32 (int (*)(...))QNetworkConfigurationManager::qt_metacall
+40 (int (*)(...))QNetworkConfigurationManager::~QNetworkConfigurationManager
+48 (int (*)(...))QNetworkConfigurationManager::~QNetworkConfigurationManager
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+
+Class QNetworkConfigurationManager
+ size=16 align=8
+ base size=16 base align=8
+QNetworkConfigurationManager (0x0x7f2343e93d00) 0
+ vptr=((& QNetworkConfigurationManager::_ZTV28QNetworkConfigurationManager) + 16)
+ QObject (0x0x7f2343ea4960) 0
+ primary-for QNetworkConfigurationManager (0x0x7f2343e93d00)
+
+Class QNetworkCookie
+ size=8 align=8
+ base size=8 base align=8
+QNetworkCookie (0x0x7f2343ef5540) 0
+
+Class QNetworkCookieJar::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QNetworkCookieJar::QPrivateSignal (0x0x7f2343f6d060) 0 empty
+
+Vtable for QNetworkCookieJar
+QNetworkCookieJar::_ZTV17QNetworkCookieJar: 20 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI17QNetworkCookieJar)
+16 (int (*)(...))QNetworkCookieJar::metaObject
+24 (int (*)(...))QNetworkCookieJar::qt_metacast
+32 (int (*)(...))QNetworkCookieJar::qt_metacall
+40 (int (*)(...))QNetworkCookieJar::~QNetworkCookieJar
+48 (int (*)(...))QNetworkCookieJar::~QNetworkCookieJar
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QNetworkCookieJar::cookiesForUrl
+120 (int (*)(...))QNetworkCookieJar::setCookiesFromUrl
+128 (int (*)(...))QNetworkCookieJar::insertCookie
+136 (int (*)(...))QNetworkCookieJar::updateCookie
+144 (int (*)(...))QNetworkCookieJar::deleteCookie
+152 (int (*)(...))QNetworkCookieJar::validateCookie
+
+Class QNetworkCookieJar
+ size=16 align=8
+ base size=16 base align=8
+QNetworkCookieJar (0x0x7f2343f59750) 0
+ vptr=((& QNetworkCookieJar::_ZTV17QNetworkCookieJar) + 16)
+ QObject (0x0x7f2343f6d000) 0
+ primary-for QNetworkCookieJar (0x0x7f2343f59750)
+
+Class QNetworkDatagram
+ size=8 align=8
+ base size=8 base align=8
+QNetworkDatagram (0x0x7f2343f6d240) 0
+
+Class QNetworkDiskCache::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QNetworkDiskCache::QPrivateSignal (0x0x7f2343c24d80) 0 empty
+
+Vtable for QNetworkDiskCache
+QNetworkDiskCache::_ZTV17QNetworkDiskCache: 23 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI17QNetworkDiskCache)
+16 (int (*)(...))QNetworkDiskCache::metaObject
+24 (int (*)(...))QNetworkDiskCache::qt_metacast
+32 (int (*)(...))QNetworkDiskCache::qt_metacall
+40 (int (*)(...))QNetworkDiskCache::~QNetworkDiskCache
+48 (int (*)(...))QNetworkDiskCache::~QNetworkDiskCache
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QNetworkDiskCache::metaData
+120 (int (*)(...))QNetworkDiskCache::updateMetaData
+128 (int (*)(...))QNetworkDiskCache::data
+136 (int (*)(...))QNetworkDiskCache::remove
+144 (int (*)(...))QNetworkDiskCache::cacheSize
+152 (int (*)(...))QNetworkDiskCache::prepare
+160 (int (*)(...))QNetworkDiskCache::insert
+168 (int (*)(...))QNetworkDiskCache::clear
+176 (int (*)(...))QNetworkDiskCache::expire
+
+Class QNetworkDiskCache
+ size=16 align=8
+ base size=16 base align=8
+QNetworkDiskCache (0x0x7f2343c32618) 0
+ vptr=((& QNetworkDiskCache::_ZTV17QNetworkDiskCache) + 16)
+ QAbstractNetworkCache (0x0x7f2343c32680) 0
+ primary-for QNetworkDiskCache (0x0x7f2343c32618)
+ QObject (0x0x7f2343c24d20) 0
+ primary-for QAbstractNetworkCache (0x0x7f2343c32680)
+
+Class QNetworkAddressEntry
+ size=8 align=8
+ base size=8 base align=8
+QNetworkAddressEntry (0x0x7f2343c24f60) 0
+
+Class QNetworkInterface
+ size=8 align=8
+ base size=8 base align=8
+QNetworkInterface (0x0x7f2343cf8f00) 0
+
+Class QNetworkProxyQuery
+ size=8 align=8
+ base size=8 base align=8
+QNetworkProxyQuery (0x0x7f2343d76de0) 0
+
+Class QNetworkProxy
+ size=8 align=8
+ base size=8 base align=8
+QNetworkProxy (0x0x7f2343a09300) 0
+
+Vtable for QNetworkProxyFactory
+QNetworkProxyFactory::_ZTV20QNetworkProxyFactory: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI20QNetworkProxyFactory)
+16 0
+24 0
+32 (int (*)(...))__cxa_pure_virtual
+
+Class QNetworkProxyFactory
+ size=8 align=8
+ base size=8 base align=8
+QNetworkProxyFactory (0x0x7f2343a99060) 0 nearly-empty
+ vptr=((& QNetworkProxyFactory::_ZTV20QNetworkProxyFactory) + 16)
+
+Class QNetworkReply::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QNetworkReply::QPrivateSignal (0x0x7f2343a99300) 0 empty
+
+Vtable for QNetworkReply
+QNetworkReply::_ZTV13QNetworkReply: 36 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI13QNetworkReply)
+16 (int (*)(...))QNetworkReply::metaObject
+24 (int (*)(...))QNetworkReply::qt_metacast
+32 (int (*)(...))QNetworkReply::qt_metacall
+40 0
+48 0
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QNetworkReply::isSequential
+120 (int (*)(...))QIODevice::open
+128 (int (*)(...))QNetworkReply::close
+136 (int (*)(...))QIODevice::pos
+144 (int (*)(...))QIODevice::size
+152 (int (*)(...))QIODevice::seek
+160 (int (*)(...))QIODevice::atEnd
+168 (int (*)(...))QIODevice::reset
+176 (int (*)(...))QIODevice::bytesAvailable
+184 (int (*)(...))QIODevice::bytesToWrite
+192 (int (*)(...))QIODevice::canReadLine
+200 (int (*)(...))QIODevice::waitForReadyRead
+208 (int (*)(...))QIODevice::waitForBytesWritten
+216 (int (*)(...))__cxa_pure_virtual
+224 (int (*)(...))QIODevice::readLineData
+232 (int (*)(...))QNetworkReply::writeData
+240 (int (*)(...))QNetworkReply::setReadBufferSize
+248 (int (*)(...))__cxa_pure_virtual
+256 (int (*)(...))QNetworkReply::ignoreSslErrors
+264 (int (*)(...))QNetworkReply::sslConfigurationImplementation
+272 (int (*)(...))QNetworkReply::setSslConfigurationImplementation
+280 (int (*)(...))QNetworkReply::ignoreSslErrorsImplementation
+
+Class QNetworkReply
+ size=16 align=8
+ base size=16 base align=8
+QNetworkReply (0x0x7f2343a6e208) 0
+ vptr=((& QNetworkReply::_ZTV13QNetworkReply) + 16)
+ QIODevice (0x0x7f2343a6e270) 0
+ primary-for QNetworkReply (0x0x7f2343a6e208)
+ QObject (0x0x7f2343a992a0) 0
+ primary-for QIODevice (0x0x7f2343a6e270)
+
+Class QNetworkSession::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QNetworkSession::QPrivateSignal (0x0x7f2343a997e0) 0 empty
+
+Vtable for QNetworkSession
+QNetworkSession::_ZTV15QNetworkSession: 14 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI15QNetworkSession)
+16 (int (*)(...))QNetworkSession::metaObject
+24 (int (*)(...))QNetworkSession::qt_metacast
+32 (int (*)(...))QNetworkSession::qt_metacall
+40 (int (*)(...))QNetworkSession::~QNetworkSession
+48 (int (*)(...))QNetworkSession::~QNetworkSession
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QNetworkSession::connectNotify
+104 (int (*)(...))QNetworkSession::disconnectNotify
+
+Class QNetworkSession
+ size=24 align=8
+ base size=24 base align=8
+QNetworkSession (0x0x7f2343a6e2d8) 0
+ vptr=((& QNetworkSession::_ZTV15QNetworkSession) + 16)
+ QObject (0x0x7f2343a99780) 0
+ primary-for QNetworkSession (0x0x7f2343a6e2d8)
+
+Class QOcspResponse
+ size=8 align=8
+ base size=8 base align=8
+QOcspResponse (0x0x7f2343b04060) 0
+
+Class QTcpServer::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QTcpServer::QPrivateSignal (0x0x7f2343b558a0) 0 empty
+
+Vtable for QTcpServer
+QTcpServer::_ZTV10QTcpServer: 17 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI10QTcpServer)
+16 (int (*)(...))QTcpServer::metaObject
+24 (int (*)(...))QTcpServer::qt_metacast
+32 (int (*)(...))QTcpServer::qt_metacall
+40 (int (*)(...))QTcpServer::~QTcpServer
+48 (int (*)(...))QTcpServer::~QTcpServer
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QTcpServer::hasPendingConnections
+120 (int (*)(...))QTcpServer::nextPendingConnection
+128 (int (*)(...))QTcpServer::incomingConnection
+
+Class QTcpServer
+ size=16 align=8
+ base size=16 base align=8
+QTcpServer (0x0x7f2343b49b60) 0
+ vptr=((& QTcpServer::_ZTV10QTcpServer) + 16)
+ QObject (0x0x7f2343b55840) 0
+ primary-for QTcpServer (0x0x7f2343b49b60)
+
+Class QSslCertificateExtension
+ size=8 align=8
+ base size=8 base align=8
+QSslCertificateExtension (0x0x7f2343b55a80) 0
+
+Class QSslCipher
+ size=8 align=8
+ base size=8 base align=8
+QSslCipher (0x0x7f2343bbb840) 0
+
+Class QSslDiffieHellmanParameters
+ size=8 align=8
+ base size=8 base align=8
+QSslDiffieHellmanParameters (0x0x7f234387a900) 0
+
+Class QSslEllipticCurve
+ size=4 align=4
+ base size=4 base align=4
+QSslEllipticCurve (0x0x7f234393f660) 0
+
+Class QSslKey
+ size=8 align=8
+ base size=8 base align=8
+QSslKey (0x0x7f23439a5000) 0
+
+Class QUdpSocket::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QUdpSocket::QPrivateSignal (0x0x7f23435fb300) 0 empty
+
+Vtable for QUdpSocket
+QUdpSocket::_ZTV10QUdpSocket: 41 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI10QUdpSocket)
+16 (int (*)(...))QUdpSocket::metaObject
+24 (int (*)(...))QUdpSocket::qt_metacast
+32 (int (*)(...))QUdpSocket::qt_metacall
+40 (int (*)(...))QUdpSocket::~QUdpSocket
+48 (int (*)(...))QUdpSocket::~QUdpSocket
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QAbstractSocket::isSequential
+120 (int (*)(...))QIODevice::open
+128 (int (*)(...))QAbstractSocket::close
+136 (int (*)(...))QIODevice::pos
+144 (int (*)(...))QIODevice::size
+152 (int (*)(...))QIODevice::seek
+160 (int (*)(...))QAbstractSocket::atEnd
+168 (int (*)(...))QIODevice::reset
+176 (int (*)(...))QAbstractSocket::bytesAvailable
+184 (int (*)(...))QAbstractSocket::bytesToWrite
+192 (int (*)(...))QAbstractSocket::canReadLine
+200 (int (*)(...))QAbstractSocket::waitForReadyRead
+208 (int (*)(...))QAbstractSocket::waitForBytesWritten
+216 (int (*)(...))QAbstractSocket::readData
+224 (int (*)(...))QAbstractSocket::readLineData
+232 (int (*)(...))QAbstractSocket::writeData
+240 (int (*)(...))QAbstractSocket::resume
+248 (int (*)(...))QAbstractSocket::connectToHost
+256 (int (*)(...))QAbstractSocket::connectToHost
+264 (int (*)(...))QAbstractSocket::disconnectFromHost
+272 (int (*)(...))QAbstractSocket::setReadBufferSize
+280 (int (*)(...))QAbstractSocket::socketDescriptor
+288 (int (*)(...))QAbstractSocket::setSocketDescriptor
+296 (int (*)(...))QAbstractSocket::setSocketOption
+304 (int (*)(...))QAbstractSocket::socketOption
+312 (int (*)(...))QAbstractSocket::waitForConnected
+320 (int (*)(...))QAbstractSocket::waitForDisconnected
+
+Class QUdpSocket
+ size=16 align=8
+ base size=16 base align=8
+QUdpSocket (0x0x7f23435fc0d0) 0
+ vptr=((& QUdpSocket::_ZTV10QUdpSocket) + 16)
+ QAbstractSocket (0x0x7f23435fc138) 0
+ primary-for QUdpSocket (0x0x7f23435fc0d0)
+ QIODevice (0x0x7f23435fc1a0) 0
+ primary-for QAbstractSocket (0x0x7f23435fc138)
+ QObject (0x0x7f23435fb2a0) 0
+ primary-for QIODevice (0x0x7f23435fc1a0)
+
+Class QRemoteObjectSourceLocationInfo
+ size=16 align=8
+ base size=16 base align=8
+QRemoteObjectSourceLocationInfo (0x0x7f23435fb540) 0
+
+Class QAbstractItemModelReplica::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QAbstractItemModelReplica::QPrivateSignal (0x0x7f23436e85a0) 0 empty
+
+Vtable for QAbstractItemModelReplica
+QAbstractItemModelReplica::_ZTV25QAbstractItemModelReplica: 48 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI25QAbstractItemModelReplica)
+16 (int (*)(...))QAbstractItemModelReplica::metaObject
+24 (int (*)(...))QAbstractItemModelReplica::qt_metacast
+32 (int (*)(...))QAbstractItemModelReplica::qt_metacall
+40 (int (*)(...))QAbstractItemModelReplica::~QAbstractItemModelReplica
+48 (int (*)(...))QAbstractItemModelReplica::~QAbstractItemModelReplica
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QAbstractItemModelReplica::index
+120 (int (*)(...))QAbstractItemModelReplica::parent
+128 (int (*)(...))QAbstractItemModel::sibling
+136 (int (*)(...))QAbstractItemModelReplica::rowCount
+144 (int (*)(...))QAbstractItemModelReplica::columnCount
+152 (int (*)(...))QAbstractItemModelReplica::hasChildren
+160 (int (*)(...))QAbstractItemModelReplica::data
+168 (int (*)(...))QAbstractItemModelReplica::setData
+176 (int (*)(...))QAbstractItemModelReplica::headerData
+184 (int (*)(...))QAbstractItemModel::setHeaderData
+192 (int (*)(...))QAbstractItemModel::itemData
+200 (int (*)(...))QAbstractItemModel::setItemData
+208 (int (*)(...))QAbstractItemModel::mimeTypes
+216 (int (*)(...))QAbstractItemModel::mimeData
+224 (int (*)(...))QAbstractItemModel::canDropMimeData
+232 (int (*)(...))QAbstractItemModel::dropMimeData
+240 (int (*)(...))QAbstractItemModel::supportedDropActions
+248 (int (*)(...))QAbstractItemModel::supportedDragActions
+256 (int (*)(...))QAbstractItemModel::insertRows
+264 (int (*)(...))QAbstractItemModel::insertColumns
+272 (int (*)(...))QAbstractItemModel::removeRows
+280 (int (*)(...))QAbstractItemModel::removeColumns
+288 (int (*)(...))QAbstractItemModel::moveRows
+296 (int (*)(...))QAbstractItemModel::moveColumns
+304 (int (*)(...))QAbstractItemModel::fetchMore
+312 (int (*)(...))QAbstractItemModel::canFetchMore
+320 (int (*)(...))QAbstractItemModelReplica::flags
+328 (int (*)(...))QAbstractItemModel::sort
+336 (int (*)(...))QAbstractItemModel::buddy
+344 (int (*)(...))QAbstractItemModel::match
+352 (int (*)(...))QAbstractItemModel::span
+360 (int (*)(...))QAbstractItemModelReplica::roleNames
+368 (int (*)(...))QAbstractItemModel::submit
+376 (int (*)(...))QAbstractItemModel::revert
+
+Class QAbstractItemModelReplica
+ size=24 align=8
+ base size=24 base align=8
+QAbstractItemModelReplica (0x0x7f23436438f0) 0
+ vptr=((& QAbstractItemModelReplica::_ZTV25QAbstractItemModelReplica) + 16)
+ QAbstractItemModel (0x0x7f2343643958) 0
+ primary-for QAbstractItemModelReplica (0x0x7f23436438f0)
+ QObject (0x0x7f23436e8540) 0
+ primary-for QAbstractItemModel (0x0x7f2343643958)
+
+Class ModelIndex
+ size=8 align=4
+ base size=8 base align=4
+ModelIndex (0x0x7f23436e8720) 0
+
+Class IndexValuePair
+ size=40 align=8
+ base size=40 base align=8
+IndexValuePair (0x0x7f2343726000) 0
+
+Class DataEntries
+ size=8 align=8
+ base size=8 base align=8
+DataEntries (0x0x7f23437aa840) 0
+
+Class MetaAndDataEntries
+ size=24 align=8
+ base size=24 base align=8
+MetaAndDataEntries (0x0x7f23437b8d68) 0
+ DataEntries (0x0x7f23433d32a0) 0
+
+Class QRemoteObjectReplica::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QRemoteObjectReplica::QPrivateSignal (0x0x7f23434d85a0) 0 empty
+
+Vtable for QRemoteObjectReplica
+QRemoteObjectReplica::_ZTV20QRemoteObjectReplica: 16 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI20QRemoteObjectReplica)
+16 (int (*)(...))QRemoteObjectReplica::metaObject
+24 (int (*)(...))QRemoteObjectReplica::qt_metacast
+32 (int (*)(...))QRemoteObjectReplica::qt_metacall
+40 (int (*)(...))QRemoteObjectReplica::~QRemoteObjectReplica
+48 (int (*)(...))QRemoteObjectReplica::~QRemoteObjectReplica
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QRemoteObjectReplica::setNode
+120 (int (*)(...))QRemoteObjectReplica::initialize
+
+Class QRemoteObjectReplica
+ size=32 align=8
+ base size=32 base align=8
+QRemoteObjectReplica (0x0x7f2343435f70) 0
+ vptr=((& QRemoteObjectReplica::_ZTV20QRemoteObjectReplica) + 16)
+ QObject (0x0x7f23434d8540) 0
+ primary-for QRemoteObjectReplica (0x0x7f2343435f70)
+
+Vtable for QRemoteObjectDynamicReplica
+QRemoteObjectDynamicReplica::_ZTV27QRemoteObjectDynamicReplica: 16 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI27QRemoteObjectDynamicReplica)
+16 (int (*)(...))QRemoteObjectDynamicReplica::metaObject
+24 (int (*)(...))QRemoteObjectDynamicReplica::qt_metacast
+32 (int (*)(...))QRemoteObjectDynamicReplica::qt_metacall
+40 (int (*)(...))QRemoteObjectDynamicReplica::~QRemoteObjectDynamicReplica
+48 (int (*)(...))QRemoteObjectDynamicReplica::~QRemoteObjectDynamicReplica
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QRemoteObjectReplica::setNode
+120 (int (*)(...))QRemoteObjectReplica::initialize
+
+Class QRemoteObjectDynamicReplica
+ size=32 align=8
+ base size=32 base align=8
+QRemoteObjectDynamicReplica (0x0x7f234351f000) 0
+ vptr=((& QRemoteObjectDynamicReplica::_ZTV27QRemoteObjectDynamicReplica) + 16)
+ QRemoteObjectReplica (0x0x7f234351f068) 0
+ primary-for QRemoteObjectDynamicReplica (0x0x7f234351f000)
+ QObject (0x0x7f23434d87e0) 0
+ primary-for QRemoteObjectReplica (0x0x7f234351f068)
+
+Class QRemoteObjectRegistry::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QRemoteObjectRegistry::QPrivateSignal (0x0x7f23434d88a0) 0 empty
+
+Vtable for QRemoteObjectRegistry
+QRemoteObjectRegistry::_ZTV21QRemoteObjectRegistry: 16 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI21QRemoteObjectRegistry)
+16 (int (*)(...))QRemoteObjectRegistry::metaObject
+24 (int (*)(...))QRemoteObjectRegistry::qt_metacast
+32 (int (*)(...))QRemoteObjectRegistry::qt_metacall
+40 (int (*)(...))QRemoteObjectRegistry::~QRemoteObjectRegistry
+48 (int (*)(...))QRemoteObjectRegistry::~QRemoteObjectRegistry
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QRemoteObjectReplica::setNode
+120 (int (*)(...))QRemoteObjectRegistry::initialize
+
+Class QRemoteObjectRegistry
+ size=32 align=8
+ base size=32 base align=8
+QRemoteObjectRegistry (0x0x7f234351f0d0) 0
+ vptr=((& QRemoteObjectRegistry::_ZTV21QRemoteObjectRegistry) + 16)
+ QRemoteObjectReplica (0x0x7f234351f138) 0
+ primary-for QRemoteObjectRegistry (0x0x7f234351f0d0)
+ QObject (0x0x7f23434d8840) 0
+ primary-for QRemoteObjectReplica (0x0x7f234351f138)
+
+Class QRemoteObjectAbstractPersistedStore::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QRemoteObjectAbstractPersistedStore::QPrivateSignal (0x0x7f23434d8ae0) 0 empty
+
+Vtable for QRemoteObjectAbstractPersistedStore
+QRemoteObjectAbstractPersistedStore::_ZTV35QRemoteObjectAbstractPersistedStore: 16 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI35QRemoteObjectAbstractPersistedStore)
+16 (int (*)(...))QRemoteObjectAbstractPersistedStore::metaObject
+24 (int (*)(...))QRemoteObjectAbstractPersistedStore::qt_metacast
+32 (int (*)(...))QRemoteObjectAbstractPersistedStore::qt_metacall
+40 0
+48 0
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))__cxa_pure_virtual
+120 (int (*)(...))__cxa_pure_virtual
+
+Class QRemoteObjectAbstractPersistedStore
+ size=16 align=8
+ base size=16 base align=8
+QRemoteObjectAbstractPersistedStore (0x0x7f234351f1a0) 0
+ vptr=((& QRemoteObjectAbstractPersistedStore::_ZTV35QRemoteObjectAbstractPersistedStore) + 16)
+ QObject (0x0x7f23434d8a80) 0
+ primary-for QRemoteObjectAbstractPersistedStore (0x0x7f234351f1a0)
+
+Class QRemoteObjectNode::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QRemoteObjectNode::QPrivateSignal (0x0x7f23434d8d80) 0 empty
+
+Vtable for QRemoteObjectNode
+QRemoteObjectNode::_ZTV17QRemoteObjectNode: 16 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI17QRemoteObjectNode)
+16 (int (*)(...))QRemoteObjectNode::metaObject
+24 (int (*)(...))QRemoteObjectNode::qt_metacast
+32 (int (*)(...))QRemoteObjectNode::qt_metacall
+40 (int (*)(...))QRemoteObjectNode::~QRemoteObjectNode
+48 (int (*)(...))QRemoteObjectNode::~QRemoteObjectNode
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QRemoteObjectNode::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QRemoteObjectNode::setName
+120 (int (*)(...))QRemoteObjectNode::setRegistryUrl
+
+Class QRemoteObjectNode
+ size=16 align=8
+ base size=16 base align=8
+QRemoteObjectNode (0x0x7f234351f208) 0
+ vptr=((& QRemoteObjectNode::_ZTV17QRemoteObjectNode) + 16)
+ QObject (0x0x7f23434d8d20) 0
+ primary-for QRemoteObjectNode (0x0x7f234351f208)
+
+Class QRemoteObjectHostBase::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QRemoteObjectHostBase::QPrivateSignal (0x0x7f234355a180) 0 empty
+
+Vtable for QRemoteObjectHostBase
+QRemoteObjectHostBase::_ZTV21QRemoteObjectHostBase: 18 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI21QRemoteObjectHostBase)
+16 (int (*)(...))QRemoteObjectHostBase::metaObject
+24 (int (*)(...))QRemoteObjectHostBase::qt_metacast
+32 (int (*)(...))QRemoteObjectHostBase::qt_metacall
+40 (int (*)(...))QRemoteObjectHostBase::~QRemoteObjectHostBase
+48 (int (*)(...))QRemoteObjectHostBase::~QRemoteObjectHostBase
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QRemoteObjectNode::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QRemoteObjectHostBase::setName
+120 (int (*)(...))QRemoteObjectNode::setRegistryUrl
+128 (int (*)(...))QRemoteObjectHostBase::hostUrl
+136 (int (*)(...))QRemoteObjectHostBase::setHostUrl
+
+Class QRemoteObjectHostBase
+ size=16 align=8
+ base size=16 base align=8
+QRemoteObjectHostBase (0x0x7f234351f270) 0
+ vptr=((& QRemoteObjectHostBase::_ZTV21QRemoteObjectHostBase) + 16)
+ QRemoteObjectNode (0x0x7f234351f2d8) 0
+ primary-for QRemoteObjectHostBase (0x0x7f234351f270)
+ QObject (0x0x7f234355a120) 0
+ primary-for QRemoteObjectNode (0x0x7f234351f2d8)
+
+Class QRemoteObjectHost::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QRemoteObjectHost::QPrivateSignal (0x0x7f23431e73c0) 0 empty
+
+Vtable for QRemoteObjectHost
+QRemoteObjectHost::_ZTV17QRemoteObjectHost: 18 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI17QRemoteObjectHost)
+16 (int (*)(...))QRemoteObjectHost::metaObject
+24 (int (*)(...))QRemoteObjectHost::qt_metacast
+32 (int (*)(...))QRemoteObjectHost::qt_metacall
+40 (int (*)(...))QRemoteObjectHost::~QRemoteObjectHost
+48 (int (*)(...))QRemoteObjectHost::~QRemoteObjectHost
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QRemoteObjectNode::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QRemoteObjectHostBase::setName
+120 (int (*)(...))QRemoteObjectNode::setRegistryUrl
+128 (int (*)(...))QRemoteObjectHost::hostUrl
+136 (int (*)(...))QRemoteObjectHost::setHostUrl
+
+Class QRemoteObjectHost
+ size=16 align=8
+ base size=16 base align=8
+QRemoteObjectHost (0x0x7f23431cfb60) 0
+ vptr=((& QRemoteObjectHost::_ZTV17QRemoteObjectHost) + 16)
+ QRemoteObjectHostBase (0x0x7f23431cfbc8) 0
+ primary-for QRemoteObjectHost (0x0x7f23431cfb60)
+ QRemoteObjectNode (0x0x7f23431cfc30) 0
+ primary-for QRemoteObjectHostBase (0x0x7f23431cfbc8)
+ QObject (0x0x7f23431e7360) 0
+ primary-for QRemoteObjectNode (0x0x7f23431cfc30)
+
+Class QRemoteObjectRegistryHost::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QRemoteObjectRegistryHost::QPrivateSignal (0x0x7f23431e7600) 0 empty
+
+Vtable for QRemoteObjectRegistryHost
+QRemoteObjectRegistryHost::_ZTV25QRemoteObjectRegistryHost: 18 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI25QRemoteObjectRegistryHost)
+16 (int (*)(...))QRemoteObjectRegistryHost::metaObject
+24 (int (*)(...))QRemoteObjectRegistryHost::qt_metacast
+32 (int (*)(...))QRemoteObjectRegistryHost::qt_metacall
+40 (int (*)(...))QRemoteObjectRegistryHost::~QRemoteObjectRegistryHost
+48 (int (*)(...))QRemoteObjectRegistryHost::~QRemoteObjectRegistryHost
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QRemoteObjectNode::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QRemoteObjectHostBase::setName
+120 (int (*)(...))QRemoteObjectRegistryHost::setRegistryUrl
+128 (int (*)(...))QRemoteObjectHostBase::hostUrl
+136 (int (*)(...))QRemoteObjectHostBase::setHostUrl
+
+Class QRemoteObjectRegistryHost
+ size=16 align=8
+ base size=16 base align=8
+QRemoteObjectRegistryHost (0x0x7f23431cfc98) 0
+ vptr=((& QRemoteObjectRegistryHost::_ZTV25QRemoteObjectRegistryHost) + 16)
+ QRemoteObjectHostBase (0x0x7f23431cfd00) 0
+ primary-for QRemoteObjectRegistryHost (0x0x7f23431cfc98)
+ QRemoteObjectNode (0x0x7f23431cfd68) 0
+ primary-for QRemoteObjectHostBase (0x0x7f23431cfd00)
+ QObject (0x0x7f23431e75a0) 0
+ primary-for QRemoteObjectNode (0x0x7f23431cfd68)
+
+Class QRemoteObjectPendingCall
+ size=8 align=8
+ base size=8 base align=8
+QRemoteObjectPendingCall (0x0x7f23431e77e0) 0
+
+Class QRemoteObjectPendingCallWatcher::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QRemoteObjectPendingCallWatcher::QPrivateSignal (0x0x7f23431e7b40) 0 empty
+
+Vtable for QRemoteObjectPendingCallWatcher
+QRemoteObjectPendingCallWatcher::_ZTV31QRemoteObjectPendingCallWatcher: 14 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI31QRemoteObjectPendingCallWatcher)
+16 (int (*)(...))QRemoteObjectPendingCallWatcher::metaObject
+24 (int (*)(...))QRemoteObjectPendingCallWatcher::qt_metacast
+32 (int (*)(...))QRemoteObjectPendingCallWatcher::qt_metacall
+40 (int (*)(...))QRemoteObjectPendingCallWatcher::~QRemoteObjectPendingCallWatcher
+48 (int (*)(...))QRemoteObjectPendingCallWatcher::~QRemoteObjectPendingCallWatcher
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+
+Class QRemoteObjectPendingCallWatcher
+ size=24 align=8
+ base size=24 base align=8
+QRemoteObjectPendingCallWatcher (0x0x7f23432220e0) 0
+ vptr=((& QRemoteObjectPendingCallWatcher::_ZTV31QRemoteObjectPendingCallWatcher) + 16)
+ QObject (0x0x7f23431e7a80) 0
+ primary-for QRemoteObjectPendingCallWatcher (0x0x7f23432220e0)
+ QRemoteObjectPendingCall (0x0x7f23431e7ae0) 16
+
+Class QRemoteObjectSettingsStore::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QRemoteObjectSettingsStore::QPrivateSignal (0x0x7f2343236060) 0 empty
+
+Vtable for QRemoteObjectSettingsStore
+QRemoteObjectSettingsStore::_ZTV26QRemoteObjectSettingsStore: 16 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI26QRemoteObjectSettingsStore)
+16 (int (*)(...))QRemoteObjectSettingsStore::metaObject
+24 (int (*)(...))QRemoteObjectSettingsStore::qt_metacast
+32 (int (*)(...))QRemoteObjectSettingsStore::qt_metacall
+40 (int (*)(...))QRemoteObjectSettingsStore::~QRemoteObjectSettingsStore
+48 (int (*)(...))QRemoteObjectSettingsStore::~QRemoteObjectSettingsStore
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QRemoteObjectSettingsStore::saveProperties
+120 (int (*)(...))QRemoteObjectSettingsStore::restoreProperties
+
+Class QRemoteObjectSettingsStore
+ size=16 align=8
+ base size=16 base align=8
+QRemoteObjectSettingsStore (0x0x7f2343235000) 0
+ vptr=((& QRemoteObjectSettingsStore::_ZTV26QRemoteObjectSettingsStore) + 16)
+ QRemoteObjectAbstractPersistedStore (0x0x7f2343235068) 0
+ primary-for QRemoteObjectSettingsStore (0x0x7f2343235000)
+ QObject (0x0x7f2343236000) 0
+ primary-for QRemoteObjectAbstractPersistedStore (0x0x7f2343235068)
+
+Class QtPrivate::QMetaObjectPrivate
+ size=56 align=4
+ base size=56 base align=4
+QtPrivate::QMetaObjectPrivate (0x0x7f23432365a0) 0
+
+Class ModelInfo
+ size=24 align=8
+ base size=24 base align=8
+ModelInfo (0x0x7f23432842a0) 0
+
+Vtable for SourceApiMap
+SourceApiMap::_ZTV12SourceApiMap: 32 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI12SourceApiMap)
+16 0
+24 0
+32 (int (*)(...))__cxa_pure_virtual
+40 (int (*)(...))__cxa_pure_virtual
+48 (int (*)(...))SourceApiMap::className
+56 (int (*)(...))__cxa_pure_virtual
+64 (int (*)(...))__cxa_pure_virtual
+72 (int (*)(...))__cxa_pure_virtual
+80 (int (*)(...))__cxa_pure_virtual
+88 (int (*)(...))__cxa_pure_virtual
+96 (int (*)(...))__cxa_pure_virtual
+104 (int (*)(...))__cxa_pure_virtual
+112 (int (*)(...))__cxa_pure_virtual
+120 (int (*)(...))__cxa_pure_virtual
+128 (int (*)(...))__cxa_pure_virtual
+136 (int (*)(...))__cxa_pure_virtual
+144 (int (*)(...))__cxa_pure_virtual
+152 (int (*)(...))__cxa_pure_virtual
+160 (int (*)(...))__cxa_pure_virtual
+168 (int (*)(...))__cxa_pure_virtual
+176 (int (*)(...))__cxa_pure_virtual
+184 (int (*)(...))__cxa_pure_virtual
+192 (int (*)(...))__cxa_pure_virtual
+200 (int (*)(...))__cxa_pure_virtual
+208 (int (*)(...))__cxa_pure_virtual
+216 (int (*)(...))__cxa_pure_virtual
+224 (int (*)(...))SourceApiMap::isDynamic
+232 (int (*)(...))SourceApiMap::isAdapterSignal
+240 (int (*)(...))SourceApiMap::isAdapterMethod
+248 (int (*)(...))SourceApiMap::isAdapterProperty
+
+Class SourceApiMap
+ size=24 align=8
+ base size=24 base align=8
+SourceApiMap (0x0x7f2343284300) 0
+ vptr=((& SourceApiMap::_ZTV12SourceApiMap) + 16)
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long int; _Ret = int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Save_errno
+ size=4 align=4
+ base size=4 base align=4
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long int; _Ret = int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Save_errno (0x0x7f234331bcc0) 0
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long int; _Ret = int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Range_chk
+ size=1 align=1
+ base size=0 base align=1
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long int; _Ret = int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Range_chk (0x0x7f2343339060) 0 empty
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long int; _Ret = long int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Save_errno
+ size=4 align=4
+ base size=4 base align=4
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long int; _Ret = long int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Save_errno (0x0x7f2343339240) 0
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long int; _Ret = long int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Range_chk
+ size=1 align=1
+ base size=0 base align=1
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long int; _Ret = long int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Range_chk (0x0x7f23433395a0) 0 empty
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long unsigned int; _Ret = long unsigned int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Save_errno
+ size=4 align=4
+ base size=4 base align=4
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long unsigned int; _Ret = long unsigned int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Save_errno (0x0x7f2343339780) 0
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long unsigned int; _Ret = long unsigned int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Range_chk
+ size=1 align=1
+ base size=0 base align=1
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long unsigned int; _Ret = long unsigned int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Range_chk (0x0x7f2343339ae0) 0 empty
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long long int; _Ret = long long int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Save_errno
+ size=4 align=4
+ base size=4 base align=4
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long long int; _Ret = long long int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Save_errno (0x0x7f2343339cc0) 0
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long long int; _Ret = long long int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Range_chk
+ size=1 align=1
+ base size=0 base align=1
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long long int; _Ret = long long int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Range_chk (0x0x7f234337b060) 0 empty
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long long unsigned int; _Ret = long long unsigned int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Save_errno
+ size=4 align=4
+ base size=4 base align=4
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long long unsigned int; _Ret = long long unsigned int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Save_errno (0x0x7f234337b240) 0
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long long unsigned int; _Ret = long long unsigned int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Range_chk
+ size=1 align=1
+ base size=0 base align=1
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long long unsigned int; _Ret = long long unsigned int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Range_chk (0x0x7f234337b5a0) 0 empty
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = float; _Ret = float; _CharT = char; _Base = {}; std::size_t = long unsigned int]::_Save_errno
+ size=4 align=4
+ base size=4 base align=4
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = float; _Ret = float; _CharT = char; _Base = {}; std::size_t = long unsigned int]::_Save_errno (0x0x7f234337b780) 0
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = float; _Ret = float; _CharT = char; _Base = {}; std::size_t = long unsigned int]::_Range_chk
+ size=1 align=1
+ base size=0 base align=1
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = float; _Ret = float; _CharT = char; _Base = {}; std::size_t = long unsigned int]::_Range_chk (0x0x7f234337bae0) 0 empty
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = double; _Ret = double; _CharT = char; _Base = {}; std::size_t = long unsigned int]::_Save_errno
+ size=4 align=4
+ base size=4 base align=4
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = double; _Ret = double; _CharT = char; _Base = {}; std::size_t = long unsigned int]::_Save_errno (0x0x7f234337bcc0) 0
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = double; _Ret = double; _CharT = char; _Base = {}; std::size_t = long unsigned int]::_Range_chk
+ size=1 align=1
+ base size=0 base align=1
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = double; _Ret = double; _CharT = char; _Base = {}; std::size_t = long unsigned int]::_Range_chk (0x0x7f23433af060) 0 empty
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long double; _Ret = long double; _CharT = char; _Base = {}; std::size_t = long unsigned int]::_Save_errno
+ size=4 align=4
+ base size=4 base align=4
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long double; _Ret = long double; _CharT = char; _Base = {}; std::size_t = long unsigned int]::_Save_errno (0x0x7f23433af240) 0
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long double; _Ret = long double; _CharT = char; _Base = {}; std::size_t = long unsigned int]::_Range_chk
+ size=1 align=1
+ base size=0 base align=1
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long double; _Ret = long double; _CharT = char; _Base = {}; std::size_t = long unsigned int]::_Range_chk (0x0x7f23433af5a0) 0 empty
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long int; _Ret = int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Save_errno
+ size=4 align=4
+ base size=4 base align=4
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long int; _Ret = int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Save_errno (0x0x7f2342fe0a80) 0
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long int; _Ret = int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Range_chk
+ size=1 align=1
+ base size=0 base align=1
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long int; _Ret = int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Range_chk (0x0x7f2342fe0de0) 0 empty
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long int; _Ret = long int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Save_errno
+ size=4 align=4
+ base size=4 base align=4
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long int; _Ret = long int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Save_errno (0x0x7f2342fe0f60) 0
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long int; _Ret = long int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Range_chk
+ size=1 align=1
+ base size=0 base align=1
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long int; _Ret = long int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Range_chk (0x0x7f2343011300) 0 empty
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long unsigned int; _Ret = long unsigned int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Save_errno
+ size=4 align=4
+ base size=4 base align=4
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long unsigned int; _Ret = long unsigned int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Save_errno (0x0x7f2343011480) 0
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long unsigned int; _Ret = long unsigned int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Range_chk
+ size=1 align=1
+ base size=0 base align=1
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long unsigned int; _Ret = long unsigned int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Range_chk (0x0x7f23430117e0) 0 empty
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long long int; _Ret = long long int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Save_errno
+ size=4 align=4
+ base size=4 base align=4
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long long int; _Ret = long long int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Save_errno (0x0x7f2343011960) 0
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long long int; _Ret = long long int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Range_chk
+ size=1 align=1
+ base size=0 base align=1
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long long int; _Ret = long long int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Range_chk (0x0x7f2343011cc0) 0 empty
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long long unsigned int; _Ret = long long unsigned int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Save_errno
+ size=4 align=4
+ base size=4 base align=4
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long long unsigned int; _Ret = long long unsigned int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Save_errno (0x0x7f2343011e40) 0
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long long unsigned int; _Ret = long long unsigned int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Range_chk
+ size=1 align=1
+ base size=0 base align=1
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long long unsigned int; _Ret = long long unsigned int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Range_chk (0x0x7f23430411e0) 0 empty
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = float; _Ret = float; _CharT = wchar_t; _Base = {}; std::size_t = long unsigned int]::_Save_errno
+ size=4 align=4
+ base size=4 base align=4
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = float; _Ret = float; _CharT = wchar_t; _Base = {}; std::size_t = long unsigned int]::_Save_errno (0x0x7f2343041360) 0
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = float; _Ret = float; _CharT = wchar_t; _Base = {}; std::size_t = long unsigned int]::_Range_chk
+ size=1 align=1
+ base size=0 base align=1
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = float; _Ret = float; _CharT = wchar_t; _Base = {}; std::size_t = long unsigned int]::_Range_chk (0x0x7f23430416c0) 0 empty
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = double; _Ret = double; _CharT = wchar_t; _Base = {}; std::size_t = long unsigned int]::_Save_errno
+ size=4 align=4
+ base size=4 base align=4
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = double; _Ret = double; _CharT = wchar_t; _Base = {}; std::size_t = long unsigned int]::_Save_errno (0x0x7f2343041840) 0
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = double; _Ret = double; _CharT = wchar_t; _Base = {}; std::size_t = long unsigned int]::_Range_chk
+ size=1 align=1
+ base size=0 base align=1
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = double; _Ret = double; _CharT = wchar_t; _Base = {}; std::size_t = long unsigned int]::_Range_chk (0x0x7f2343041ba0) 0 empty
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long double; _Ret = long double; _CharT = wchar_t; _Base = {}; std::size_t = long unsigned int]::_Save_errno
+ size=4 align=4
+ base size=4 base align=4
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long double; _Ret = long double; _CharT = wchar_t; _Base = {}; std::size_t = long unsigned int]::_Save_errno (0x0x7f2343041d20) 0
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long double; _Ret = long double; _CharT = wchar_t; _Base = {}; std::size_t = long unsigned int]::_Range_chk
+ size=1 align=1
+ base size=0 base align=1
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long double; _Ret = long double; _CharT = wchar_t; _Base = {}; std::size_t = long unsigned int]::_Range_chk (0x0x7f234306e0c0) 0 empty
+
--- /dev/null
+Class std::__failure_type
+ size=1 align=1
+ base size=0 base align=1
+std::__failure_type (0x0x7f3bffb14720) 0 empty
+
+Class std::__do_is_destructible_impl
+ size=1 align=1
+ base size=0 base align=1
+std::__do_is_destructible_impl (0x0x7f3bffb77ea0) 0 empty
+
+Class std::__do_is_nt_destructible_impl
+ size=1 align=1
+ base size=0 base align=1
+std::__do_is_nt_destructible_impl (0x0x7f3bffba4120) 0 empty
+
+Class std::__do_is_default_constructible_impl
+ size=1 align=1
+ base size=0 base align=1
+std::__do_is_default_constructible_impl (0x0x7f3bffba4360) 0 empty
+
+Class std::__do_is_static_castable_impl
+ size=1 align=1
+ base size=0 base align=1
+std::__do_is_static_castable_impl (0x0x7f3bffba45a0) 0 empty
+
+Class std::__do_is_direct_constructible_impl
+ size=1 align=1
+ base size=0 base align=1
+std::__do_is_direct_constructible_impl (0x0x7f3bffba4720) 0 empty
+
+Class std::__do_is_nary_constructible_impl
+ size=1 align=1
+ base size=0 base align=1
+std::__do_is_nary_constructible_impl (0x0x7f3bffba4ae0) 0 empty
+
+Class std::__do_is_implicitly_default_constructible_impl
+ size=1 align=1
+ base size=0 base align=1
+std::__do_is_implicitly_default_constructible_impl (0x0x7f3bffbe0c00) 0 empty
+
+Class std::__do_common_type_impl
+ size=1 align=1
+ base size=0 base align=1
+std::__do_common_type_impl (0x0x7f3bff862300) 0 empty
+
+Class std::__do_member_type_wrapper
+ size=1 align=1
+ base size=0 base align=1
+std::__do_member_type_wrapper (0x0x7f3bff8623c0) 0 empty
+
+Class std::__invoke_memfun_ref
+ size=1 align=1
+ base size=0 base align=1
+std::__invoke_memfun_ref (0x0x7f3bff862780) 0 empty
+
+Class std::__invoke_memfun_deref
+ size=1 align=1
+ base size=0 base align=1
+std::__invoke_memfun_deref (0x0x7f3bff8627e0) 0 empty
+
+Class std::__invoke_memobj_ref
+ size=1 align=1
+ base size=0 base align=1
+std::__invoke_memobj_ref (0x0x7f3bff862840) 0 empty
+
+Class std::__invoke_memobj_deref
+ size=1 align=1
+ base size=0 base align=1
+std::__invoke_memobj_deref (0x0x7f3bff8628a0) 0 empty
+
+Class std::__invoke_other
+ size=1 align=1
+ base size=0 base align=1
+std::__invoke_other (0x0x7f3bff862900) 0 empty
+
+Class std::__result_of_memfun_ref_impl
+ size=1 align=1
+ base size=0 base align=1
+std::__result_of_memfun_ref_impl (0x0x7f3bff8629c0) 0 empty
+
+Class std::__result_of_memfun_deref_impl
+ size=1 align=1
+ base size=0 base align=1
+std::__result_of_memfun_deref_impl (0x0x7f3bff862a80) 0 empty
+
+Class std::__result_of_memobj_ref_impl
+ size=1 align=1
+ base size=0 base align=1
+std::__result_of_memobj_ref_impl (0x0x7f3bff862b40) 0 empty
+
+Class std::__result_of_memobj_deref_impl
+ size=1 align=1
+ base size=0 base align=1
+std::__result_of_memobj_deref_impl (0x0x7f3bff862c00) 0 empty
+
+Class std::__result_of_other_impl
+ size=1 align=1
+ base size=0 base align=1
+std::__result_of_other_impl (0x0x7f3bff862f60) 0 empty
+
+Class std::__swappable_details::__do_is_swappable_impl
+ size=1 align=1
+ base size=0 base align=1
+std::__swappable_details::__do_is_swappable_impl (0x0x7f3bff89f300) 0 empty
+
+Class std::__swappable_details::__do_is_nothrow_swappable_impl
+ size=1 align=1
+ base size=0 base align=1
+std::__swappable_details::__do_is_nothrow_swappable_impl (0x0x7f3bff89f360) 0 empty
+
+Class std::__nonesuch
+ size=1 align=1
+ base size=0 base align=1
+std::__nonesuch (0x0x7f3bff89f900) 0 empty
+
+Class std::piecewise_construct_t
+ size=1 align=1
+ base size=0 base align=1
+std::piecewise_construct_t (0x0x7f3bff89ff60) 0 empty
+
+Class std::__nonesuch_no_braces
+ size=1 align=1
+ base size=1 base align=1
+std::__nonesuch_no_braces (0x0x7f3bff8ba270) 0 empty
+ std::__nonesuch (0x0x7f3bff8e3480) 0 empty
+
+Class std::__true_type
+ size=1 align=1
+ base size=0 base align=1
+std::__true_type (0x0x7f3bff92fde0) 0 empty
+
+Class std::__false_type
+ size=1 align=1
+ base size=0 base align=1
+std::__false_type (0x0x7f3bff92fe40) 0 empty
+
+Class std::input_iterator_tag
+ size=1 align=1
+ base size=0 base align=1
+std::input_iterator_tag (0x0x7f3bff992b40) 0 empty
+
+Class std::output_iterator_tag
+ size=1 align=1
+ base size=0 base align=1
+std::output_iterator_tag (0x0x7f3bff992ba0) 0 empty
+
+Class std::forward_iterator_tag
+ size=1 align=1
+ base size=1 base align=1
+std::forward_iterator_tag (0x0x7f3bff8ba750) 0 empty
+ std::input_iterator_tag (0x0x7f3bff992c00) 0 empty
+
+Class std::bidirectional_iterator_tag
+ size=1 align=1
+ base size=1 base align=1
+std::bidirectional_iterator_tag (0x0x7f3bff8ba7b8) 0 empty
+ std::forward_iterator_tag (0x0x7f3bff8ba820) 0 empty
+ std::input_iterator_tag (0x0x7f3bff992c60) 0 empty
+
+Class std::random_access_iterator_tag
+ size=1 align=1
+ base size=1 base align=1
+std::random_access_iterator_tag (0x0x7f3bff8ba888) 0 empty
+ std::bidirectional_iterator_tag (0x0x7f3bff8ba8f0) 0 empty
+ std::forward_iterator_tag (0x0x7f3bff8ba958) 0 empty
+ std::input_iterator_tag (0x0x7f3bff992cc0) 0 empty
+
+Class __gnu_cxx::__ops::_Iter_less_iter
+ size=1 align=1
+ base size=0 base align=1
+__gnu_cxx::__ops::_Iter_less_iter (0x0x7f3bffa417e0) 0 empty
+
+Class __gnu_cxx::__ops::_Iter_less_val
+ size=1 align=1
+ base size=0 base align=1
+__gnu_cxx::__ops::_Iter_less_val (0x0x7f3bffa41900) 0 empty
+
+Class __gnu_cxx::__ops::_Val_less_iter
+ size=1 align=1
+ base size=0 base align=1
+__gnu_cxx::__ops::_Val_less_iter (0x0x7f3bffa41c00) 0 empty
+
+Class __gnu_cxx::__ops::_Iter_equal_to_iter
+ size=1 align=1
+ base size=0 base align=1
+__gnu_cxx::__ops::_Iter_equal_to_iter (0x0x7f3bffa41f00) 0 empty
+
+Class __gnu_cxx::__ops::_Iter_equal_to_val
+ size=1 align=1
+ base size=0 base align=1
+__gnu_cxx::__ops::_Iter_equal_to_val (0x0x7f3bff670060) 0 empty
+
+Class __locale_struct
+ size=232 align=8
+ base size=232 base align=8
+__locale_struct (0x0x7f3bff6fc360) 0
+
+Class timeval
+ size=16 align=8
+ base size=16 base align=8
+timeval (0x0x7f3bff6fc660) 0
+
+Class timespec
+ size=16 align=8
+ base size=16 base align=8
+timespec (0x0x7f3bff6fc6c0) 0
+
+Class __pthread_rwlock_arch_t
+ size=56 align=8
+ base size=56 base align=8
+__pthread_rwlock_arch_t (0x0x7f3bff6fc780) 0
+
+Class __pthread_internal_list
+ size=16 align=8
+ base size=16 base align=8
+__pthread_internal_list (0x0x7f3bff6fc7e0) 0
+
+Class __pthread_mutex_s
+ size=40 align=8
+ base size=40 base align=8
+__pthread_mutex_s (0x0x7f3bff6fc840) 0
+
+Class __pthread_cond_s
+ size=48 align=8
+ base size=48 base align=8
+__pthread_cond_s (0x0x7f3bff6fc8a0) 0
+
+Class pthread_attr_t
+ size=56 align=8
+ base size=56 base align=8
+pthread_attr_t (0x0x7f3bff6fcb40) 0
+
+Class random_data
+ size=48 align=8
+ base size=48 base align=8
+random_data (0x0x7f3bff6fcde0) 0
+
+Class drand48_data
+ size=24 align=8
+ base size=24 base align=8
+drand48_data (0x0x7f3bff6fce40) 0
+
+Vtable for std::exception
+std::exception::_ZTVSt9exception: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTISt9exception)
+16 (int (*)(...))std::exception::~exception
+24 (int (*)(...))std::exception::~exception
+32 (int (*)(...))std::exception::what
+
+Class std::exception
+ size=8 align=8
+ base size=8 base align=8
+std::exception (0x0x7f3bff755c00) 0 nearly-empty
+ vptr=((& std::exception::_ZTVSt9exception) + 16)
+
+Vtable for std::bad_exception
+std::bad_exception::_ZTVSt13bad_exception: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTISt13bad_exception)
+16 (int (*)(...))std::bad_exception::~bad_exception
+24 (int (*)(...))std::bad_exception::~bad_exception
+32 (int (*)(...))std::bad_exception::what
+
+Class std::bad_exception
+ size=8 align=8
+ base size=8 base align=8
+std::bad_exception (0x0x7f3bff8bac98) 0 nearly-empty
+ vptr=((& std::bad_exception::_ZTVSt13bad_exception) + 16)
+ std::exception (0x0x7f3bff755de0) 0 nearly-empty
+ primary-for std::bad_exception (0x0x7f3bff8bac98)
+
+Vtable for std::type_info
+std::type_info::_ZTVSt9type_info: 8 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTISt9type_info)
+16 (int (*)(...))std::type_info::~type_info
+24 (int (*)(...))std::type_info::~type_info
+32 (int (*)(...))std::type_info::__is_pointer_p
+40 (int (*)(...))std::type_info::__is_function_p
+48 (int (*)(...))std::type_info::__do_catch
+56 (int (*)(...))std::type_info::__do_upcast
+
+Class std::type_info
+ size=16 align=8
+ base size=16 base align=8
+std::type_info (0x0x7f3bff7f8000) 0
+ vptr=((& std::type_info::_ZTVSt9type_info) + 16)
+
+Vtable for std::bad_cast
+std::bad_cast::_ZTVSt8bad_cast: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTISt8bad_cast)
+16 (int (*)(...))std::bad_cast::~bad_cast
+24 (int (*)(...))std::bad_cast::~bad_cast
+32 (int (*)(...))std::bad_cast::what
+
+Class std::bad_cast
+ size=8 align=8
+ base size=8 base align=8
+std::bad_cast (0x0x7f3bff8bad00) 0 nearly-empty
+ vptr=((& std::bad_cast::_ZTVSt8bad_cast) + 16)
+ std::exception (0x0x7f3bff7f83c0) 0 nearly-empty
+ primary-for std::bad_cast (0x0x7f3bff8bad00)
+
+Vtable for std::bad_typeid
+std::bad_typeid::_ZTVSt10bad_typeid: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTISt10bad_typeid)
+16 (int (*)(...))std::bad_typeid::~bad_typeid
+24 (int (*)(...))std::bad_typeid::~bad_typeid
+32 (int (*)(...))std::bad_typeid::what
+
+Class std::bad_typeid
+ size=8 align=8
+ base size=8 base align=8
+std::bad_typeid (0x0x7f3bff8bad68) 0 nearly-empty
+ vptr=((& std::bad_typeid::_ZTVSt10bad_typeid) + 16)
+ std::exception (0x0x7f3bff7f85a0) 0 nearly-empty
+ primary-for std::bad_typeid (0x0x7f3bff8bad68)
+
+Class std::__exception_ptr::exception_ptr
+ size=8 align=8
+ base size=8 base align=8
+std::__exception_ptr::exception_ptr (0x0x7f3bff7f8780) 0
+
+Vtable for std::nested_exception
+std::nested_exception::_ZTVSt16nested_exception: 4 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTISt16nested_exception)
+16 (int (*)(...))std::nested_exception::~nested_exception
+24 (int (*)(...))std::nested_exception::~nested_exception
+
+Class std::nested_exception
+ size=16 align=8
+ base size=16 base align=8
+std::nested_exception (0x0x7f3bff7f8d20) 0
+ vptr=((& std::nested_exception::_ZTVSt16nested_exception) + 16)
+
+Vtable for std::bad_alloc
+std::bad_alloc::_ZTVSt9bad_alloc: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTISt9bad_alloc)
+16 (int (*)(...))std::bad_alloc::~bad_alloc
+24 (int (*)(...))std::bad_alloc::~bad_alloc
+32 (int (*)(...))std::bad_alloc::what
+
+Class std::bad_alloc
+ size=8 align=8
+ base size=8 base align=8
+std::bad_alloc (0x0x7f3bff8badd0) 0 nearly-empty
+ vptr=((& std::bad_alloc::_ZTVSt9bad_alloc) + 16)
+ std::exception (0x0x7f3bff82d420) 0 nearly-empty
+ primary-for std::bad_alloc (0x0x7f3bff8badd0)
+
+Vtable for std::bad_array_new_length
+std::bad_array_new_length::_ZTVSt20bad_array_new_length: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTISt20bad_array_new_length)
+16 (int (*)(...))std::bad_array_new_length::~bad_array_new_length
+24 (int (*)(...))std::bad_array_new_length::~bad_array_new_length
+32 (int (*)(...))std::bad_array_new_length::what
+
+Class std::bad_array_new_length
+ size=8 align=8
+ base size=8 base align=8
+std::bad_array_new_length (0x0x7f3bff8bae38) 0 nearly-empty
+ vptr=((& std::bad_array_new_length::_ZTVSt20bad_array_new_length) + 16)
+ std::bad_alloc (0x0x7f3bff8baea0) 0 nearly-empty
+ primary-for std::bad_array_new_length (0x0x7f3bff8bae38)
+ std::exception (0x0x7f3bff82d600) 0 nearly-empty
+ primary-for std::bad_alloc (0x0x7f3bff8baea0)
+
+Class std::nothrow_t
+ size=1 align=1
+ base size=0 base align=1
+std::nothrow_t (0x0x7f3bff82d7e0) 0 empty
+
+Class std::__allocator_traits_base
+ size=1 align=1
+ base size=0 base align=1
+std::__allocator_traits_base (0x0x7f3bff82d9c0) 0 empty
+
+Class std::__numeric_limits_base
+ size=1 align=1
+ base size=0 base align=1
+std::__numeric_limits_base (0x0x7f3bff4abea0) 0 empty
+
+Class QSysInfo
+ size=1 align=1
+ base size=0 base align=1
+QSysInfo (0x0x7f3bff145420) 0 empty
+
+Class QMessageLogContext
+ size=32 align=8
+ base size=32 base align=8
+QMessageLogContext (0x0x7f3bff145540) 0
+
+Class QMessageLogger
+ size=32 align=8
+ base size=32 base align=8
+QMessageLogger (0x0x7f3bff145720) 0
+
+Class QFlag
+ size=4 align=4
+ base size=4 base align=4
+QFlag (0x0x7f3bff145de0) 0
+
+Class QIncompatibleFlag
+ size=4 align=4
+ base size=4 base align=4
+QIncompatibleFlag (0x0x7f3bff1c05a0) 0
+
+Class std::__atomic_flag_base
+ size=1 align=1
+ base size=1 base align=1
+std::__atomic_flag_base (0x0x7f3bfee56a80) 0
+
+Class std::atomic_flag
+ size=1 align=1
+ base size=1 base align=1
+std::atomic_flag (0x0x7f3bff1f6d00) 0
+ std::__atomic_flag_base (0x0x7f3bfee56ae0) 0
+
+Class QAtomicInt
+ size=4 align=4
+ base size=4 base align=4
+QAtomicInt (0x0x7f3bff002478) 0
+ QAtomicInteger<int> (0x0x7f3bff0024e0) 0
+ QBasicAtomicInteger<int> (0x0x7f3bfed8cd20) 0
+
+Class QInternal
+ size=1 align=1
+ base size=0 base align=1
+QInternal (0x0x7f3bfe9e08a0) 0 empty
+
+Class QtPrivate::QSlotObjectBase
+ size=16 align=8
+ base size=16 base align=8
+QtPrivate::QSlotObjectBase (0x0x7f3bfea10e40) 0
+
+Class QGenericArgument
+ size=16 align=8
+ base size=16 base align=8
+QGenericArgument (0x0x7f3bfe65d5a0) 0
+
+Class QGenericReturnArgument
+ size=16 align=8
+ base size=16 base align=8
+QGenericReturnArgument (0x0x7f3bfe666138) 0
+ QGenericArgument (0x0x7f3bfe65d840) 0
+
+Class QMetaObject::SuperData
+ size=8 align=8
+ base size=8 base align=8
+QMetaObject::SuperData (0x0x7f3bfe65dcc0) 0
+
+Class QMetaObject
+ size=48 align=8
+ base size=48 base align=8
+QMetaObject (0x0x7f3bfe65dc60) 0
+
+Class QMetaObject::Connection
+ size=8 align=8
+ base size=8 base align=8
+QMetaObject::Connection (0x0x7f3bfe6b25a0) 0
+
+Class QLatin1Char
+ size=1 align=1
+ base size=1 base align=1
+QLatin1Char (0x0x7f3bfe7350c0) 0
+
+Class QChar
+ size=2 align=2
+ base size=2 base align=2
+QChar (0x0x7f3bfe7357e0) 0
+
+Class QtPrivate::RefCount
+ size=4 align=4
+ base size=4 base align=4
+QtPrivate::RefCount (0x0x7f3bfe804600) 0
+
+Class QArrayData
+ size=24 align=8
+ base size=24 base align=8
+QArrayData (0x0x7f3bfe804960) 0
+
+Class QtPrivate::QContainerImplHelper
+ size=1 align=1
+ base size=0 base align=1
+QtPrivate::QContainerImplHelper (0x0x7f3bfe461c60) 0 empty
+
+Class lconv
+ size=96 align=8
+ base size=96 base align=8
+lconv (0x0x7f3bfe5574e0) 0
+
+Vtable for __cxxabiv1::__forced_unwind
+__cxxabiv1::__forced_unwind::_ZTVN10__cxxabiv115__forced_unwindE: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTIN10__cxxabiv115__forced_unwindE)
+16 0
+24 0
+32 (int (*)(...))__cxa_pure_virtual
+
+Class __cxxabiv1::__forced_unwind
+ size=8 align=8
+ base size=8 base align=8
+__cxxabiv1::__forced_unwind (0x0x7f3bfe5575a0) 0 nearly-empty
+ vptr=((& __cxxabiv1::__forced_unwind::_ZTVN10__cxxabiv115__forced_unwindE) + 16)
+
+Class sched_param
+ size=4 align=4
+ base size=4 base align=4
+sched_param (0x0x7f3bfe60c6c0) 0
+
+Class timex
+ size=208 align=8
+ base size=208 base align=8
+timex (0x0x7f3bfe60c780) 0
+
+Class tm
+ size=56 align=8
+ base size=56 base align=8
+tm (0x0x7f3bfe60c7e0) 0
+
+Class itimerspec
+ size=32 align=8
+ base size=32 base align=8
+itimerspec (0x0x7f3bfe60c840) 0
+
+Class _pthread_cleanup_buffer
+ size=32 align=8
+ base size=32 base align=8
+_pthread_cleanup_buffer (0x0x7f3bfe60c8a0) 0
+
+Class __pthread_cleanup_frame
+ size=24 align=8
+ base size=24 base align=8
+__pthread_cleanup_frame (0x0x7f3bfe60c9c0) 0
+
+Class __pthread_cleanup_class
+ size=24 align=8
+ base size=24 base align=8
+__pthread_cleanup_class (0x0x7f3bfe60ca20) 0
+
+Class _IO_marker
+ size=24 align=8
+ base size=24 base align=8
+_IO_marker (0x0x7f3bfe34d9c0) 0
+
+Class _IO_FILE
+ size=216 align=8
+ base size=216 base align=8
+_IO_FILE (0x0x7f3bfe34da20) 0
+
+Class std::_Hash_impl
+ size=1 align=1
+ base size=0 base align=1
+std::_Hash_impl (0x0x7f3bfe106a80) 0 empty
+
+Class std::_Fnv_hash_impl
+ size=1 align=1
+ base size=0 base align=1
+std::_Fnv_hash_impl (0x0x7f3bfe106c00) 0 empty
+
+Class std::locale
+ size=8 align=8
+ base size=8 base align=8
+std::locale (0x0x7f3bfde7bd80) 0
+
+Vtable for std::locale::facet
+std::locale::facet::_ZTVNSt6locale5facetE: 4 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTINSt6locale5facetE)
+16 (int (*)(...))std::locale::facet::~facet
+24 (int (*)(...))std::locale::facet::~facet
+
+Class std::locale::facet
+ size=16 align=8
+ base size=12 base align=8
+std::locale::facet (0x0x7f3bfdec7180) 0
+ vptr=((& std::locale::facet::_ZTVNSt6locale5facetE) + 16)
+
+Class std::locale::id
+ size=8 align=8
+ base size=8 base align=8
+std::locale::id (0x0x7f3bfdec7420) 0
+
+Class std::locale::_Impl
+ size=40 align=8
+ base size=40 base align=8
+std::locale::_Impl (0x0x7f3bfdec7600) 0
+
+Class std::__cow_string
+ size=8 align=8
+ base size=8 base align=8
+std::__cow_string (0x0x7f3bfdf14600) 0
+
+Vtable for std::logic_error
+std::logic_error::_ZTVSt11logic_error: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTISt11logic_error)
+16 (int (*)(...))std::logic_error::~logic_error
+24 (int (*)(...))std::logic_error::~logic_error
+32 (int (*)(...))std::logic_error::what
+
+Class std::logic_error
+ size=16 align=8
+ base size=16 base align=8
+std::logic_error (0x0x7f3bfdf250d0) 0
+ vptr=((& std::logic_error::_ZTVSt11logic_error) + 16)
+ std::exception (0x0x7f3bfdf146c0) 0 nearly-empty
+ primary-for std::logic_error (0x0x7f3bfdf250d0)
+
+Vtable for std::domain_error
+std::domain_error::_ZTVSt12domain_error: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTISt12domain_error)
+16 (int (*)(...))std::domain_error::~domain_error
+24 (int (*)(...))std::domain_error::~domain_error
+32 (int (*)(...))std::logic_error::what
+
+Class std::domain_error
+ size=16 align=8
+ base size=16 base align=8
+std::domain_error (0x0x7f3bfdf25138) 0
+ vptr=((& std::domain_error::_ZTVSt12domain_error) + 16)
+ std::logic_error (0x0x7f3bfdf251a0) 0
+ primary-for std::domain_error (0x0x7f3bfdf25138)
+ std::exception (0x0x7f3bfdf14720) 0 nearly-empty
+ primary-for std::logic_error (0x0x7f3bfdf251a0)
+
+Vtable for std::invalid_argument
+std::invalid_argument::_ZTVSt16invalid_argument: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTISt16invalid_argument)
+16 (int (*)(...))std::invalid_argument::~invalid_argument
+24 (int (*)(...))std::invalid_argument::~invalid_argument
+32 (int (*)(...))std::logic_error::what
+
+Class std::invalid_argument
+ size=16 align=8
+ base size=16 base align=8
+std::invalid_argument (0x0x7f3bfdf25208) 0
+ vptr=((& std::invalid_argument::_ZTVSt16invalid_argument) + 16)
+ std::logic_error (0x0x7f3bfdf25270) 0
+ primary-for std::invalid_argument (0x0x7f3bfdf25208)
+ std::exception (0x0x7f3bfdf14780) 0 nearly-empty
+ primary-for std::logic_error (0x0x7f3bfdf25270)
+
+Vtable for std::length_error
+std::length_error::_ZTVSt12length_error: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTISt12length_error)
+16 (int (*)(...))std::length_error::~length_error
+24 (int (*)(...))std::length_error::~length_error
+32 (int (*)(...))std::logic_error::what
+
+Class std::length_error
+ size=16 align=8
+ base size=16 base align=8
+std::length_error (0x0x7f3bfdf252d8) 0
+ vptr=((& std::length_error::_ZTVSt12length_error) + 16)
+ std::logic_error (0x0x7f3bfdf25340) 0
+ primary-for std::length_error (0x0x7f3bfdf252d8)
+ std::exception (0x0x7f3bfdf147e0) 0 nearly-empty
+ primary-for std::logic_error (0x0x7f3bfdf25340)
+
+Vtable for std::out_of_range
+std::out_of_range::_ZTVSt12out_of_range: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTISt12out_of_range)
+16 (int (*)(...))std::out_of_range::~out_of_range
+24 (int (*)(...))std::out_of_range::~out_of_range
+32 (int (*)(...))std::logic_error::what
+
+Class std::out_of_range
+ size=16 align=8
+ base size=16 base align=8
+std::out_of_range (0x0x7f3bfdf253a8) 0
+ vptr=((& std::out_of_range::_ZTVSt12out_of_range) + 16)
+ std::logic_error (0x0x7f3bfdf25410) 0
+ primary-for std::out_of_range (0x0x7f3bfdf253a8)
+ std::exception (0x0x7f3bfdf14840) 0 nearly-empty
+ primary-for std::logic_error (0x0x7f3bfdf25410)
+
+Vtable for std::runtime_error
+std::runtime_error::_ZTVSt13runtime_error: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTISt13runtime_error)
+16 (int (*)(...))std::runtime_error::~runtime_error
+24 (int (*)(...))std::runtime_error::~runtime_error
+32 (int (*)(...))std::runtime_error::what
+
+Class std::runtime_error
+ size=16 align=8
+ base size=16 base align=8
+std::runtime_error (0x0x7f3bfdf25478) 0
+ vptr=((& std::runtime_error::_ZTVSt13runtime_error) + 16)
+ std::exception (0x0x7f3bfdf148a0) 0 nearly-empty
+ primary-for std::runtime_error (0x0x7f3bfdf25478)
+
+Vtable for std::range_error
+std::range_error::_ZTVSt11range_error: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTISt11range_error)
+16 (int (*)(...))std::range_error::~range_error
+24 (int (*)(...))std::range_error::~range_error
+32 (int (*)(...))std::runtime_error::what
+
+Class std::range_error
+ size=16 align=8
+ base size=16 base align=8
+std::range_error (0x0x7f3bfdf254e0) 0
+ vptr=((& std::range_error::_ZTVSt11range_error) + 16)
+ std::runtime_error (0x0x7f3bfdf25548) 0
+ primary-for std::range_error (0x0x7f3bfdf254e0)
+ std::exception (0x0x7f3bfdf14900) 0 nearly-empty
+ primary-for std::runtime_error (0x0x7f3bfdf25548)
+
+Vtable for std::overflow_error
+std::overflow_error::_ZTVSt14overflow_error: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTISt14overflow_error)
+16 (int (*)(...))std::overflow_error::~overflow_error
+24 (int (*)(...))std::overflow_error::~overflow_error
+32 (int (*)(...))std::runtime_error::what
+
+Class std::overflow_error
+ size=16 align=8
+ base size=16 base align=8
+std::overflow_error (0x0x7f3bfdf255b0) 0
+ vptr=((& std::overflow_error::_ZTVSt14overflow_error) + 16)
+ std::runtime_error (0x0x7f3bfdf25618) 0
+ primary-for std::overflow_error (0x0x7f3bfdf255b0)
+ std::exception (0x0x7f3bfdf14960) 0 nearly-empty
+ primary-for std::runtime_error (0x0x7f3bfdf25618)
+
+Vtable for std::underflow_error
+std::underflow_error::_ZTVSt15underflow_error: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTISt15underflow_error)
+16 (int (*)(...))std::underflow_error::~underflow_error
+24 (int (*)(...))std::underflow_error::~underflow_error
+32 (int (*)(...))std::runtime_error::what
+
+Class std::underflow_error
+ size=16 align=8
+ base size=16 base align=8
+std::underflow_error (0x0x7f3bfdf25680) 0
+ vptr=((& std::underflow_error::_ZTVSt15underflow_error) + 16)
+ std::runtime_error (0x0x7f3bfdf256e8) 0
+ primary-for std::underflow_error (0x0x7f3bfdf25680)
+ std::exception (0x0x7f3bfdf149c0) 0 nearly-empty
+ primary-for std::runtime_error (0x0x7f3bfdf256e8)
+
+Vtable for std::_V2::error_category
+std::_V2::error_category::_ZTVNSt3_V214error_categoryE: 10 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTINSt3_V214error_categoryE)
+16 0
+24 0
+32 (int (*)(...))__cxa_pure_virtual
+40 (int (*)(...))std::_V2::error_category::_M_message
+48 (int (*)(...))__cxa_pure_virtual
+56 (int (*)(...))std::_V2::error_category::default_error_condition
+64 (int (*)(...))std::_V2::error_category::equivalent
+72 (int (*)(...))std::_V2::error_category::equivalent
+
+Class std::_V2::error_category
+ size=8 align=8
+ base size=8 base align=8
+std::_V2::error_category (0x0x7f3bfdf14b40) 0 nearly-empty
+ vptr=((& std::_V2::error_category::_ZTVNSt3_V214error_categoryE) + 16)
+
+Class std::error_code
+ size=16 align=8
+ base size=16 base align=8
+std::error_code (0x0x7f3bfdf14ea0) 0
+
+Class std::error_condition
+ size=16 align=8
+ base size=16 base align=8
+std::error_condition (0x0x7f3bfdf72720) 0
+
+Vtable for std::system_error
+std::system_error::_ZTVSt12system_error: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTISt12system_error)
+16 (int (*)(...))std::system_error::~system_error
+24 (int (*)(...))std::system_error::~system_error
+32 (int (*)(...))std::runtime_error::what
+
+Class std::system_error
+ size=32 align=8
+ base size=32 base align=8
+std::system_error (0x0x7f3bfdf25af8) 0
+ vptr=((& std::system_error::_ZTVSt12system_error) + 16)
+ std::runtime_error (0x0x7f3bfdf25b60) 0
+ primary-for std::system_error (0x0x7f3bfdf25af8)
+ std::exception (0x0x7f3bfdf99300) 0 nearly-empty
+ primary-for std::runtime_error (0x0x7f3bfdf25b60)
+
+Vtable for std::ios_base::failure
+std::ios_base::failure::_ZTVNSt8ios_base7failureB5cxx11E: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTINSt8ios_base7failureB5cxx11E)
+16 (int (*)(...))std::ios_base::failure::~failure
+24 (int (*)(...))std::ios_base::failure::~failure
+32 (int (*)(...))std::ios_base::failure::what
+
+Class std::ios_base::failure
+ size=32 align=8
+ base size=32 base align=8
+std::ios_base::failure (0x0x7f3bfdf25dd0) 0
+ vptr=((& std::ios_base::failure::_ZTVNSt8ios_base7failureB5cxx11E) + 16)
+ std::system_error (0x0x7f3bfdf25e38) 0
+ primary-for std::ios_base::failure (0x0x7f3bfdf25dd0)
+ std::runtime_error (0x0x7f3bfdf25ea0) 0
+ primary-for std::system_error (0x0x7f3bfdf25e38)
+ std::exception (0x0x7f3bfdfca8a0) 0 nearly-empty
+ primary-for std::runtime_error (0x0x7f3bfdf25ea0)
+
+Class std::ios_base::_Callback_list
+ size=24 align=8
+ base size=24 base align=8
+std::ios_base::_Callback_list (0x0x7f3bfdfca900) 0
+
+Class std::ios_base::_Words
+ size=16 align=8
+ base size=16 base align=8
+std::ios_base::_Words (0x0x7f3bfdfca960) 0
+
+Class std::ios_base::Init
+ size=1 align=1
+ base size=0 base align=1
+std::ios_base::Init (0x0x7f3bfdfca9c0) 0 empty
+
+Vtable for std::ios_base
+std::ios_base::_ZTVSt8ios_base: 4 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTISt8ios_base)
+16 (int (*)(...))std::ios_base::~ios_base
+24 (int (*)(...))std::ios_base::~ios_base
+
+Class std::ios_base
+ size=216 align=8
+ base size=216 base align=8
+std::ios_base (0x0x7f3bfdfca840) 0
+ vptr=((& std::ios_base::_ZTVSt8ios_base) + 16)
+
+Class std::ctype_base
+ size=1 align=1
+ base size=0 base align=1
+std::ctype_base (0x0x7f3bfdcbe300) 0 empty
+
+Class std::__num_base
+ size=1 align=1
+ base size=0 base align=1
+std::__num_base (0x0x7f3bfdd8a4e0) 0 empty
+
+VTT for std::basic_ostream<char>
+std::basic_ostream<char>::_ZTTSo: 2 entries
+0 ((& std::basic_ostream<char>::_ZTVSo) + 24)
+8 ((& std::basic_ostream<char>::_ZTVSo) + 64)
+
+VTT for std::basic_ostream<wchar_t>
+std::basic_ostream<wchar_t>::_ZTTSt13basic_ostreamIwSt11char_traitsIwEE: 2 entries
+0 ((& std::basic_ostream<wchar_t>::_ZTVSt13basic_ostreamIwSt11char_traitsIwEE) + 24)
+8 ((& std::basic_ostream<wchar_t>::_ZTVSt13basic_ostreamIwSt11char_traitsIwEE) + 64)
+
+VTT for std::basic_istream<char>
+std::basic_istream<char>::_ZTTSi: 2 entries
+0 ((& std::basic_istream<char>::_ZTVSi) + 24)
+8 ((& std::basic_istream<char>::_ZTVSi) + 64)
+
+VTT for std::basic_istream<wchar_t>
+std::basic_istream<wchar_t>::_ZTTSt13basic_istreamIwSt11char_traitsIwEE: 2 entries
+0 ((& std::basic_istream<wchar_t>::_ZTVSt13basic_istreamIwSt11char_traitsIwEE) + 24)
+8 ((& std::basic_istream<wchar_t>::_ZTVSt13basic_istreamIwSt11char_traitsIwEE) + 64)
+
+Construction vtable for std::basic_istream<char> (0x0x7f3bfd9265b0 instance) in std::basic_iostream<char>
+std::basic_iostream<char>::_ZTCSd0_Si: 10 entries
+0 24
+8 (int (*)(...))0
+16 (int (*)(...))(& _ZTISi)
+24 0
+32 0
+40 18446744073709551592
+48 (int (*)(...))-24
+56 (int (*)(...))(& _ZTISi)
+64 0
+72 0
+
+Construction vtable for std::basic_ostream<char> (0x0x7f3bfd926680 instance) in std::basic_iostream<char>
+std::basic_iostream<char>::_ZTCSd16_So: 10 entries
+0 8
+8 (int (*)(...))0
+16 (int (*)(...))(& _ZTISo)
+24 0
+32 0
+40 18446744073709551608
+48 (int (*)(...))-8
+56 (int (*)(...))(& _ZTISo)
+64 0
+72 0
+
+VTT for std::basic_iostream<char>
+std::basic_iostream<char>::_ZTTSd: 7 entries
+0 ((& std::basic_iostream<char>::_ZTVSd) + 24)
+8 ((& std::basic_iostream<char>::_ZTCSd0_Si) + 24)
+16 ((& std::basic_iostream<char>::_ZTCSd0_Si) + 64)
+24 ((& std::basic_iostream<char>::_ZTCSd16_So) + 24)
+32 ((& std::basic_iostream<char>::_ZTCSd16_So) + 64)
+40 ((& std::basic_iostream<char>::_ZTVSd) + 104)
+48 ((& std::basic_iostream<char>::_ZTVSd) + 64)
+
+Construction vtable for std::basic_istream<wchar_t> (0x0x7f3bfd967340 instance) in std::basic_iostream<wchar_t>
+std::basic_iostream<wchar_t>::_ZTCSt14basic_iostreamIwSt11char_traitsIwEE0_St13basic_istreamIwS1_E: 10 entries
+0 24
+8 (int (*)(...))0
+16 (int (*)(...))(& _ZTISt13basic_istreamIwSt11char_traitsIwEE)
+24 0
+32 0
+40 18446744073709551592
+48 (int (*)(...))-24
+56 (int (*)(...))(& _ZTISt13basic_istreamIwSt11char_traitsIwEE)
+64 0
+72 0
+
+Construction vtable for std::basic_ostream<wchar_t> (0x0x7f3bfd967410 instance) in std::basic_iostream<wchar_t>
+std::basic_iostream<wchar_t>::_ZTCSt14basic_iostreamIwSt11char_traitsIwEE16_St13basic_ostreamIwS1_E: 10 entries
+0 8
+8 (int (*)(...))0
+16 (int (*)(...))(& _ZTISt13basic_ostreamIwSt11char_traitsIwEE)
+24 0
+32 0
+40 18446744073709551608
+48 (int (*)(...))-8
+56 (int (*)(...))(& _ZTISt13basic_ostreamIwSt11char_traitsIwEE)
+64 0
+72 0
+
+VTT for std::basic_iostream<wchar_t>
+std::basic_iostream<wchar_t>::_ZTTSt14basic_iostreamIwSt11char_traitsIwEE: 7 entries
+0 ((& std::basic_iostream<wchar_t>::_ZTVSt14basic_iostreamIwSt11char_traitsIwEE) + 24)
+8 ((& std::basic_iostream<wchar_t>::_ZTCSt14basic_iostreamIwSt11char_traitsIwEE0_St13basic_istreamIwS1_E) + 24)
+16 ((& std::basic_iostream<wchar_t>::_ZTCSt14basic_iostreamIwSt11char_traitsIwEE0_St13basic_istreamIwS1_E) + 64)
+24 ((& std::basic_iostream<wchar_t>::_ZTCSt14basic_iostreamIwSt11char_traitsIwEE16_St13basic_ostreamIwS1_E) + 24)
+32 ((& std::basic_iostream<wchar_t>::_ZTCSt14basic_iostreamIwSt11char_traitsIwEE16_St13basic_ostreamIwS1_E) + 64)
+40 ((& std::basic_iostream<wchar_t>::_ZTVSt14basic_iostreamIwSt11char_traitsIwEE) + 104)
+48 ((& std::basic_iostream<wchar_t>::_ZTVSt14basic_iostreamIwSt11char_traitsIwEE) + 64)
+
+Class QByteArrayDataPtr
+ size=8 align=8
+ base size=8 base align=8
+QByteArrayDataPtr (0x0x7f3bfd963e40) 0
+
+Class QByteArray
+ size=8 align=8
+ base size=8 base align=8
+QByteArray (0x0x7f3bfd963ea0) 0
+
+Class QByteRef
+ size=16 align=8
+ base size=12 base align=8
+QByteRef (0x0x7f3bfd6d02a0) 0
+
+Class QStringDataPtr
+ size=8 align=8
+ base size=8 base align=8
+QStringDataPtr (0x0x7f3bfd76c120) 0
+
+Class QStringView
+ size=16 align=8
+ base size=16 base align=8
+QStringView (0x0x7f3bfd76c5a0) 0
+
+Class QLatin1String
+ size=16 align=8
+ base size=16 base align=8
+QLatin1String (0x0x7f3bfd455660) 0
+
+Class QString::Null
+ size=1 align=1
+ base size=0 base align=1
+QString::Null (0x0x7f3bfd505600) 0 empty
+
+Class QString
+ size=8 align=8
+ base size=8 base align=8
+QString (0x0x7f3bfd5054e0) 0
+
+Class QCharRef
+ size=16 align=8
+ base size=12 base align=8
+QCharRef (0x0x7f3bfd3df480) 0
+
+Class QStringRef
+ size=16 align=8
+ base size=16 base align=8
+QStringRef (0x0x7f3bfd162060) 0
+
+Class QtPrivate::ArgBase
+ size=1 align=1
+ base size=1 base align=1
+QtPrivate::ArgBase (0x0x7f3bfcec0e40) 0
+
+Class QtPrivate::QStringViewArg
+ size=24 align=8
+ base size=24 base align=8
+QtPrivate::QStringViewArg (0x0x7f3bfd1f5270) 0
+ QtPrivate::ArgBase (0x0x7f3bfcec0ea0) 0
+
+Class QtPrivate::QLatin1StringArg
+ size=24 align=8
+ base size=24 base align=8
+QtPrivate::QLatin1StringArg (0x0x7f3bfd1f52d8) 0
+ QtPrivate::ArgBase (0x0x7f3bfcefd0c0) 0
+
+Class std::__erased_type
+ size=1 align=1
+ base size=0 base align=1
+std::__erased_type (0x0x7f3bfcfbc000) 0 empty
+
+Class std::allocator_arg_t
+ size=1 align=1
+ base size=0 base align=1
+std::allocator_arg_t (0x0x7f3bfcfbc060) 0 empty
+
+Class std::__uses_alloc_base
+ size=1 align=1
+ base size=0 base align=1
+std::__uses_alloc_base (0x0x7f3bfcfbc1e0) 0 empty
+
+Class std::__uses_alloc0::_Sink
+ size=1 align=1
+ base size=0 base align=1
+std::__uses_alloc0::_Sink (0x0x7f3bfcfbc2a0) 0 empty
+
+Class std::__uses_alloc0
+ size=1 align=1
+ base size=1 base align=1
+std::__uses_alloc0 (0x0x7f3bfd1f5680) 0
+ std::__uses_alloc_base (0x0x7f3bfcfbc240) 0 empty
+
+Class std::_Swallow_assign
+ size=1 align=1
+ base size=0 base align=1
+std::_Swallow_assign (0x0x7f3bfcd27600) 0 empty
+
+Vtable for std::bad_function_call
+std::bad_function_call::_ZTVSt17bad_function_call: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTISt17bad_function_call)
+16 (int (*)(...))std::bad_function_call::~bad_function_call
+24 (int (*)(...))std::bad_function_call::~bad_function_call
+32 (int (*)(...))std::bad_function_call::what
+
+Class std::bad_function_call
+ size=8 align=8
+ base size=8 base align=8
+std::bad_function_call (0x0x7f3bfcd6f8f0) 0 nearly-empty
+ vptr=((& std::bad_function_call::_ZTVSt17bad_function_call) + 16)
+ std::exception (0x0x7f3bfcd6cf00) 0 nearly-empty
+ primary-for std::bad_function_call (0x0x7f3bfcd6f8f0)
+
+Class std::_Nocopy_types
+ size=16 align=8
+ base size=16 base align=8
+std::_Nocopy_types (0x0x7f3bfcda0000) 0
+
+Class std::_Any_data
+ size=16 align=8
+ base size=16 base align=8
+std::_Any_data (0x0x7f3bfcda0060) 0
+
+Class std::_Function_base
+ size=24 align=8
+ base size=24 base align=8
+std::_Function_base (0x0x7f3bfcda0360) 0
+
+Class QtPrivate::QHashCombine
+ size=1 align=1
+ base size=0 base align=1
+QtPrivate::QHashCombine (0x0x7f3bfcb927e0) 0 empty
+
+Class QtPrivate::QHashCombineCommutative
+ size=1 align=1
+ base size=0 base align=1
+QtPrivate::QHashCombineCommutative (0x0x7f3bfcb928a0) 0 empty
+
+Class std::_Bit_reference
+ size=16 align=8
+ base size=16 base align=8
+std::_Bit_reference (0x0x7f3bfc8c5000) 0
+
+Class std::_Bit_iterator_base
+ size=16 align=8
+ base size=12 base align=8
+std::_Bit_iterator_base (0x0x7f3bfcbf2478) 0
+ std::iterator<std::random_access_iterator_tag, bool> (0x0x7f3bfc8c5720) 0 empty
+
+Class std::_Bit_iterator
+ size=16 align=8
+ base size=12 base align=8
+std::_Bit_iterator (0x0x7f3bfcbf25b0) 0
+ std::_Bit_iterator_base (0x0x7f3bfcbf2618) 0
+ std::iterator<std::random_access_iterator_tag, bool> (0x0x7f3bfc8c5d80) 0 empty
+
+Class std::_Bit_const_iterator
+ size=16 align=8
+ base size=12 base align=8
+std::_Bit_const_iterator (0x0x7f3bfcbf2680) 0
+ std::_Bit_iterator_base (0x0x7f3bfcbf26e8) 0
+ std::iterator<std::random_access_iterator_tag, bool> (0x0x7f3bfc8fd5a0) 0 empty
+
+Class std::__detail::_List_node_base
+ size=16 align=8
+ base size=16 base align=8
+std::__detail::_List_node_base (0x0x7f3bfc748120) 0
+
+Class QListData::NotArrayCompatibleLayout
+ size=1 align=1
+ base size=0 base align=1
+QListData::NotArrayCompatibleLayout (0x0x7f3bfc7f5ea0) 0 empty
+
+Class QListData::NotIndirectLayout
+ size=1 align=1
+ base size=0 base align=1
+QListData::NotIndirectLayout (0x0x7f3bfc7f5f00) 0 empty
+
+Class QListData::ArrayCompatibleLayout
+ size=1 align=1
+ base size=1 base align=1
+QListData::ArrayCompatibleLayout (0x0x7f3bfc744208) 0 empty
+ QListData::NotIndirectLayout (0x0x7f3bfc7f5f60) 0 empty
+
+Class QListData::InlineWithPaddingLayout
+ size=1 align=1
+ base size=1 base align=1
+QListData::InlineWithPaddingLayout (0x0x7f3bfc738af0) 0 empty
+ QListData::NotArrayCompatibleLayout (0x0x7f3bfc80d000) 0 empty
+ QListData::NotIndirectLayout (0x0x7f3bfc80d060) 0 empty
+
+Class QListData::IndirectLayout
+ size=1 align=1
+ base size=1 base align=1
+QListData::IndirectLayout (0x0x7f3bfc744270) 0 empty
+ QListData::NotArrayCompatibleLayout (0x0x7f3bfc80d0c0) 0 empty
+
+Class QListData::Data
+ size=24 align=8
+ base size=24 base align=8
+QListData::Data (0x0x7f3bfc80d120) 0
+
+Class QListData
+ size=8 align=8
+ base size=8 base align=8
+QListData (0x0x7f3bfc7f5e40) 0
+
+Class QRegExp
+ size=8 align=8
+ base size=8 base align=8
+QRegExp (0x0x7f3bfc5072a0) 0
+
+Class QStringMatcher::Data
+ size=272 align=8
+ base size=272 base align=8
+QStringMatcher::Data (0x0x7f3bfc5e57e0) 0
+
+Class QStringMatcher
+ size=1048 align=8
+ base size=1048 base align=8
+QStringMatcher (0x0x7f3bfc5e5780) 0
+
+Class QStringList
+ size=8 align=8
+ base size=8 base align=8
+QStringList (0x0x7f3bfc5d5f08) 0
+ QList<QString> (0x0x7f3bfc5d5f70) 0
+ QListSpecialMethods<QString> (0x0x7f3bfc5e5a20) 0 empty
+
+Class QScopedPointerPodDeleter
+ size=1 align=1
+ base size=0 base align=1
+QScopedPointerPodDeleter (0x0x7f3bfc2b4960) 0 empty
+
+Class std::_Rb_tree_node_base
+ size=32 align=8
+ base size=32 base align=8
+std::_Rb_tree_node_base (0x0x7f3bfc34aba0) 0
+
+Class std::_Rb_tree_header
+ size=40 align=8
+ base size=40 base align=8
+std::_Rb_tree_header (0x0x7f3bfc34af00) 0
+
+Class QtPrivate::AbstractDebugStreamFunction
+ size=16 align=8
+ base size=16 base align=8
+QtPrivate::AbstractDebugStreamFunction (0x0x7f3bfc0a6540) 0
+
+Class QtPrivate::AbstractComparatorFunction
+ size=24 align=8
+ base size=24 base align=8
+QtPrivate::AbstractComparatorFunction (0x0x7f3bfc0a68a0) 0
+
+Class QtPrivate::AbstractConverterFunction
+ size=8 align=8
+ base size=8 base align=8
+QtPrivate::AbstractConverterFunction (0x0x7f3bfc0a6de0) 0
+
+Class QMetaType
+ size=80 align=8
+ base size=80 base align=8
+QMetaType (0x0x7f3bfc0cb360) 0
+
+Class QtMetaTypePrivate::VariantData
+ size=24 align=8
+ base size=20 base align=8
+QtMetaTypePrivate::VariantData (0x0x7f3bfc136540) 0
+
+Class QtMetaTypePrivate::VectorBoolElements
+ size=1 align=1
+ base size=0 base align=1
+QtMetaTypePrivate::VectorBoolElements (0x0x7f3bfc136c00) 0 empty
+
+Class QtMetaTypePrivate::QSequentialIterableImpl
+ size=104 align=8
+ base size=104 base align=8
+QtMetaTypePrivate::QSequentialIterableImpl (0x0x7f3bfbd8da80) 0
+
+Class QtMetaTypePrivate::QAssociativeIterableImpl
+ size=112 align=8
+ base size=112 base align=8
+QtMetaTypePrivate::QAssociativeIterableImpl (0x0x7f3bfbe46180) 0
+
+Class QtMetaTypePrivate::QPairVariantInterfaceImpl
+ size=40 align=8
+ base size=40 base align=8
+QtMetaTypePrivate::QPairVariantInterfaceImpl (0x0x7f3bfbe9d6c0) 0
+
+Class std::chrono::_V2::system_clock
+ size=1 align=1
+ base size=0 base align=1
+std::chrono::_V2::system_clock (0x0x7f3bfbd30c60) 0 empty
+
+Class std::chrono::_V2::steady_clock
+ size=1 align=1
+ base size=0 base align=1
+std::chrono::_V2::steady_clock (0x0x7f3bfba65720) 0 empty
+
+Vtable for QObjectData
+QObjectData::_ZTV11QObjectData: 4 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI11QObjectData)
+16 (int (*)(...))__cxa_pure_virtual
+24 (int (*)(...))__cxa_pure_virtual
+
+Class QObjectData
+ size=48 align=8
+ base size=48 base align=8
+QObjectData (0x0x7f3bfba65780) 0
+ vptr=((& QObjectData::_ZTV11QObjectData) + 16)
+
+Class QObject::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QObject::QPrivateSignal (0x0x7f3bfba65960) 0 empty
+
+Vtable for QObject
+QObject::_ZTV7QObject: 14 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI7QObject)
+16 (int (*)(...))QObject::metaObject
+24 (int (*)(...))QObject::qt_metacast
+32 (int (*)(...))QObject::qt_metacall
+40 (int (*)(...))QObject::~QObject
+48 (int (*)(...))QObject::~QObject
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+
+Class QObject
+ size=16 align=8
+ base size=16 base align=8
+QObject (0x0x7f3bfba65900) 0
+ vptr=((& QObject::_ZTV7QObject) + 16)
+
+Vtable for QObjectUserData
+QObjectUserData::_ZTV15QObjectUserData: 4 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI15QObjectUserData)
+16 (int (*)(...))QObjectUserData::~QObjectUserData
+24 (int (*)(...))QObjectUserData::~QObjectUserData
+
+Class QObjectUserData
+ size=8 align=8
+ base size=8 base align=8
+QObjectUserData (0x0x7f3bfb749780) 0 nearly-empty
+ vptr=((& QObjectUserData::_ZTV15QObjectUserData) + 16)
+
+Class QSignalBlocker
+ size=16 align=8
+ base size=10 base align=8
+QSignalBlocker (0x0x7f3bfb749900) 0
+
+Class QAbstractAnimation::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QAbstractAnimation::QPrivateSignal (0x0x7f3bfb76c1e0) 0 empty
+
+Vtable for QAbstractAnimation
+QAbstractAnimation::_ZTV18QAbstractAnimation: 18 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI18QAbstractAnimation)
+16 (int (*)(...))QAbstractAnimation::metaObject
+24 (int (*)(...))QAbstractAnimation::qt_metacast
+32 (int (*)(...))QAbstractAnimation::qt_metacall
+40 0
+48 0
+56 (int (*)(...))QAbstractAnimation::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))__cxa_pure_virtual
+120 (int (*)(...))__cxa_pure_virtual
+128 (int (*)(...))QAbstractAnimation::updateState
+136 (int (*)(...))QAbstractAnimation::updateDirection
+
+Class QAbstractAnimation
+ size=16 align=8
+ base size=16 base align=8
+QAbstractAnimation (0x0x7f3bfb74d0d0) 0
+ vptr=((& QAbstractAnimation::_ZTV18QAbstractAnimation) + 16)
+ QObject (0x0x7f3bfb76c180) 0
+ primary-for QAbstractAnimation (0x0x7f3bfb74d0d0)
+
+Class QAnimationDriver::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QAnimationDriver::QPrivateSignal (0x0x7f3bfb76c5a0) 0 empty
+
+Vtable for QAnimationDriver
+QAnimationDriver::_ZTV16QAnimationDriver: 18 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI16QAnimationDriver)
+16 (int (*)(...))QAnimationDriver::metaObject
+24 (int (*)(...))QAnimationDriver::qt_metacast
+32 (int (*)(...))QAnimationDriver::qt_metacall
+40 (int (*)(...))QAnimationDriver::~QAnimationDriver
+48 (int (*)(...))QAnimationDriver::~QAnimationDriver
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QAnimationDriver::advance
+120 (int (*)(...))QAnimationDriver::elapsed
+128 (int (*)(...))QAnimationDriver::start
+136 (int (*)(...))QAnimationDriver::stop
+
+Class QAnimationDriver
+ size=16 align=8
+ base size=16 base align=8
+QAnimationDriver (0x0x7f3bfb74d138) 0
+ vptr=((& QAnimationDriver::_ZTV16QAnimationDriver) + 16)
+ QObject (0x0x7f3bfb76c540) 0
+ primary-for QAnimationDriver (0x0x7f3bfb74d138)
+
+Class QEventLoop::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QEventLoop::QPrivateSignal (0x0x7f3bfb76c7e0) 0 empty
+
+Vtable for QEventLoop
+QEventLoop::_ZTV10QEventLoop: 14 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI10QEventLoop)
+16 (int (*)(...))QEventLoop::metaObject
+24 (int (*)(...))QEventLoop::qt_metacast
+32 (int (*)(...))QEventLoop::qt_metacall
+40 (int (*)(...))QEventLoop::~QEventLoop
+48 (int (*)(...))QEventLoop::~QEventLoop
+56 (int (*)(...))QEventLoop::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+
+Class QEventLoop
+ size=16 align=8
+ base size=16 base align=8
+QEventLoop (0x0x7f3bfb74d1a0) 0
+ vptr=((& QEventLoop::_ZTV10QEventLoop) + 16)
+ QObject (0x0x7f3bfb76c780) 0
+ primary-for QEventLoop (0x0x7f3bfb74d1a0)
+
+Class QEventLoopLocker
+ size=8 align=8
+ base size=8 base align=8
+QEventLoopLocker (0x0x7f3bfb7ca0c0) 0
+
+Class QAbstractEventDispatcher::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QAbstractEventDispatcher::QPrivateSignal (0x0x7f3bfb7ca180) 0 empty
+
+Class QAbstractEventDispatcher::TimerInfo
+ size=12 align=4
+ base size=12 base align=4
+QAbstractEventDispatcher::TimerInfo (0x0x7f3bfb7ca1e0) 0
+
+Vtable for QAbstractEventDispatcher
+QAbstractEventDispatcher::_ZTV24QAbstractEventDispatcher: 28 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI24QAbstractEventDispatcher)
+16 (int (*)(...))QAbstractEventDispatcher::metaObject
+24 (int (*)(...))QAbstractEventDispatcher::qt_metacast
+32 (int (*)(...))QAbstractEventDispatcher::qt_metacall
+40 0
+48 0
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))__cxa_pure_virtual
+120 (int (*)(...))__cxa_pure_virtual
+128 (int (*)(...))__cxa_pure_virtual
+136 (int (*)(...))__cxa_pure_virtual
+144 (int (*)(...))__cxa_pure_virtual
+152 (int (*)(...))__cxa_pure_virtual
+160 (int (*)(...))__cxa_pure_virtual
+168 (int (*)(...))__cxa_pure_virtual
+176 (int (*)(...))__cxa_pure_virtual
+184 (int (*)(...))__cxa_pure_virtual
+192 (int (*)(...))__cxa_pure_virtual
+200 (int (*)(...))__cxa_pure_virtual
+208 (int (*)(...))QAbstractEventDispatcher::startingUp
+216 (int (*)(...))QAbstractEventDispatcher::closingDown
+
+Class QAbstractEventDispatcher
+ size=16 align=8
+ base size=16 base align=8
+QAbstractEventDispatcher (0x0x7f3bfb74d2d8) 0
+ vptr=((& QAbstractEventDispatcher::_ZTV24QAbstractEventDispatcher) + 16)
+ QObject (0x0x7f3bfb7ca120) 0
+ primary-for QAbstractEventDispatcher (0x0x7f3bfb74d2d8)
+
+Class QMapNodeBase
+ size=24 align=8
+ base size=24 base align=8
+QMapNodeBase (0x0x7f3bfb8201e0) 0
+
+Class QMapDataBase
+ size=40 align=8
+ base size=40 base align=8
+QMapDataBase (0x0x7f3bfb820e40) 0
+
+Class QHashData::Node
+ size=16 align=8
+ base size=16 base align=8
+QHashData::Node (0x0x7f3bfb9117e0) 0
+
+Class QHashData
+ size=48 align=8
+ base size=44 base align=8
+QHashData (0x0x7f3bfb911780) 0
+
+Class QHashDummyValue
+ size=1 align=1
+ base size=0 base align=1
+QHashDummyValue (0x0x7f3bfb911a80) 0 empty
+
+Class QVariant::PrivateShared
+ size=16 align=8
+ base size=12 base align=8
+QVariant::PrivateShared (0x0x7f3bfb6451e0) 0
+
+Class QVariant::Private::Data
+ size=8 align=8
+ base size=8 base align=8
+QVariant::Private::Data (0x0x7f3bfb6452a0) 0
+
+Class QVariant::Private
+ size=16 align=8
+ base size=12 base align=8
+QVariant::Private (0x0x7f3bfb645240) 0
+
+Class QVariant::Handler
+ size=72 align=8
+ base size=72 base align=8
+QVariant::Handler (0x0x7f3bfb645300) 0
+
+Class QVariant
+ size=16 align=8
+ base size=16 base align=8
+QVariant (0x0x7f3bfb645180) 0
+
+Class QVariantComparisonHelper
+ size=8 align=8
+ base size=8 base align=8
+QVariantComparisonHelper (0x0x7f3bfb3a55a0) 0
+
+Class QSequentialIterable::const_iterator
+ size=112 align=8
+ base size=112 base align=8
+QSequentialIterable::const_iterator (0x0x7f3bfb3e7c00) 0
+
+Class QSequentialIterable
+ size=104 align=8
+ base size=104 base align=8
+QSequentialIterable (0x0x7f3bfb3e7ba0) 0
+
+Class QAssociativeIterable::const_iterator
+ size=120 align=8
+ base size=120 base align=8
+QAssociativeIterable::const_iterator (0x0x7f3bfb3e7d20) 0
+
+Class QAssociativeIterable
+ size=112 align=8
+ base size=112 base align=8
+QAssociativeIterable (0x0x7f3bfb3e7cc0) 0
+
+Class QModelIndex
+ size=24 align=8
+ base size=24 base align=8
+QModelIndex (0x0x7f3bfb4b3ea0) 0
+
+Class QPersistentModelIndex
+ size=8 align=8
+ base size=8 base align=8
+QPersistentModelIndex (0x0x7f3bfb526ae0) 0
+
+Class QAbstractItemModel::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QAbstractItemModel::QPrivateSignal (0x0x7f3bfb1f5900) 0 empty
+
+Vtable for QAbstractItemModel
+QAbstractItemModel::_ZTV18QAbstractItemModel: 48 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI18QAbstractItemModel)
+16 (int (*)(...))QAbstractItemModel::metaObject
+24 (int (*)(...))QAbstractItemModel::qt_metacast
+32 (int (*)(...))QAbstractItemModel::qt_metacall
+40 0
+48 0
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))__cxa_pure_virtual
+120 (int (*)(...))__cxa_pure_virtual
+128 (int (*)(...))QAbstractItemModel::sibling
+136 (int (*)(...))__cxa_pure_virtual
+144 (int (*)(...))__cxa_pure_virtual
+152 (int (*)(...))QAbstractItemModel::hasChildren
+160 (int (*)(...))__cxa_pure_virtual
+168 (int (*)(...))QAbstractItemModel::setData
+176 (int (*)(...))QAbstractItemModel::headerData
+184 (int (*)(...))QAbstractItemModel::setHeaderData
+192 (int (*)(...))QAbstractItemModel::itemData
+200 (int (*)(...))QAbstractItemModel::setItemData
+208 (int (*)(...))QAbstractItemModel::mimeTypes
+216 (int (*)(...))QAbstractItemModel::mimeData
+224 (int (*)(...))QAbstractItemModel::canDropMimeData
+232 (int (*)(...))QAbstractItemModel::dropMimeData
+240 (int (*)(...))QAbstractItemModel::supportedDropActions
+248 (int (*)(...))QAbstractItemModel::supportedDragActions
+256 (int (*)(...))QAbstractItemModel::insertRows
+264 (int (*)(...))QAbstractItemModel::insertColumns
+272 (int (*)(...))QAbstractItemModel::removeRows
+280 (int (*)(...))QAbstractItemModel::removeColumns
+288 (int (*)(...))QAbstractItemModel::moveRows
+296 (int (*)(...))QAbstractItemModel::moveColumns
+304 (int (*)(...))QAbstractItemModel::fetchMore
+312 (int (*)(...))QAbstractItemModel::canFetchMore
+320 (int (*)(...))QAbstractItemModel::flags
+328 (int (*)(...))QAbstractItemModel::sort
+336 (int (*)(...))QAbstractItemModel::buddy
+344 (int (*)(...))QAbstractItemModel::match
+352 (int (*)(...))QAbstractItemModel::span
+360 (int (*)(...))QAbstractItemModel::roleNames
+368 (int (*)(...))QAbstractItemModel::submit
+376 (int (*)(...))QAbstractItemModel::revert
+
+Class QAbstractItemModel
+ size=16 align=8
+ base size=16 base align=8
+QAbstractItemModel (0x0x7f3bfb203478) 0
+ vptr=((& QAbstractItemModel::_ZTV18QAbstractItemModel) + 16)
+ QObject (0x0x7f3bfb1f58a0) 0
+ primary-for QAbstractItemModel (0x0x7f3bfb203478)
+
+Class QAbstractTableModel::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QAbstractTableModel::QPrivateSignal (0x0x7f3bfb26ecc0) 0 empty
+
+Vtable for QAbstractTableModel
+QAbstractTableModel::_ZTV19QAbstractTableModel: 48 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI19QAbstractTableModel)
+16 (int (*)(...))QAbstractTableModel::metaObject
+24 (int (*)(...))QAbstractTableModel::qt_metacast
+32 (int (*)(...))QAbstractTableModel::qt_metacall
+40 0
+48 0
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QAbstractTableModel::index
+120 (int (*)(...))QAbstractTableModel::parent
+128 (int (*)(...))QAbstractTableModel::sibling
+136 (int (*)(...))__cxa_pure_virtual
+144 (int (*)(...))__cxa_pure_virtual
+152 (int (*)(...))QAbstractTableModel::hasChildren
+160 (int (*)(...))__cxa_pure_virtual
+168 (int (*)(...))QAbstractItemModel::setData
+176 (int (*)(...))QAbstractItemModel::headerData
+184 (int (*)(...))QAbstractItemModel::setHeaderData
+192 (int (*)(...))QAbstractItemModel::itemData
+200 (int (*)(...))QAbstractItemModel::setItemData
+208 (int (*)(...))QAbstractItemModel::mimeTypes
+216 (int (*)(...))QAbstractItemModel::mimeData
+224 (int (*)(...))QAbstractItemModel::canDropMimeData
+232 (int (*)(...))QAbstractTableModel::dropMimeData
+240 (int (*)(...))QAbstractItemModel::supportedDropActions
+248 (int (*)(...))QAbstractItemModel::supportedDragActions
+256 (int (*)(...))QAbstractItemModel::insertRows
+264 (int (*)(...))QAbstractItemModel::insertColumns
+272 (int (*)(...))QAbstractItemModel::removeRows
+280 (int (*)(...))QAbstractItemModel::removeColumns
+288 (int (*)(...))QAbstractItemModel::moveRows
+296 (int (*)(...))QAbstractItemModel::moveColumns
+304 (int (*)(...))QAbstractItemModel::fetchMore
+312 (int (*)(...))QAbstractItemModel::canFetchMore
+320 (int (*)(...))QAbstractTableModel::flags
+328 (int (*)(...))QAbstractItemModel::sort
+336 (int (*)(...))QAbstractItemModel::buddy
+344 (int (*)(...))QAbstractItemModel::match
+352 (int (*)(...))QAbstractItemModel::span
+360 (int (*)(...))QAbstractItemModel::roleNames
+368 (int (*)(...))QAbstractItemModel::submit
+376 (int (*)(...))QAbstractItemModel::revert
+
+Class QAbstractTableModel
+ size=16 align=8
+ base size=16 base align=8
+QAbstractTableModel (0x0x7f3bfb203a90) 0
+ vptr=((& QAbstractTableModel::_ZTV19QAbstractTableModel) + 16)
+ QAbstractItemModel (0x0x7f3bfb203af8) 0
+ primary-for QAbstractTableModel (0x0x7f3bfb203a90)
+ QObject (0x0x7f3bfb26ec60) 0
+ primary-for QAbstractItemModel (0x0x7f3bfb203af8)
+
+Class QAbstractListModel::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QAbstractListModel::QPrivateSignal (0x0x7f3bfb26ee40) 0 empty
+
+Vtable for QAbstractListModel
+QAbstractListModel::_ZTV18QAbstractListModel: 48 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI18QAbstractListModel)
+16 (int (*)(...))QAbstractListModel::metaObject
+24 (int (*)(...))QAbstractListModel::qt_metacast
+32 (int (*)(...))QAbstractListModel::qt_metacall
+40 0
+48 0
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QAbstractListModel::index
+120 (int (*)(...))QAbstractListModel::parent
+128 (int (*)(...))QAbstractListModel::sibling
+136 (int (*)(...))__cxa_pure_virtual
+144 (int (*)(...))QAbstractListModel::columnCount
+152 (int (*)(...))QAbstractListModel::hasChildren
+160 (int (*)(...))__cxa_pure_virtual
+168 (int (*)(...))QAbstractItemModel::setData
+176 (int (*)(...))QAbstractItemModel::headerData
+184 (int (*)(...))QAbstractItemModel::setHeaderData
+192 (int (*)(...))QAbstractItemModel::itemData
+200 (int (*)(...))QAbstractItemModel::setItemData
+208 (int (*)(...))QAbstractItemModel::mimeTypes
+216 (int (*)(...))QAbstractItemModel::mimeData
+224 (int (*)(...))QAbstractItemModel::canDropMimeData
+232 (int (*)(...))QAbstractListModel::dropMimeData
+240 (int (*)(...))QAbstractItemModel::supportedDropActions
+248 (int (*)(...))QAbstractItemModel::supportedDragActions
+256 (int (*)(...))QAbstractItemModel::insertRows
+264 (int (*)(...))QAbstractItemModel::insertColumns
+272 (int (*)(...))QAbstractItemModel::removeRows
+280 (int (*)(...))QAbstractItemModel::removeColumns
+288 (int (*)(...))QAbstractItemModel::moveRows
+296 (int (*)(...))QAbstractItemModel::moveColumns
+304 (int (*)(...))QAbstractItemModel::fetchMore
+312 (int (*)(...))QAbstractItemModel::canFetchMore
+320 (int (*)(...))QAbstractListModel::flags
+328 (int (*)(...))QAbstractItemModel::sort
+336 (int (*)(...))QAbstractItemModel::buddy
+344 (int (*)(...))QAbstractItemModel::match
+352 (int (*)(...))QAbstractItemModel::span
+360 (int (*)(...))QAbstractItemModel::roleNames
+368 (int (*)(...))QAbstractItemModel::submit
+376 (int (*)(...))QAbstractItemModel::revert
+
+Class QAbstractListModel
+ size=16 align=8
+ base size=16 base align=8
+QAbstractListModel (0x0x7f3bfb203b60) 0
+ vptr=((& QAbstractListModel::_ZTV18QAbstractListModel) + 16)
+ QAbstractItemModel (0x0x7f3bfb203bc8) 0
+ primary-for QAbstractListModel (0x0x7f3bfb203b60)
+ QObject (0x0x7f3bfb26ede0) 0
+ primary-for QAbstractItemModel (0x0x7f3bfb203bc8)
+
+Vtable for QAbstractNativeEventFilter
+QAbstractNativeEventFilter::_ZTV26QAbstractNativeEventFilter: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI26QAbstractNativeEventFilter)
+16 0
+24 0
+32 (int (*)(...))__cxa_pure_virtual
+
+Class QAbstractNativeEventFilter
+ size=16 align=8
+ base size=16 base align=8
+QAbstractNativeEventFilter (0x0x7f3bfb2f65a0) 0
+ vptr=((& QAbstractNativeEventFilter::_ZTV26QAbstractNativeEventFilter) + 16)
+
+Class QAbstractProxyModel::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QAbstractProxyModel::QPrivateSignal (0x0x7f3bfb2f6660) 0 empty
+
+Vtable for QAbstractProxyModel
+QAbstractProxyModel::_ZTV19QAbstractProxyModel: 53 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI19QAbstractProxyModel)
+16 (int (*)(...))QAbstractProxyModel::metaObject
+24 (int (*)(...))QAbstractProxyModel::qt_metacast
+32 (int (*)(...))QAbstractProxyModel::qt_metacall
+40 0
+48 0
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))__cxa_pure_virtual
+120 (int (*)(...))__cxa_pure_virtual
+128 (int (*)(...))QAbstractProxyModel::sibling
+136 (int (*)(...))__cxa_pure_virtual
+144 (int (*)(...))__cxa_pure_virtual
+152 (int (*)(...))QAbstractProxyModel::hasChildren
+160 (int (*)(...))QAbstractProxyModel::data
+168 (int (*)(...))QAbstractProxyModel::setData
+176 (int (*)(...))QAbstractProxyModel::headerData
+184 (int (*)(...))QAbstractProxyModel::setHeaderData
+192 (int (*)(...))QAbstractProxyModel::itemData
+200 (int (*)(...))QAbstractProxyModel::setItemData
+208 (int (*)(...))QAbstractProxyModel::mimeTypes
+216 (int (*)(...))QAbstractProxyModel::mimeData
+224 (int (*)(...))QAbstractProxyModel::canDropMimeData
+232 (int (*)(...))QAbstractProxyModel::dropMimeData
+240 (int (*)(...))QAbstractProxyModel::supportedDropActions
+248 (int (*)(...))QAbstractProxyModel::supportedDragActions
+256 (int (*)(...))QAbstractItemModel::insertRows
+264 (int (*)(...))QAbstractItemModel::insertColumns
+272 (int (*)(...))QAbstractItemModel::removeRows
+280 (int (*)(...))QAbstractItemModel::removeColumns
+288 (int (*)(...))QAbstractItemModel::moveRows
+296 (int (*)(...))QAbstractItemModel::moveColumns
+304 (int (*)(...))QAbstractProxyModel::fetchMore
+312 (int (*)(...))QAbstractProxyModel::canFetchMore
+320 (int (*)(...))QAbstractProxyModel::flags
+328 (int (*)(...))QAbstractProxyModel::sort
+336 (int (*)(...))QAbstractProxyModel::buddy
+344 (int (*)(...))QAbstractItemModel::match
+352 (int (*)(...))QAbstractProxyModel::span
+360 (int (*)(...))QAbstractItemModel::roleNames
+368 (int (*)(...))QAbstractProxyModel::submit
+376 (int (*)(...))QAbstractProxyModel::revert
+384 (int (*)(...))QAbstractProxyModel::setSourceModel
+392 (int (*)(...))__cxa_pure_virtual
+400 (int (*)(...))__cxa_pure_virtual
+408 (int (*)(...))QAbstractProxyModel::mapSelectionToSource
+416 (int (*)(...))QAbstractProxyModel::mapSelectionFromSource
+
+Class QAbstractProxyModel
+ size=16 align=8
+ base size=16 base align=8
+QAbstractProxyModel (0x0x7f3bfb203c98) 0
+ vptr=((& QAbstractProxyModel::_ZTV19QAbstractProxyModel) + 16)
+ QAbstractItemModel (0x0x7f3bfb203d00) 0
+ primary-for QAbstractProxyModel (0x0x7f3bfb203c98)
+ QObject (0x0x7f3bfb2f6600) 0
+ primary-for QAbstractItemModel (0x0x7f3bfb203d00)
+
+Class QAbstractState::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QAbstractState::QPrivateSignal (0x0x7f3bfb2f68a0) 0 empty
+
+Vtable for QAbstractState
+QAbstractState::_ZTV14QAbstractState: 16 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI14QAbstractState)
+16 (int (*)(...))QAbstractState::metaObject
+24 (int (*)(...))QAbstractState::qt_metacast
+32 (int (*)(...))QAbstractState::qt_metacall
+40 0
+48 0
+56 (int (*)(...))QAbstractState::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))__cxa_pure_virtual
+120 (int (*)(...))__cxa_pure_virtual
+
+Class QAbstractState
+ size=16 align=8
+ base size=16 base align=8
+QAbstractState (0x0x7f3bfb203d68) 0
+ vptr=((& QAbstractState::_ZTV14QAbstractState) + 16)
+ QObject (0x0x7f3bfb2f6840) 0
+ primary-for QAbstractState (0x0x7f3bfb203d68)
+
+Class QAbstractTransition::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QAbstractTransition::QPrivateSignal (0x0x7f3bfb2f6ae0) 0 empty
+
+Vtable for QAbstractTransition
+QAbstractTransition::_ZTV19QAbstractTransition: 16 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI19QAbstractTransition)
+16 (int (*)(...))QAbstractTransition::metaObject
+24 (int (*)(...))QAbstractTransition::qt_metacast
+32 (int (*)(...))QAbstractTransition::qt_metacall
+40 0
+48 0
+56 (int (*)(...))QAbstractTransition::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))__cxa_pure_virtual
+120 (int (*)(...))__cxa_pure_virtual
+
+Class QAbstractTransition
+ size=16 align=8
+ base size=16 base align=8
+QAbstractTransition (0x0x7f3bfb203dd0) 0
+ vptr=((& QAbstractTransition::_ZTV19QAbstractTransition) + 16)
+ QObject (0x0x7f3bfb2f6a80) 0
+ primary-for QAbstractTransition (0x0x7f3bfb203dd0)
+
+Class QAnimationGroup::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QAnimationGroup::QPrivateSignal (0x0x7f3bfb2f6de0) 0 empty
+
+Vtable for QAnimationGroup
+QAnimationGroup::_ZTV15QAnimationGroup: 18 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI15QAnimationGroup)
+16 (int (*)(...))QAnimationGroup::metaObject
+24 (int (*)(...))QAnimationGroup::qt_metacast
+32 (int (*)(...))QAnimationGroup::qt_metacall
+40 0
+48 0
+56 (int (*)(...))QAnimationGroup::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))__cxa_pure_virtual
+120 (int (*)(...))__cxa_pure_virtual
+128 (int (*)(...))QAbstractAnimation::updateState
+136 (int (*)(...))QAbstractAnimation::updateDirection
+
+Class QAnimationGroup
+ size=16 align=8
+ base size=16 base align=8
+QAnimationGroup (0x0x7f3bfb203e38) 0
+ vptr=((& QAnimationGroup::_ZTV15QAnimationGroup) + 16)
+ QAbstractAnimation (0x0x7f3bfb203ea0) 0
+ primary-for QAnimationGroup (0x0x7f3bfb203e38)
+ QObject (0x0x7f3bfb2f6d80) 0
+ primary-for QAbstractAnimation (0x0x7f3bfb203ea0)
+
+Class QBasicTimer
+ size=4 align=4
+ base size=4 base align=4
+QBasicTimer (0x0x7f3bfafc9120) 0
+
+Class QBitArray
+ size=8 align=8
+ base size=8 base align=8
+QBitArray (0x0x7f3bfb04aa80) 0
+
+Class QBitRef
+ size=16 align=8
+ base size=12 base align=8
+QBitRef (0x0x7f3bfb099f00) 0
+
+Class QIODevice::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QIODevice::QPrivateSignal (0x0x7f3bfb10f1e0) 0 empty
+
+Vtable for QIODevice
+QIODevice::_ZTV9QIODevice: 30 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI9QIODevice)
+16 (int (*)(...))QIODevice::metaObject
+24 (int (*)(...))QIODevice::qt_metacast
+32 (int (*)(...))QIODevice::qt_metacall
+40 0
+48 0
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QIODevice::isSequential
+120 (int (*)(...))QIODevice::open
+128 (int (*)(...))QIODevice::close
+136 (int (*)(...))QIODevice::pos
+144 (int (*)(...))QIODevice::size
+152 (int (*)(...))QIODevice::seek
+160 (int (*)(...))QIODevice::atEnd
+168 (int (*)(...))QIODevice::reset
+176 (int (*)(...))QIODevice::bytesAvailable
+184 (int (*)(...))QIODevice::bytesToWrite
+192 (int (*)(...))QIODevice::canReadLine
+200 (int (*)(...))QIODevice::waitForReadyRead
+208 (int (*)(...))QIODevice::waitForBytesWritten
+216 (int (*)(...))__cxa_pure_virtual
+224 (int (*)(...))QIODevice::readLineData
+232 (int (*)(...))__cxa_pure_virtual
+
+Class QIODevice
+ size=16 align=8
+ base size=16 base align=8
+QIODevice (0x0x7f3bfb108478) 0
+ vptr=((& QIODevice::_ZTV9QIODevice) + 16)
+ QObject (0x0x7f3bfb10f180) 0
+ primary-for QIODevice (0x0x7f3bfb108478)
+
+Class QBuffer::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QBuffer::QPrivateSignal (0x0x7f3bfb10fb40) 0 empty
+
+Vtable for QBuffer
+QBuffer::_ZTV7QBuffer: 30 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI7QBuffer)
+16 (int (*)(...))QBuffer::metaObject
+24 (int (*)(...))QBuffer::qt_metacast
+32 (int (*)(...))QBuffer::qt_metacall
+40 (int (*)(...))QBuffer::~QBuffer
+48 (int (*)(...))QBuffer::~QBuffer
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QBuffer::connectNotify
+104 (int (*)(...))QBuffer::disconnectNotify
+112 (int (*)(...))QIODevice::isSequential
+120 (int (*)(...))QBuffer::open
+128 (int (*)(...))QBuffer::close
+136 (int (*)(...))QBuffer::pos
+144 (int (*)(...))QBuffer::size
+152 (int (*)(...))QBuffer::seek
+160 (int (*)(...))QBuffer::atEnd
+168 (int (*)(...))QIODevice::reset
+176 (int (*)(...))QIODevice::bytesAvailable
+184 (int (*)(...))QIODevice::bytesToWrite
+192 (int (*)(...))QBuffer::canReadLine
+200 (int (*)(...))QIODevice::waitForReadyRead
+208 (int (*)(...))QIODevice::waitForBytesWritten
+216 (int (*)(...))QBuffer::readData
+224 (int (*)(...))QIODevice::readLineData
+232 (int (*)(...))QBuffer::writeData
+
+Class QBuffer
+ size=16 align=8
+ base size=16 base align=8
+QBuffer (0x0x7f3bfb1085b0) 0
+ vptr=((& QBuffer::_ZTV7QBuffer) + 16)
+ QIODevice (0x0x7f3bfb108618) 0
+ primary-for QBuffer (0x0x7f3bfb1085b0)
+ QObject (0x0x7f3bfb10fae0) 0
+ primary-for QIODevice (0x0x7f3bfb108618)
+
+Class QByteArrayMatcher::Data
+ size=272 align=8
+ base size=272 base align=8
+QByteArrayMatcher::Data (0x0x7f3bfb10fde0) 0
+
+Class QByteArrayMatcher
+ size=1040 align=8
+ base size=1040 base align=8
+QByteArrayMatcher (0x0x7f3bfb10fd80) 0
+
+Class QStaticByteArrayMatcherBase::Skiptable
+ size=256 align=1
+ base size=256 base align=1
+QStaticByteArrayMatcherBase::Skiptable (0x0x7f3bfb10ff60) 0
+
+Class QStaticByteArrayMatcherBase
+ size=256 align=16
+ base size=256 base align=16
+QStaticByteArrayMatcherBase (0x0x7f3bfb10ff00) 0
+
+Class QSharedData
+ size=4 align=4
+ base size=4 base align=4
+QSharedData (0x0x7f3bfad77e40) 0
+
+Class QLocale
+ size=8 align=8
+ base size=8 base align=8
+QLocale (0x0x7f3bfadd4d20) 0
+
+Class QCalendar::YearMonthDay
+ size=12 align=4
+ base size=12 base align=4
+QCalendar::YearMonthDay (0x0x7f3bfab61240) 0
+
+Class QCalendar
+ size=8 align=8
+ base size=8 base align=8
+QCalendar (0x0x7f3bfab611e0) 0
+
+Class QDate
+ size=8 align=8
+ base size=8 base align=8
+QDate (0x0x7f3bfab61a20) 0
+
+Class QTime
+ size=4 align=4
+ base size=4 base align=4
+QTime (0x0x7f3bfabe8300) 0
+
+Class QDateTime::ShortData
+ size=8 align=8
+ base size=8 base align=8
+QDateTime::ShortData (0x0x7f3bfac37f60) 0
+
+Class QDateTime::Data
+ size=8 align=8
+ base size=8 base align=8
+QDateTime::Data (0x0x7f3bfac51000) 0
+
+Class QDateTime
+ size=8 align=8
+ base size=8 base align=8
+QDateTime (0x0x7f3bfac37f00) 0
+
+Vtable for QTextStream
+QTextStream::_ZTV11QTextStream: 4 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI11QTextStream)
+16 (int (*)(...))QTextStream::~QTextStream
+24 (int (*)(...))QTextStream::~QTextStream
+
+Class QTextStream
+ size=16 align=8
+ base size=16 base align=8
+QTextStream (0x0x7f3bfad296c0) 0
+ vptr=((& QTextStream::_ZTV11QTextStream) + 16)
+
+Class QTextStreamManipulator
+ size=40 align=8
+ base size=38 base align=8
+QTextStreamManipulator (0x0x7f3bfad29f60) 0
+
+Class QContiguousCacheData
+ size=24 align=4
+ base size=24 base align=4
+QContiguousCacheData (0x0x7f3bfa9fac00) 0
+
+Vtable for __gnu_cxx::__concurrence_lock_error
+__gnu_cxx::__concurrence_lock_error::_ZTVN9__gnu_cxx24__concurrence_lock_errorE: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTIN9__gnu_cxx24__concurrence_lock_errorE)
+16 (int (*)(...))__gnu_cxx::__concurrence_lock_error::~__concurrence_lock_error
+24 (int (*)(...))__gnu_cxx::__concurrence_lock_error::~__concurrence_lock_error
+32 (int (*)(...))__gnu_cxx::__concurrence_lock_error::what
+
+Class __gnu_cxx::__concurrence_lock_error
+ size=8 align=8
+ base size=8 base align=8
+__gnu_cxx::__concurrence_lock_error (0x0x7f3bfad2a618) 0 nearly-empty
+ vptr=((& __gnu_cxx::__concurrence_lock_error::_ZTVN9__gnu_cxx24__concurrence_lock_errorE) + 16)
+ std::exception (0x0x7f3bfaa43a80) 0 nearly-empty
+ primary-for __gnu_cxx::__concurrence_lock_error (0x0x7f3bfad2a618)
+
+Vtable for __gnu_cxx::__concurrence_unlock_error
+__gnu_cxx::__concurrence_unlock_error::_ZTVN9__gnu_cxx26__concurrence_unlock_errorE: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTIN9__gnu_cxx26__concurrence_unlock_errorE)
+16 (int (*)(...))__gnu_cxx::__concurrence_unlock_error::~__concurrence_unlock_error
+24 (int (*)(...))__gnu_cxx::__concurrence_unlock_error::~__concurrence_unlock_error
+32 (int (*)(...))__gnu_cxx::__concurrence_unlock_error::what
+
+Class __gnu_cxx::__concurrence_unlock_error
+ size=8 align=8
+ base size=8 base align=8
+__gnu_cxx::__concurrence_unlock_error (0x0x7f3bfad2a680) 0 nearly-empty
+ vptr=((& __gnu_cxx::__concurrence_unlock_error::_ZTVN9__gnu_cxx26__concurrence_unlock_errorE) + 16)
+ std::exception (0x0x7f3bfaa43ba0) 0 nearly-empty
+ primary-for __gnu_cxx::__concurrence_unlock_error (0x0x7f3bfad2a680)
+
+Vtable for __gnu_cxx::__concurrence_broadcast_error
+__gnu_cxx::__concurrence_broadcast_error::_ZTVN9__gnu_cxx29__concurrence_broadcast_errorE: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTIN9__gnu_cxx29__concurrence_broadcast_errorE)
+16 (int (*)(...))__gnu_cxx::__concurrence_broadcast_error::~__concurrence_broadcast_error
+24 (int (*)(...))__gnu_cxx::__concurrence_broadcast_error::~__concurrence_broadcast_error
+32 (int (*)(...))__gnu_cxx::__concurrence_broadcast_error::what
+
+Class __gnu_cxx::__concurrence_broadcast_error
+ size=8 align=8
+ base size=8 base align=8
+__gnu_cxx::__concurrence_broadcast_error (0x0x7f3bfad2a6e8) 0 nearly-empty
+ vptr=((& __gnu_cxx::__concurrence_broadcast_error::_ZTVN9__gnu_cxx29__concurrence_broadcast_errorE) + 16)
+ std::exception (0x0x7f3bfaa43cc0) 0 nearly-empty
+ primary-for __gnu_cxx::__concurrence_broadcast_error (0x0x7f3bfad2a6e8)
+
+Vtable for __gnu_cxx::__concurrence_wait_error
+__gnu_cxx::__concurrence_wait_error::_ZTVN9__gnu_cxx24__concurrence_wait_errorE: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTIN9__gnu_cxx24__concurrence_wait_errorE)
+16 (int (*)(...))__gnu_cxx::__concurrence_wait_error::~__concurrence_wait_error
+24 (int (*)(...))__gnu_cxx::__concurrence_wait_error::~__concurrence_wait_error
+32 (int (*)(...))__gnu_cxx::__concurrence_wait_error::what
+
+Class __gnu_cxx::__concurrence_wait_error
+ size=8 align=8
+ base size=8 base align=8
+__gnu_cxx::__concurrence_wait_error (0x0x7f3bfad2a7b8) 0 nearly-empty
+ vptr=((& __gnu_cxx::__concurrence_wait_error::_ZTVN9__gnu_cxx24__concurrence_wait_errorE) + 16)
+ std::exception (0x0x7f3bfaa43de0) 0 nearly-empty
+ primary-for __gnu_cxx::__concurrence_wait_error (0x0x7f3bfad2a7b8)
+
+Class __gnu_cxx::__mutex
+ size=40 align=8
+ base size=40 base align=8
+__gnu_cxx::__mutex (0x0x7f3bfaa6fe40) 0
+
+Class __gnu_cxx::__recursive_mutex
+ size=40 align=8
+ base size=40 base align=8
+__gnu_cxx::__recursive_mutex (0x0x7f3bfaa96180) 0
+
+Class __gnu_cxx::__scoped_lock
+ size=8 align=8
+ base size=8 base align=8
+__gnu_cxx::__scoped_lock (0x0x7f3bfaa96480) 0
+
+Class __gnu_cxx::__cond
+ size=48 align=8
+ base size=48 base align=8
+__gnu_cxx::__cond (0x0x7f3bfaa967e0) 0
+
+Vtable for std::bad_weak_ptr
+std::bad_weak_ptr::_ZTVSt12bad_weak_ptr: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTISt12bad_weak_ptr)
+16 (int (*)(...))std::bad_weak_ptr::~bad_weak_ptr
+24 (int (*)(...))std::bad_weak_ptr::~bad_weak_ptr
+32 (int (*)(...))std::bad_weak_ptr::what
+
+Class std::bad_weak_ptr
+ size=8 align=8
+ base size=8 base align=8
+std::bad_weak_ptr (0x0x7f3bfad2a820) 0 nearly-empty
+ vptr=((& std::bad_weak_ptr::_ZTVSt12bad_weak_ptr) + 16)
+ std::exception (0x0x7f3bfab0a9c0) 0 nearly-empty
+ primary-for std::bad_weak_ptr (0x0x7f3bfad2a820)
+
+Class std::_Sp_make_shared_tag
+ size=1 align=1
+ base size=0 base align=1
+std::_Sp_make_shared_tag (0x0x7f3bfa776960) 0 empty
+
+Class std::__sp_array_delete
+ size=1 align=1
+ base size=0 base align=1
+std::__sp_array_delete (0x0x7f3bfa776d80) 0 empty
+
+Class std::_Sp_locker
+ size=2 align=1
+ base size=2 base align=1
+std::_Sp_locker (0x0x7f3bfa8acc00) 0
+
+Class QtSharedPointer::NormalDeleter
+ size=1 align=1
+ base size=0 base align=1
+QtSharedPointer::NormalDeleter (0x0x7f3bfa90d120) 0 empty
+
+Class QtSharedPointer::ExternalRefCountData
+ size=16 align=8
+ base size=16 base align=8
+QtSharedPointer::ExternalRefCountData (0x0x7f3bfa90d2a0) 0
+
+Class QtPrivate::EnableInternalData
+ size=1 align=1
+ base size=0 base align=1
+QtPrivate::EnableInternalData (0x0x7f3bfa56eba0) 0 empty
+
+Class QDebug::Stream
+ size=80 align=8
+ base size=76 base align=8
+QDebug::Stream (0x0x7f3bfa5c82a0) 0
+
+Class QDebug
+ size=8 align=8
+ base size=8 base align=8
+QDebug (0x0x7f3bfa5c8240) 0
+
+Class QDebugStateSaver
+ size=8 align=8
+ base size=8 base align=8
+QDebugStateSaver (0x0x7f3bfa738ba0) 0
+
+Class QNoDebug
+ size=1 align=1
+ base size=0 base align=1
+QNoDebug (0x0x7f3bfa738c60) 0 empty
+
+Class QCborError
+ size=4 align=4
+ base size=4 base align=4
+QCborError (0x0x7f3bfa3b7ea0) 0
+
+Class QRegularExpression
+ size=8 align=8
+ base size=8 base align=8
+QRegularExpression (0x0x7f3bfa3ea660) 0
+
+Class QRegularExpressionMatch
+ size=8 align=8
+ base size=8 base align=8
+QRegularExpressionMatch (0x0x7f3bfa499540) 0
+
+Class QRegularExpressionMatchIterator
+ size=8 align=8
+ base size=8 base align=8
+QRegularExpressionMatchIterator (0x0x7f3bfa500300) 0
+
+Class QUrl
+ size=8 align=8
+ base size=8 base align=8
+QUrl (0x0x7f3bfa153d20) 0
+
+Class QUuid
+ size=16 align=4
+ base size=16 base align=4
+QUuid (0x0x7f3bfa29acc0) 0
+
+Class QCborParserError
+ size=16 align=8
+ base size=12 base align=8
+QCborParserError (0x0x7f3bfa32f840) 0
+
+Class QCborValue
+ size=24 align=8
+ base size=20 base align=8
+QCborValue (0x0x7f3bfa32f900) 0
+
+Class QCborValueRef
+ size=16 align=8
+ base size=16 base align=8
+QCborValueRef (0x0x7f3bf9daf4e0) 0
+
+Class QCborArray::Iterator
+ size=16 align=8
+ base size=16 base align=8
+QCborArray::Iterator (0x0x7f3bf9e1ff00) 0
+
+Class QCborArray::ConstIterator
+ size=16 align=8
+ base size=16 base align=8
+QCborArray::ConstIterator (0x0x7f3bf9e1ff60) 0
+
+Class QCborArray
+ size=8 align=8
+ base size=8 base align=8
+QCborArray (0x0x7f3bf9e1fea0) 0
+
+Class QCborMap::Iterator
+ size=16 align=8
+ base size=16 base align=8
+QCborMap::Iterator (0x0x7f3bf9ba2b40) 0
+
+Class QCborMap::ConstIterator
+ size=16 align=8
+ base size=16 base align=8
+QCborMap::ConstIterator (0x0x7f3bf9ba2ba0) 0
+
+Class QCborMap
+ size=8 align=8
+ base size=8 base align=8
+QCborMap (0x0x7f3bf9ba2ae0) 0
+
+Class qfloat16::Wrap
+ size=2 align=2
+ base size=2 base align=2
+qfloat16::Wrap (0x0x7f3bf99bf360) 0
+
+Class qfloat16
+ size=2 align=2
+ base size=2 base align=2
+qfloat16 (0x0x7f3bf99bf300) 0
+
+Class QCborStreamWriter
+ size=8 align=8
+ base size=8 base align=8
+QCborStreamWriter (0x0x7f3bf9aaf000) 0
+
+Class QCborStreamReader
+ size=24 align=8
+ base size=20 base align=8
+QCborStreamReader (0x0x7f3bf9aafd20) 0
+
+Class QCollatorSortKey
+ size=8 align=8
+ base size=8 base align=8
+QCollatorSortKey (0x0x7f3bf9740e40) 0
+
+Class QCollator
+ size=8 align=8
+ base size=8 base align=8
+QCollator (0x0x7f3bf976d060) 0
+
+Class QCommandLineOption
+ size=8 align=8
+ base size=8 base align=8
+QCommandLineOption (0x0x7f3bf985d660) 0
+
+Vtable for QEvent
+QEvent::_ZTV6QEvent: 4 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI6QEvent)
+16 (int (*)(...))QEvent::~QEvent
+24 (int (*)(...))QEvent::~QEvent
+
+Class QEvent
+ size=24 align=8
+ base size=20 base align=8
+QEvent (0x0x7f3bf991fba0) 0
+ vptr=((& QEvent::_ZTV6QEvent) + 16)
+
+Vtable for QTimerEvent
+QTimerEvent::_ZTV11QTimerEvent: 4 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI11QTimerEvent)
+16 (int (*)(...))QTimerEvent::~QTimerEvent
+24 (int (*)(...))QTimerEvent::~QTimerEvent
+
+Class QTimerEvent
+ size=24 align=8
+ base size=24 base align=8
+QTimerEvent (0x0x7f3bf9926270) 0
+ vptr=((& QTimerEvent::_ZTV11QTimerEvent) + 16)
+ QEvent (0x0x7f3bf991ff60) 0
+ primary-for QTimerEvent (0x0x7f3bf9926270)
+
+Vtable for QChildEvent
+QChildEvent::_ZTV11QChildEvent: 4 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI11QChildEvent)
+16 (int (*)(...))QChildEvent::~QChildEvent
+24 (int (*)(...))QChildEvent::~QChildEvent
+
+Class QChildEvent
+ size=32 align=8
+ base size=32 base align=8
+QChildEvent (0x0x7f3bf99262d8) 0
+ vptr=((& QChildEvent::_ZTV11QChildEvent) + 16)
+ QEvent (0x0x7f3bf9566060) 0
+ primary-for QChildEvent (0x0x7f3bf99262d8)
+
+Vtable for QDynamicPropertyChangeEvent
+QDynamicPropertyChangeEvent::_ZTV27QDynamicPropertyChangeEvent: 4 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI27QDynamicPropertyChangeEvent)
+16 (int (*)(...))QDynamicPropertyChangeEvent::~QDynamicPropertyChangeEvent
+24 (int (*)(...))QDynamicPropertyChangeEvent::~QDynamicPropertyChangeEvent
+
+Class QDynamicPropertyChangeEvent
+ size=32 align=8
+ base size=32 base align=8
+QDynamicPropertyChangeEvent (0x0x7f3bf9926820) 0
+ vptr=((& QDynamicPropertyChangeEvent::_ZTV27QDynamicPropertyChangeEvent) + 16)
+ QEvent (0x0x7f3bf95666c0) 0
+ primary-for QDynamicPropertyChangeEvent (0x0x7f3bf9926820)
+
+Vtable for QDeferredDeleteEvent
+QDeferredDeleteEvent::_ZTV20QDeferredDeleteEvent: 4 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI20QDeferredDeleteEvent)
+16 (int (*)(...))QDeferredDeleteEvent::~QDeferredDeleteEvent
+24 (int (*)(...))QDeferredDeleteEvent::~QDeferredDeleteEvent
+
+Class QDeferredDeleteEvent
+ size=24 align=8
+ base size=24 base align=8
+QDeferredDeleteEvent (0x0x7f3bf9926888) 0
+ vptr=((& QDeferredDeleteEvent::_ZTV20QDeferredDeleteEvent) + 16)
+ QEvent (0x0x7f3bf9566780) 0
+ primary-for QDeferredDeleteEvent (0x0x7f3bf9926888)
+
+Class QCoreApplication::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QCoreApplication::QPrivateSignal (0x0x7f3bf95668a0) 0 empty
+
+Vtable for QCoreApplication
+QCoreApplication::_ZTV16QCoreApplication: 16 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI16QCoreApplication)
+16 (int (*)(...))QCoreApplication::metaObject
+24 (int (*)(...))QCoreApplication::qt_metacast
+32 (int (*)(...))QCoreApplication::qt_metacall
+40 (int (*)(...))QCoreApplication::~QCoreApplication
+48 (int (*)(...))QCoreApplication::~QCoreApplication
+56 (int (*)(...))QCoreApplication::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QCoreApplication::notify
+120 (int (*)(...))QCoreApplication::compressEvent
+
+Class QCoreApplication
+ size=16 align=8
+ base size=16 base align=8
+QCoreApplication (0x0x7f3bf99268f0) 0
+ vptr=((& QCoreApplication::_ZTV16QCoreApplication) + 16)
+ QObject (0x0x7f3bf9566840) 0
+ primary-for QCoreApplication (0x0x7f3bf99268f0)
+
+Class QCommandLineParser
+ size=8 align=8
+ base size=8 base align=8
+QCommandLineParser (0x0x7f3bf9566ae0) 0
+
+Class QConcatenateTablesProxyModel::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QConcatenateTablesProxyModel::QPrivateSignal (0x0x7f3bf9566c60) 0 empty
+
+Vtable for QConcatenateTablesProxyModel
+QConcatenateTablesProxyModel::_ZTV28QConcatenateTablesProxyModel: 48 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI28QConcatenateTablesProxyModel)
+16 (int (*)(...))QConcatenateTablesProxyModel::metaObject
+24 (int (*)(...))QConcatenateTablesProxyModel::qt_metacast
+32 (int (*)(...))QConcatenateTablesProxyModel::qt_metacall
+40 (int (*)(...))QConcatenateTablesProxyModel::~QConcatenateTablesProxyModel
+48 (int (*)(...))QConcatenateTablesProxyModel::~QConcatenateTablesProxyModel
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QConcatenateTablesProxyModel::index
+120 (int (*)(...))QConcatenateTablesProxyModel::parent
+128 (int (*)(...))QAbstractItemModel::sibling
+136 (int (*)(...))QConcatenateTablesProxyModel::rowCount
+144 (int (*)(...))QConcatenateTablesProxyModel::columnCount
+152 (int (*)(...))QAbstractItemModel::hasChildren
+160 (int (*)(...))QConcatenateTablesProxyModel::data
+168 (int (*)(...))QConcatenateTablesProxyModel::setData
+176 (int (*)(...))QConcatenateTablesProxyModel::headerData
+184 (int (*)(...))QAbstractItemModel::setHeaderData
+192 (int (*)(...))QConcatenateTablesProxyModel::itemData
+200 (int (*)(...))QConcatenateTablesProxyModel::setItemData
+208 (int (*)(...))QConcatenateTablesProxyModel::mimeTypes
+216 (int (*)(...))QConcatenateTablesProxyModel::mimeData
+224 (int (*)(...))QConcatenateTablesProxyModel::canDropMimeData
+232 (int (*)(...))QConcatenateTablesProxyModel::dropMimeData
+240 (int (*)(...))QAbstractItemModel::supportedDropActions
+248 (int (*)(...))QAbstractItemModel::supportedDragActions
+256 (int (*)(...))QAbstractItemModel::insertRows
+264 (int (*)(...))QAbstractItemModel::insertColumns
+272 (int (*)(...))QAbstractItemModel::removeRows
+280 (int (*)(...))QAbstractItemModel::removeColumns
+288 (int (*)(...))QAbstractItemModel::moveRows
+296 (int (*)(...))QAbstractItemModel::moveColumns
+304 (int (*)(...))QAbstractItemModel::fetchMore
+312 (int (*)(...))QAbstractItemModel::canFetchMore
+320 (int (*)(...))QConcatenateTablesProxyModel::flags
+328 (int (*)(...))QAbstractItemModel::sort
+336 (int (*)(...))QAbstractItemModel::buddy
+344 (int (*)(...))QAbstractItemModel::match
+352 (int (*)(...))QConcatenateTablesProxyModel::span
+360 (int (*)(...))QAbstractItemModel::roleNames
+368 (int (*)(...))QAbstractItemModel::submit
+376 (int (*)(...))QAbstractItemModel::revert
+
+Class QConcatenateTablesProxyModel
+ size=16 align=8
+ base size=16 base align=8
+QConcatenateTablesProxyModel (0x0x7f3bf9926958) 0
+ vptr=((& QConcatenateTablesProxyModel::_ZTV28QConcatenateTablesProxyModel) + 16)
+ QAbstractItemModel (0x0x7f3bf99269c0) 0
+ primary-for QConcatenateTablesProxyModel (0x0x7f3bf9926958)
+ QObject (0x0x7f3bf9566c00) 0
+ primary-for QAbstractItemModel (0x0x7f3bf99269c0)
+
+Class QCryptographicHash
+ size=8 align=8
+ base size=8 base align=8
+QCryptographicHash (0x0x7f3bf9566e40) 0
+
+Class QDataStream
+ size=32 align=8
+ base size=32 base align=8
+QDataStream (0x0x7f3bf9566f60) 0
+
+Class QtPrivate::StreamStateSaver
+ size=16 align=8
+ base size=12 base align=8
+QtPrivate::StreamStateSaver (0x0x7f3bf95ed120) 0
+
+Class QElapsedTimer
+ size=16 align=8
+ base size=16 base align=8
+QElapsedTimer (0x0x7f3bf962a840) 0
+
+Class QDeadlineTimer
+ size=16 align=8
+ base size=16 base align=8
+QDeadlineTimer (0x0x7f3bf962af60) 0
+
+Class QFileDevice::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QFileDevice::QPrivateSignal (0x0x7f3bf937ec60) 0 empty
+
+Vtable for QFileDevice
+QFileDevice::_ZTV11QFileDevice: 34 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI11QFileDevice)
+16 (int (*)(...))QFileDevice::metaObject
+24 (int (*)(...))QFileDevice::qt_metacast
+32 (int (*)(...))QFileDevice::qt_metacall
+40 (int (*)(...))QFileDevice::~QFileDevice
+48 (int (*)(...))QFileDevice::~QFileDevice
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QFileDevice::isSequential
+120 (int (*)(...))QIODevice::open
+128 (int (*)(...))QFileDevice::close
+136 (int (*)(...))QFileDevice::pos
+144 (int (*)(...))QFileDevice::size
+152 (int (*)(...))QFileDevice::seek
+160 (int (*)(...))QFileDevice::atEnd
+168 (int (*)(...))QIODevice::reset
+176 (int (*)(...))QIODevice::bytesAvailable
+184 (int (*)(...))QIODevice::bytesToWrite
+192 (int (*)(...))QIODevice::canReadLine
+200 (int (*)(...))QIODevice::waitForReadyRead
+208 (int (*)(...))QIODevice::waitForBytesWritten
+216 (int (*)(...))QFileDevice::readData
+224 (int (*)(...))QFileDevice::readLineData
+232 (int (*)(...))QFileDevice::writeData
+240 (int (*)(...))QFileDevice::fileName
+248 (int (*)(...))QFileDevice::resize
+256 (int (*)(...))QFileDevice::permissions
+264 (int (*)(...))QFileDevice::setPermissions
+
+Class QFileDevice
+ size=16 align=8
+ base size=16 base align=8
+QFileDevice (0x0x7f3bf9375bc8) 0
+ vptr=((& QFileDevice::_ZTV11QFileDevice) + 16)
+ QIODevice (0x0x7f3bf9375c30) 0
+ primary-for QFileDevice (0x0x7f3bf9375bc8)
+ QObject (0x0x7f3bf937ec00) 0
+ primary-for QIODevice (0x0x7f3bf9375c30)
+
+Class QFile::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QFile::QPrivateSignal (0x0x7f3bf93c55a0) 0 empty
+
+Vtable for QFile
+QFile::_ZTV5QFile: 34 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI5QFile)
+16 (int (*)(...))QFile::metaObject
+24 (int (*)(...))QFile::qt_metacast
+32 (int (*)(...))QFile::qt_metacall
+40 (int (*)(...))QFile::~QFile
+48 (int (*)(...))QFile::~QFile
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QFileDevice::isSequential
+120 (int (*)(...))QFile::open
+128 (int (*)(...))QFileDevice::close
+136 (int (*)(...))QFileDevice::pos
+144 (int (*)(...))QFile::size
+152 (int (*)(...))QFileDevice::seek
+160 (int (*)(...))QFileDevice::atEnd
+168 (int (*)(...))QIODevice::reset
+176 (int (*)(...))QIODevice::bytesAvailable
+184 (int (*)(...))QIODevice::bytesToWrite
+192 (int (*)(...))QIODevice::canReadLine
+200 (int (*)(...))QIODevice::waitForReadyRead
+208 (int (*)(...))QIODevice::waitForBytesWritten
+216 (int (*)(...))QFileDevice::readData
+224 (int (*)(...))QFileDevice::readLineData
+232 (int (*)(...))QFileDevice::writeData
+240 (int (*)(...))QFile::fileName
+248 (int (*)(...))QFile::resize
+256 (int (*)(...))QFile::permissions
+264 (int (*)(...))QFile::setPermissions
+
+Class QFile
+ size=16 align=8
+ base size=16 base align=8
+QFile (0x0x7f3bf9375d68) 0
+ vptr=((& QFile::_ZTV5QFile) + 16)
+ QFileDevice (0x0x7f3bf9375dd0) 0
+ primary-for QFile (0x0x7f3bf9375d68)
+ QIODevice (0x0x7f3bf9375e38) 0
+ primary-for QFileDevice (0x0x7f3bf9375dd0)
+ QObject (0x0x7f3bf93c5540) 0
+ primary-for QIODevice (0x0x7f3bf9375e38)
+
+Class QFileInfo
+ size=8 align=8
+ base size=8 base align=8
+QFileInfo (0x0x7f3bf93c5c00) 0
+
+Class QDir
+ size=8 align=8
+ base size=8 base align=8
+QDir (0x0x7f3bf94bdae0) 0
+
+Class QDirIterator
+ size=8 align=8
+ base size=8 base align=8
+QDirIterator (0x0x7f3bf9156ae0) 0
+
+Class QEasingCurve
+ size=8 align=8
+ base size=8 base align=8
+QEasingCurve (0x0x7f3bf91b02a0) 0
+
+Class QEventTransition::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QEventTransition::QPrivateSignal (0x0x7f3bf92af3c0) 0 empty
+
+Vtable for QEventTransition
+QEventTransition::_ZTV16QEventTransition: 16 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI16QEventTransition)
+16 (int (*)(...))QEventTransition::metaObject
+24 (int (*)(...))QEventTransition::qt_metacast
+32 (int (*)(...))QEventTransition::qt_metacall
+40 (int (*)(...))QEventTransition::~QEventTransition
+48 (int (*)(...))QEventTransition::~QEventTransition
+56 (int (*)(...))QEventTransition::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QEventTransition::eventTest
+120 (int (*)(...))QEventTransition::onTransition
+
+Class QEventTransition
+ size=16 align=8
+ base size=16 base align=8
+QEventTransition (0x0x7f3bf9269af8) 0
+ vptr=((& QEventTransition::_ZTV16QEventTransition) + 16)
+ QAbstractTransition (0x0x7f3bf9269b60) 0
+ primary-for QEventTransition (0x0x7f3bf9269af8)
+ QObject (0x0x7f3bf92af360) 0
+ primary-for QAbstractTransition (0x0x7f3bf9269b60)
+
+Vtable for QException
+QException::_ZTV10QException: 7 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI10QException)
+16 (int (*)(...))QException::~QException
+24 (int (*)(...))QException::~QException
+32 (int (*)(...))std::exception::what
+40 (int (*)(...))QException::raise
+48 (int (*)(...))QException::clone
+
+Class QException
+ size=8 align=8
+ base size=8 base align=8
+QException (0x0x7f3bf9269bc8) 0 nearly-empty
+ vptr=((& QException::_ZTV10QException) + 16)
+ std::exception (0x0x7f3bf92af5a0) 0 nearly-empty
+ primary-for QException (0x0x7f3bf9269bc8)
+
+Vtable for QUnhandledException
+QUnhandledException::_ZTV19QUnhandledException: 7 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI19QUnhandledException)
+16 (int (*)(...))QUnhandledException::~QUnhandledException
+24 (int (*)(...))QUnhandledException::~QUnhandledException
+32 (int (*)(...))std::exception::what
+40 (int (*)(...))QUnhandledException::raise
+48 (int (*)(...))QUnhandledException::clone
+
+Class QUnhandledException
+ size=8 align=8
+ base size=8 base align=8
+QUnhandledException (0x0x7f3bf9269c30) 0 nearly-empty
+ vptr=((& QUnhandledException::_ZTV19QUnhandledException) + 16)
+ QException (0x0x7f3bf9269c98) 0 nearly-empty
+ primary-for QUnhandledException (0x0x7f3bf9269c30)
+ std::exception (0x0x7f3bf92af600) 0 nearly-empty
+ primary-for QException (0x0x7f3bf9269c98)
+
+Class QtPrivate::ExceptionHolder
+ size=8 align=8
+ base size=8 base align=8
+QtPrivate::ExceptionHolder (0x0x7f3bf92af660) 0
+
+Class QtPrivate::ExceptionStore
+ size=8 align=8
+ base size=8 base align=8
+QtPrivate::ExceptionStore (0x0x7f3bf92af720) 0
+
+Vtable for QFactoryInterface
+QFactoryInterface::_ZTV17QFactoryInterface: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI17QFactoryInterface)
+16 0
+24 0
+32 (int (*)(...))__cxa_pure_virtual
+
+Class QFactoryInterface
+ size=8 align=8
+ base size=8 base align=8
+QFactoryInterface (0x0x7f3bf92af780) 0 nearly-empty
+ vptr=((& QFactoryInterface::_ZTV17QFactoryInterface) + 16)
+
+Class QFileSelector::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QFileSelector::QPrivateSignal (0x0x7f3bf92af9c0) 0 empty
+
+Vtable for QFileSelector
+QFileSelector::_ZTV13QFileSelector: 14 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI13QFileSelector)
+16 (int (*)(...))QFileSelector::metaObject
+24 (int (*)(...))QFileSelector::qt_metacast
+32 (int (*)(...))QFileSelector::qt_metacall
+40 (int (*)(...))QFileSelector::~QFileSelector
+48 (int (*)(...))QFileSelector::~QFileSelector
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+
+Class QFileSelector
+ size=16 align=8
+ base size=16 base align=8
+QFileSelector (0x0x7f3bf9269d00) 0
+ vptr=((& QFileSelector::_ZTV13QFileSelector) + 16)
+ QObject (0x0x7f3bf92af960) 0
+ primary-for QFileSelector (0x0x7f3bf9269d00)
+
+Class QFileSystemWatcher::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QFileSystemWatcher::QPrivateSignal (0x0x7f3bf92afc00) 0 empty
+
+Vtable for QFileSystemWatcher
+QFileSystemWatcher::_ZTV18QFileSystemWatcher: 14 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI18QFileSystemWatcher)
+16 (int (*)(...))QFileSystemWatcher::metaObject
+24 (int (*)(...))QFileSystemWatcher::qt_metacast
+32 (int (*)(...))QFileSystemWatcher::qt_metacall
+40 (int (*)(...))QFileSystemWatcher::~QFileSystemWatcher
+48 (int (*)(...))QFileSystemWatcher::~QFileSystemWatcher
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+
+Class QFileSystemWatcher
+ size=16 align=8
+ base size=16 base align=8
+QFileSystemWatcher (0x0x7f3bf9269d68) 0
+ vptr=((& QFileSystemWatcher::_ZTV18QFileSystemWatcher) + 16)
+ QObject (0x0x7f3bf92afba0) 0
+ primary-for QFileSystemWatcher (0x0x7f3bf9269d68)
+
+Class QFinalState::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QFinalState::QPrivateSignal (0x0x7f3bf92afe40) 0 empty
+
+Vtable for QFinalState
+QFinalState::_ZTV11QFinalState: 16 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI11QFinalState)
+16 (int (*)(...))QFinalState::metaObject
+24 (int (*)(...))QFinalState::qt_metacast
+32 (int (*)(...))QFinalState::qt_metacall
+40 (int (*)(...))QFinalState::~QFinalState
+48 (int (*)(...))QFinalState::~QFinalState
+56 (int (*)(...))QFinalState::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QFinalState::onEntry
+120 (int (*)(...))QFinalState::onExit
+
+Class QFinalState
+ size=16 align=8
+ base size=16 base align=8
+QFinalState (0x0x7f3bf9269dd0) 0
+ vptr=((& QFinalState::_ZTV11QFinalState) + 16)
+ QAbstractState (0x0x7f3bf9269e38) 0
+ primary-for QFinalState (0x0x7f3bf9269dd0)
+ QObject (0x0x7f3bf92afde0) 0
+ primary-for QAbstractState (0x0x7f3bf9269e38)
+
+Vtable for QRunnable
+QRunnable::_ZTV9QRunnable: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI9QRunnable)
+16 (int (*)(...))__cxa_pure_virtual
+24 0
+32 0
+
+Class QRunnable
+ size=16 align=8
+ base size=12 base align=8
+QRunnable (0x0x7f3bf8ecd060) 0
+ vptr=((& QRunnable::_ZTV9QRunnable) + 16)
+
+Class QBasicMutex
+ size=8 align=8
+ base size=8 base align=8
+QBasicMutex (0x0x7f3bf8ecd300) 0
+
+Class QMutex
+ size=8 align=8
+ base size=8 base align=8
+QMutex (0x0x7f3bf9269f08) 0
+ QBasicMutex (0x0x7f3bf8ecdf60) 0
+
+Class QRecursiveMutex
+ size=8 align=8
+ base size=8 base align=8
+QRecursiveMutex (0x0x7f3bf9269f70) 0
+ QMutex (0x0x7f3bf8f5c000) 0
+ QBasicMutex (0x0x7f3bf8f571e0) 0
+
+Class QMutexLocker
+ size=8 align=8
+ base size=8 base align=8
+QMutexLocker (0x0x7f3bf8f57240) 0
+
+Class QtPrivate::ResultItem
+ size=16 align=8
+ base size=16 base align=8
+QtPrivate::ResultItem (0x0x7f3bf8f57840) 0
+
+Class QtPrivate::ResultIteratorBase
+ size=16 align=8
+ base size=12 base align=8
+QtPrivate::ResultIteratorBase (0x0x7f3bf8f57e40) 0
+
+Vtable for QtPrivate::ResultStoreBase
+QtPrivate::ResultStoreBase::_ZTVN9QtPrivate15ResultStoreBaseE: 4 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTIN9QtPrivate15ResultStoreBaseE)
+16 (int (*)(...))QtPrivate::ResultStoreBase::~ResultStoreBase
+24 (int (*)(...))QtPrivate::ResultStoreBase::~ResultStoreBase
+
+Class QtPrivate::ResultStoreBase
+ size=48 align=8
+ base size=44 base align=8
+QtPrivate::ResultStoreBase (0x0x7f3bf8fa7060) 0
+ vptr=((& QtPrivate::ResultStoreBase::_ZTVN9QtPrivate15ResultStoreBaseE) + 16)
+
+Class std::__mutex_base
+ size=40 align=8
+ base size=40 base align=8
+std::__mutex_base (0x0x7f3bf8ff3840) 0
+
+Class std::mutex
+ size=40 align=8
+ base size=40 base align=8
+std::mutex (0x0x7f3bf8ff18f0) 0
+ std::__mutex_base (0x0x7f3bf8ff38a0) 0
+
+Class std::defer_lock_t
+ size=1 align=1
+ base size=0 base align=1
+std::defer_lock_t (0x0x7f3bf8ff3a80) 0 empty
+
+Class std::try_to_lock_t
+ size=1 align=1
+ base size=0 base align=1
+std::try_to_lock_t (0x0x7f3bf8ff3ae0) 0 empty
+
+Class std::adopt_lock_t
+ size=1 align=1
+ base size=0 base align=1
+std::adopt_lock_t (0x0x7f3bf8ff3b40) 0 empty
+
+Class std::__recursive_mutex_base
+ size=40 align=8
+ base size=40 base align=8
+std::__recursive_mutex_base (0x0x7f3bf90265a0) 0
+
+Class std::recursive_mutex
+ size=40 align=8
+ base size=40 base align=8
+std::recursive_mutex (0x0x7f3bf8ff1958) 0
+ std::__recursive_mutex_base (0x0x7f3bf9026600) 0
+
+Class std::timed_mutex
+ size=40 align=8
+ base size=40 base align=8
+std::timed_mutex (0x0x7f3bf8ffdd20) 0
+ std::__mutex_base (0x0x7f3bf90269c0) 0
+ std::__timed_mutex_impl<std::timed_mutex> (0x0x7f3bf9026a20) 0 empty
+
+Class std::recursive_timed_mutex
+ size=40 align=8
+ base size=40 base align=8
+std::recursive_timed_mutex (0x0x7f3bf9051070) 0
+ std::__recursive_mutex_base (0x0x7f3bf9026d80) 0
+ std::__timed_mutex_impl<std::recursive_timed_mutex> (0x0x7f3bf9026de0) 0 empty
+
+Class std::once_flag
+ size=4 align=4
+ base size=4 base align=4
+std::once_flag (0x0x7f3bf9067540) 0
+
+Vtable for QFutureInterfaceBase
+QFutureInterfaceBase::_ZTV20QFutureInterfaceBase: 4 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI20QFutureInterfaceBase)
+16 (int (*)(...))QFutureInterfaceBase::~QFutureInterfaceBase
+24 (int (*)(...))QFutureInterfaceBase::~QFutureInterfaceBase
+
+Class QFutureInterfaceBase
+ size=16 align=8
+ base size=16 base align=8
+QFutureInterfaceBase (0x0x7f3bf9067780) 0
+ vptr=((& QFutureInterfaceBase::_ZTV20QFutureInterfaceBase) + 16)
+
+Class QFutureWatcherBase::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QFutureWatcherBase::QPrivateSignal (0x0x7f3bf8d15ae0) 0 empty
+
+Vtable for QFutureWatcherBase
+QFutureWatcherBase::_ZTV18QFutureWatcherBase: 16 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI18QFutureWatcherBase)
+16 (int (*)(...))QFutureWatcherBase::metaObject
+24 (int (*)(...))QFutureWatcherBase::qt_metacast
+32 (int (*)(...))QFutureWatcherBase::qt_metacall
+40 0
+48 0
+56 (int (*)(...))QFutureWatcherBase::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QFutureWatcherBase::connectNotify
+104 (int (*)(...))QFutureWatcherBase::disconnectNotify
+112 (int (*)(...))__cxa_pure_virtual
+120 (int (*)(...))__cxa_pure_virtual
+
+Class QFutureWatcherBase
+ size=16 align=8
+ base size=16 base align=8
+QFutureWatcherBase (0x0x7f3bf8cb3750) 0
+ vptr=((& QFutureWatcherBase::_ZTV18QFutureWatcherBase) + 16)
+ QObject (0x0x7f3bf8d15a80) 0
+ primary-for QFutureWatcherBase (0x0x7f3bf8cb3750)
+
+Class QHistoryState::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QHistoryState::QPrivateSignal (0x0x7f3bf8d40e40) 0 empty
+
+Vtable for QHistoryState
+QHistoryState::_ZTV13QHistoryState: 16 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI13QHistoryState)
+16 (int (*)(...))QHistoryState::metaObject
+24 (int (*)(...))QHistoryState::qt_metacast
+32 (int (*)(...))QHistoryState::qt_metacall
+40 (int (*)(...))QHistoryState::~QHistoryState
+48 (int (*)(...))QHistoryState::~QHistoryState
+56 (int (*)(...))QHistoryState::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QHistoryState::onEntry
+120 (int (*)(...))QHistoryState::onExit
+
+Class QHistoryState
+ size=16 align=8
+ base size=16 base align=8
+QHistoryState (0x0x7f3bf8cb3f70) 0
+ vptr=((& QHistoryState::_ZTV13QHistoryState) + 16)
+ QAbstractState (0x0x7f3bf8d60000) 0
+ primary-for QHistoryState (0x0x7f3bf8cb3f70)
+ QObject (0x0x7f3bf8d40de0) 0
+ primary-for QAbstractState (0x0x7f3bf8d60000)
+
+Class QIdentityProxyModel::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QIdentityProxyModel::QPrivateSignal (0x0x7f3bf8d6e180) 0 empty
+
+Vtable for QIdentityProxyModel
+QIdentityProxyModel::_ZTV19QIdentityProxyModel: 53 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI19QIdentityProxyModel)
+16 (int (*)(...))QIdentityProxyModel::metaObject
+24 (int (*)(...))QIdentityProxyModel::qt_metacast
+32 (int (*)(...))QIdentityProxyModel::qt_metacall
+40 (int (*)(...))QIdentityProxyModel::~QIdentityProxyModel
+48 (int (*)(...))QIdentityProxyModel::~QIdentityProxyModel
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QIdentityProxyModel::index
+120 (int (*)(...))QIdentityProxyModel::parent
+128 (int (*)(...))QIdentityProxyModel::sibling
+136 (int (*)(...))QIdentityProxyModel::rowCount
+144 (int (*)(...))QIdentityProxyModel::columnCount
+152 (int (*)(...))QAbstractProxyModel::hasChildren
+160 (int (*)(...))QAbstractProxyModel::data
+168 (int (*)(...))QAbstractProxyModel::setData
+176 (int (*)(...))QIdentityProxyModel::headerData
+184 (int (*)(...))QAbstractProxyModel::setHeaderData
+192 (int (*)(...))QAbstractProxyModel::itemData
+200 (int (*)(...))QAbstractProxyModel::setItemData
+208 (int (*)(...))QAbstractProxyModel::mimeTypes
+216 (int (*)(...))QAbstractProxyModel::mimeData
+224 (int (*)(...))QAbstractProxyModel::canDropMimeData
+232 (int (*)(...))QIdentityProxyModel::dropMimeData
+240 (int (*)(...))QAbstractProxyModel::supportedDropActions
+248 (int (*)(...))QAbstractProxyModel::supportedDragActions
+256 (int (*)(...))QIdentityProxyModel::insertRows
+264 (int (*)(...))QIdentityProxyModel::insertColumns
+272 (int (*)(...))QIdentityProxyModel::removeRows
+280 (int (*)(...))QIdentityProxyModel::removeColumns
+288 (int (*)(...))QAbstractItemModel::moveRows
+296 (int (*)(...))QAbstractItemModel::moveColumns
+304 (int (*)(...))QAbstractProxyModel::fetchMore
+312 (int (*)(...))QAbstractProxyModel::canFetchMore
+320 (int (*)(...))QAbstractProxyModel::flags
+328 (int (*)(...))QAbstractProxyModel::sort
+336 (int (*)(...))QAbstractProxyModel::buddy
+344 (int (*)(...))QIdentityProxyModel::match
+352 (int (*)(...))QAbstractProxyModel::span
+360 (int (*)(...))QAbstractItemModel::roleNames
+368 (int (*)(...))QAbstractProxyModel::submit
+376 (int (*)(...))QAbstractProxyModel::revert
+384 (int (*)(...))QIdentityProxyModel::setSourceModel
+392 (int (*)(...))QIdentityProxyModel::mapToSource
+400 (int (*)(...))QIdentityProxyModel::mapFromSource
+408 (int (*)(...))QIdentityProxyModel::mapSelectionToSource
+416 (int (*)(...))QIdentityProxyModel::mapSelectionFromSource
+
+Class QIdentityProxyModel
+ size=16 align=8
+ base size=16 base align=8
+QIdentityProxyModel (0x0x7f3bf8d60068) 0
+ vptr=((& QIdentityProxyModel::_ZTV19QIdentityProxyModel) + 16)
+ QAbstractProxyModel (0x0x7f3bf8d600d0) 0
+ primary-for QIdentityProxyModel (0x0x7f3bf8d60068)
+ QAbstractItemModel (0x0x7f3bf8d60138) 0
+ primary-for QAbstractProxyModel (0x0x7f3bf8d600d0)
+ QObject (0x0x7f3bf8d6e120) 0
+ primary-for QAbstractItemModel (0x0x7f3bf8d60138)
+
+Class QItemSelectionRange
+ size=16 align=8
+ base size=16 base align=8
+QItemSelectionRange (0x0x7f3bf8d6e360) 0
+
+Class QItemSelectionModel::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QItemSelectionModel::QPrivateSignal (0x0x7f3bf8e29c60) 0 empty
+
+Vtable for QItemSelectionModel
+QItemSelectionModel::_ZTV19QItemSelectionModel: 20 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI19QItemSelectionModel)
+16 (int (*)(...))QItemSelectionModel::metaObject
+24 (int (*)(...))QItemSelectionModel::qt_metacast
+32 (int (*)(...))QItemSelectionModel::qt_metacall
+40 (int (*)(...))QItemSelectionModel::~QItemSelectionModel
+48 (int (*)(...))QItemSelectionModel::~QItemSelectionModel
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QItemSelectionModel::setCurrentIndex
+120 (int (*)(...))QItemSelectionModel::select
+128 (int (*)(...))QItemSelectionModel::select
+136 (int (*)(...))QItemSelectionModel::clear
+144 (int (*)(...))QItemSelectionModel::reset
+152 (int (*)(...))QItemSelectionModel::clearCurrentIndex
+
+Class QItemSelectionModel
+ size=16 align=8
+ base size=16 base align=8
+QItemSelectionModel (0x0x7f3bf8e33a90) 0
+ vptr=((& QItemSelectionModel::_ZTV19QItemSelectionModel) + 16)
+ QObject (0x0x7f3bf8e29c00) 0
+ primary-for QItemSelectionModel (0x0x7f3bf8e33a90)
+
+Class QItemSelection
+ size=8 align=8
+ base size=8 base align=8
+QItemSelection (0x0x7f3bf8e33c30) 0
+ QList<QItemSelectionRange> (0x0x7f3bf8e33c98) 0
+ QListSpecialMethods<QItemSelectionRange> (0x0x7f3bf8e6b780) 0 empty
+
+Class QJsonValue
+ size=24 align=8
+ base size=20 base align=8
+QJsonValue (0x0x7f3bf8aff0c0) 0
+
+Class QJsonValueRef
+ size=16 align=8
+ base size=12 base align=8
+QJsonValueRef (0x0x7f3bf8c2bd20) 0
+
+Class QJsonValuePtr
+ size=24 align=8
+ base size=24 base align=8
+QJsonValuePtr (0x0x7f3bf8c68cc0) 0
+
+Class QJsonValueRefPtr
+ size=16 align=8
+ base size=16 base align=8
+QJsonValueRefPtr (0x0x7f3bf8c68f60) 0
+
+Class QJsonArray::iterator
+ size=16 align=8
+ base size=12 base align=8
+QJsonArray::iterator (0x0x7f3bf88e4300) 0
+
+Class QJsonArray::const_iterator
+ size=16 align=8
+ base size=12 base align=8
+QJsonArray::const_iterator (0x0x7f3bf88e4360) 0
+
+Class QJsonArray
+ size=16 align=8
+ base size=16 base align=8
+QJsonArray (0x0x7f3bf88e42a0) 0
+
+Class QJsonParseError
+ size=8 align=4
+ base size=8 base align=4
+QJsonParseError (0x0x7f3bf8a14240) 0
+
+Class QJsonDocument
+ size=8 align=8
+ base size=8 base align=8
+QJsonDocument (0x0x7f3bf8a142a0) 0
+
+Class QJsonObject::iterator
+ size=16 align=8
+ base size=12 base align=8
+QJsonObject::iterator (0x0x7f3bf8a65a80) 0
+
+Class QJsonObject::const_iterator
+ size=16 align=8
+ base size=12 base align=8
+QJsonObject::const_iterator (0x0x7f3bf8a65ae0) 0
+
+Class QJsonObject
+ size=16 align=8
+ base size=16 base align=8
+QJsonObject (0x0x7f3bf8a65a20) 0
+
+Class QLibrary::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QLibrary::QPrivateSignal (0x0x7f3bf8781f00) 0 empty
+
+Vtable for QLibrary
+QLibrary::_ZTV8QLibrary: 14 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI8QLibrary)
+16 (int (*)(...))QLibrary::metaObject
+24 (int (*)(...))QLibrary::qt_metacast
+32 (int (*)(...))QLibrary::qt_metacall
+40 (int (*)(...))QLibrary::~QLibrary
+48 (int (*)(...))QLibrary::~QLibrary
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+
+Class QLibrary
+ size=32 align=8
+ base size=25 base align=8
+QLibrary (0x0x7f3bf878e8f0) 0
+ vptr=((& QLibrary::_ZTV8QLibrary) + 16)
+ QObject (0x0x7f3bf8781ea0) 0
+ primary-for QLibrary (0x0x7f3bf878e8f0)
+
+Class QVersionNumber::SegmentStorage
+ size=8 align=8
+ base size=8 base align=8
+QVersionNumber::SegmentStorage (0x0x7f3bf87b1d80) 0
+
+Class QVersionNumber
+ size=8 align=8
+ base size=8 base align=8
+QVersionNumber (0x0x7f3bf87b18a0) 0
+
+Class QLibraryInfo
+ size=1 align=1
+ base size=0 base align=1
+QLibraryInfo (0x0x7f3bf8481540) 0 empty
+
+Class QPoint
+ size=8 align=4
+ base size=8 base align=4
+QPoint (0x0x7f3bf84815a0) 0
+
+Class QPointF
+ size=16 align=8
+ base size=16 base align=8
+QPointF (0x0x7f3bf84f9420) 0
+
+Class QLine
+ size=16 align=4
+ base size=16 base align=4
+QLine (0x0x7f3bf856a600) 0
+
+Class QLineF
+ size=32 align=8
+ base size=32 base align=8
+QLineF (0x0x7f3bf85d79c0) 0
+
+Class QLinkedListData
+ size=32 align=8
+ base size=25 base align=8
+QLinkedListData (0x0x7f3bf8654c60) 0
+
+Class QLockFile
+ size=8 align=8
+ base size=8 base align=8
+QLockFile (0x0x7f3bf831a1e0) 0
+
+Class QLoggingCategory::AtomicBools
+ size=4 align=1
+ base size=4 base align=1
+QLoggingCategory::AtomicBools (0x0x7f3bf831a420) 0
+
+Class QLoggingCategory
+ size=24 align=8
+ base size=24 base align=8
+QLoggingCategory (0x0x7f3bf831a3c0) 0
+
+Class QMargins
+ size=16 align=4
+ base size=16 base align=4
+QMargins (0x0x7f3bf831a840) 0
+
+Class QMarginsF
+ size=32 align=8
+ base size=32 base align=8
+QMarginsF (0x0x7f3bf83d8780) 0
+
+Class QMessageAuthenticationCode
+ size=8 align=8
+ base size=8 base align=8
+QMessageAuthenticationCode (0x0x7f3bf8221f60) 0
+
+Class QMetaMethod
+ size=16 align=8
+ base size=12 base align=8
+QMetaMethod (0x0x7f3bf8248000) 0
+
+Class QMetaEnum
+ size=16 align=8
+ base size=12 base align=8
+QMetaEnum (0x0x7f3bf7e2a840) 0
+
+Class QMetaProperty
+ size=32 align=8
+ base size=32 base align=8
+QMetaProperty (0x0x7f3bf7e6ea20) 0
+
+Class QMetaClassInfo
+ size=16 align=8
+ base size=12 base align=8
+QMetaClassInfo (0x0x7f3bf7e6eb40) 0
+
+Class QMimeData::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QMimeData::QPrivateSignal (0x0x7f3bf7ec9120) 0 empty
+
+Vtable for QMimeData
+QMimeData::_ZTV9QMimeData: 17 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI9QMimeData)
+16 (int (*)(...))QMimeData::metaObject
+24 (int (*)(...))QMimeData::qt_metacast
+32 (int (*)(...))QMimeData::qt_metacall
+40 (int (*)(...))QMimeData::~QMimeData
+48 (int (*)(...))QMimeData::~QMimeData
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QMimeData::hasFormat
+120 (int (*)(...))QMimeData::formats
+128 (int (*)(...))QMimeData::retrieveData
+
+Class QMimeData
+ size=16 align=8
+ base size=16 base align=8
+QMimeData (0x0x7f3bf7ec1548) 0
+ vptr=((& QMimeData::_ZTV9QMimeData) + 16)
+ QObject (0x0x7f3bf7ec90c0) 0
+ primary-for QMimeData (0x0x7f3bf7ec1548)
+
+Class QMimeType
+ size=8 align=8
+ base size=8 base align=8
+QMimeType (0x0x7f3bf7ec9300) 0
+
+Class QMimeDatabase
+ size=8 align=8
+ base size=8 base align=8
+QMimeDatabase (0x0x7f3bf7f97240) 0
+
+Class QObjectCleanupHandler::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QObjectCleanupHandler::QPrivateSignal (0x0x7f3bf7f97300) 0 empty
+
+Vtable for QObjectCleanupHandler
+QObjectCleanupHandler::_ZTV21QObjectCleanupHandler: 14 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI21QObjectCleanupHandler)
+16 (int (*)(...))QObjectCleanupHandler::metaObject
+24 (int (*)(...))QObjectCleanupHandler::qt_metacast
+32 (int (*)(...))QObjectCleanupHandler::qt_metacall
+40 (int (*)(...))QObjectCleanupHandler::~QObjectCleanupHandler
+48 (int (*)(...))QObjectCleanupHandler::~QObjectCleanupHandler
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+
+Class QObjectCleanupHandler
+ size=24 align=8
+ base size=24 base align=8
+QObjectCleanupHandler (0x0x7f3bf7f990d0) 0
+ vptr=((& QObjectCleanupHandler::_ZTV21QObjectCleanupHandler) + 16)
+ QObject (0x0x7f3bf7f972a0) 0
+ primary-for QObjectCleanupHandler (0x0x7f3bf7f990d0)
+
+Class QOperatingSystemVersion
+ size=16 align=4
+ base size=16 base align=4
+QOperatingSystemVersion (0x0x7f3bf7f97420) 0
+
+Class QParallelAnimationGroup::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QParallelAnimationGroup::QPrivateSignal (0x0x7f3bf7c08ba0) 0 empty
+
+Vtable for QParallelAnimationGroup
+QParallelAnimationGroup::_ZTV23QParallelAnimationGroup: 18 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI23QParallelAnimationGroup)
+16 (int (*)(...))QParallelAnimationGroup::metaObject
+24 (int (*)(...))QParallelAnimationGroup::qt_metacast
+32 (int (*)(...))QParallelAnimationGroup::qt_metacall
+40 (int (*)(...))QParallelAnimationGroup::~QParallelAnimationGroup
+48 (int (*)(...))QParallelAnimationGroup::~QParallelAnimationGroup
+56 (int (*)(...))QParallelAnimationGroup::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QParallelAnimationGroup::duration
+120 (int (*)(...))QParallelAnimationGroup::updateCurrentTime
+128 (int (*)(...))QParallelAnimationGroup::updateState
+136 (int (*)(...))QParallelAnimationGroup::updateDirection
+
+Class QParallelAnimationGroup
+ size=16 align=8
+ base size=16 base align=8
+QParallelAnimationGroup (0x0x7f3bf7c12958) 0
+ vptr=((& QParallelAnimationGroup::_ZTV23QParallelAnimationGroup) + 16)
+ QAnimationGroup (0x0x7f3bf7c129c0) 0
+ primary-for QParallelAnimationGroup (0x0x7f3bf7c12958)
+ QAbstractAnimation (0x0x7f3bf7c12a28) 0
+ primary-for QAnimationGroup (0x0x7f3bf7c129c0)
+ QObject (0x0x7f3bf7c08b40) 0
+ primary-for QAbstractAnimation (0x0x7f3bf7c12a28)
+
+Class QPauseAnimation::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QPauseAnimation::QPrivateSignal (0x0x7f3bf7c08de0) 0 empty
+
+Vtable for QPauseAnimation
+QPauseAnimation::_ZTV15QPauseAnimation: 18 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI15QPauseAnimation)
+16 (int (*)(...))QPauseAnimation::metaObject
+24 (int (*)(...))QPauseAnimation::qt_metacast
+32 (int (*)(...))QPauseAnimation::qt_metacall
+40 (int (*)(...))QPauseAnimation::~QPauseAnimation
+48 (int (*)(...))QPauseAnimation::~QPauseAnimation
+56 (int (*)(...))QPauseAnimation::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QPauseAnimation::duration
+120 (int (*)(...))QPauseAnimation::updateCurrentTime
+128 (int (*)(...))QAbstractAnimation::updateState
+136 (int (*)(...))QAbstractAnimation::updateDirection
+
+Class QPauseAnimation
+ size=16 align=8
+ base size=16 base align=8
+QPauseAnimation (0x0x7f3bf7c12a90) 0
+ vptr=((& QPauseAnimation::_ZTV15QPauseAnimation) + 16)
+ QAbstractAnimation (0x0x7f3bf7c12af8) 0
+ primary-for QPauseAnimation (0x0x7f3bf7c12a90)
+ QObject (0x0x7f3bf7c08d80) 0
+ primary-for QAbstractAnimation (0x0x7f3bf7c12af8)
+
+Class QStaticPlugin
+ size=16 align=8
+ base size=16 base align=8
+QStaticPlugin (0x0x7f3bf7c39960) 0
+
+Class QPluginLoader::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QPluginLoader::QPrivateSignal (0x0x7f3bf7c84ae0) 0 empty
+
+Vtable for QPluginLoader
+QPluginLoader::_ZTV13QPluginLoader: 14 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI13QPluginLoader)
+16 (int (*)(...))QPluginLoader::metaObject
+24 (int (*)(...))QPluginLoader::qt_metacast
+32 (int (*)(...))QPluginLoader::qt_metacall
+40 (int (*)(...))QPluginLoader::~QPluginLoader
+48 (int (*)(...))QPluginLoader::~QPluginLoader
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+
+Class QPluginLoader
+ size=32 align=8
+ base size=25 base align=8
+QPluginLoader (0x0x7f3bf7c79e38) 0
+ vptr=((& QPluginLoader::_ZTV13QPluginLoader) + 16)
+ QObject (0x0x7f3bf7c84a80) 0
+ primary-for QPluginLoader (0x0x7f3bf7c79e38)
+
+Class QProcessEnvironment
+ size=8 align=8
+ base size=8 base align=8
+QProcessEnvironment (0x0x7f3bf7c84c00) 0
+
+Class QProcess::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QProcess::QPrivateSignal (0x0x7f3bf7d670c0) 0 empty
+
+Vtable for QProcess
+QProcess::_ZTV8QProcess: 31 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI8QProcess)
+16 (int (*)(...))QProcess::metaObject
+24 (int (*)(...))QProcess::qt_metacast
+32 (int (*)(...))QProcess::qt_metacall
+40 (int (*)(...))QProcess::~QProcess
+48 (int (*)(...))QProcess::~QProcess
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QProcess::isSequential
+120 (int (*)(...))QProcess::open
+128 (int (*)(...))QProcess::close
+136 (int (*)(...))QIODevice::pos
+144 (int (*)(...))QIODevice::size
+152 (int (*)(...))QIODevice::seek
+160 (int (*)(...))QProcess::atEnd
+168 (int (*)(...))QIODevice::reset
+176 (int (*)(...))QProcess::bytesAvailable
+184 (int (*)(...))QProcess::bytesToWrite
+192 (int (*)(...))QProcess::canReadLine
+200 (int (*)(...))QProcess::waitForReadyRead
+208 (int (*)(...))QProcess::waitForBytesWritten
+216 (int (*)(...))QProcess::readData
+224 (int (*)(...))QIODevice::readLineData
+232 (int (*)(...))QProcess::writeData
+240 (int (*)(...))QProcess::setupChildProcess
+
+Class QProcess
+ size=16 align=8
+ base size=16 base align=8
+QProcess (0x0x7f3bf7d632d8) 0
+ vptr=((& QProcess::_ZTV8QProcess) + 16)
+ QIODevice (0x0x7f3bf7d63340) 0
+ primary-for QProcess (0x0x7f3bf7d632d8)
+ QObject (0x0x7f3bf7d67060) 0
+ primary-for QIODevice (0x0x7f3bf7d63340)
+
+Class QVariantAnimation::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QVariantAnimation::QPrivateSignal (0x0x7f3bf7d67780) 0 empty
+
+Vtable for QVariantAnimation
+QVariantAnimation::_ZTV17QVariantAnimation: 20 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI17QVariantAnimation)
+16 (int (*)(...))QVariantAnimation::metaObject
+24 (int (*)(...))QVariantAnimation::qt_metacast
+32 (int (*)(...))QVariantAnimation::qt_metacall
+40 (int (*)(...))QVariantAnimation::~QVariantAnimation
+48 (int (*)(...))QVariantAnimation::~QVariantAnimation
+56 (int (*)(...))QVariantAnimation::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QVariantAnimation::duration
+120 (int (*)(...))QVariantAnimation::updateCurrentTime
+128 (int (*)(...))QVariantAnimation::updateState
+136 (int (*)(...))QAbstractAnimation::updateDirection
+144 (int (*)(...))QVariantAnimation::updateCurrentValue
+152 (int (*)(...))QVariantAnimation::interpolated
+
+Class QVariantAnimation
+ size=16 align=8
+ base size=16 base align=8
+QVariantAnimation (0x0x7f3bf7d633a8) 0
+ vptr=((& QVariantAnimation::_ZTV17QVariantAnimation) + 16)
+ QAbstractAnimation (0x0x7f3bf7d63410) 0
+ primary-for QVariantAnimation (0x0x7f3bf7d633a8)
+ QObject (0x0x7f3bf7d67720) 0
+ primary-for QAbstractAnimation (0x0x7f3bf7d63410)
+
+Class QPropertyAnimation::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QPropertyAnimation::QPrivateSignal (0x0x7f3bf7d67a20) 0 empty
+
+Vtable for QPropertyAnimation
+QPropertyAnimation::_ZTV18QPropertyAnimation: 20 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI18QPropertyAnimation)
+16 (int (*)(...))QPropertyAnimation::metaObject
+24 (int (*)(...))QPropertyAnimation::qt_metacast
+32 (int (*)(...))QPropertyAnimation::qt_metacall
+40 (int (*)(...))QPropertyAnimation::~QPropertyAnimation
+48 (int (*)(...))QPropertyAnimation::~QPropertyAnimation
+56 (int (*)(...))QPropertyAnimation::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QVariantAnimation::duration
+120 (int (*)(...))QVariantAnimation::updateCurrentTime
+128 (int (*)(...))QPropertyAnimation::updateState
+136 (int (*)(...))QAbstractAnimation::updateDirection
+144 (int (*)(...))QPropertyAnimation::updateCurrentValue
+152 (int (*)(...))QVariantAnimation::interpolated
+
+Class QPropertyAnimation
+ size=16 align=8
+ base size=16 base align=8
+QPropertyAnimation (0x0x7f3bf7d634e0) 0
+ vptr=((& QPropertyAnimation::_ZTV18QPropertyAnimation) + 16)
+ QVariantAnimation (0x0x7f3bf7d63548) 0
+ primary-for QPropertyAnimation (0x0x7f3bf7d634e0)
+ QAbstractAnimation (0x0x7f3bf7d635b0) 0
+ primary-for QVariantAnimation (0x0x7f3bf7d63548)
+ QObject (0x0x7f3bf7d679c0) 0
+ primary-for QAbstractAnimation (0x0x7f3bf7d635b0)
+
+Class std::random_device
+ size=5000 align=8
+ base size=5000 base align=8
+std::random_device (0x0x7f3bf7a39180) 0
+
+Class std::bernoulli_distribution::param_type
+ size=8 align=8
+ base size=8 base align=8
+std::bernoulli_distribution::param_type (0x0x7f3bf7b13ea0) 0
+
+Class std::bernoulli_distribution
+ size=8 align=8
+ base size=8 base align=8
+std::bernoulli_distribution (0x0x7f3bf7b13e40) 0
+
+Class std::seed_seq
+ size=24 align=8
+ base size=24 base align=8
+std::seed_seq (0x0x7f3bf7901c00) 0
+
+Class QRandomGenerator::Storage
+ size=2504 align=8
+ base size=2504 base align=8
+QRandomGenerator::Storage (0x0x7f3bf773f8a0) 0
+
+Class QRandomGenerator
+ size=2512 align=8
+ base size=2512 base align=8
+QRandomGenerator (0x0x7f3bf773f840) 0
+
+Class QRandomGenerator64
+ size=2512 align=8
+ base size=2512 base align=8
+QRandomGenerator64 (0x0x7f3bf77d6270) 0
+ QRandomGenerator (0x0x7f3bf77e93c0) 0
+
+Class QReadWriteLock
+ size=8 align=8
+ base size=8 base align=8
+QReadWriteLock (0x0x7f3bf77e9f60) 0
+
+Class QReadLocker
+ size=8 align=8
+ base size=8 base align=8
+QReadLocker (0x0x7f3bf7408240) 0
+
+Class QWriteLocker
+ size=8 align=8
+ base size=8 base align=8
+QWriteLocker (0x0x7f3bf7408720) 0
+
+Class QSize
+ size=8 align=4
+ base size=8 base align=4
+QSize (0x0x7f3bf7408c00) 0
+
+Class QSizeF
+ size=16 align=8
+ base size=16 base align=8
+QSizeF (0x0x7f3bf74ddae0) 0
+
+Class QRect
+ size=16 align=4
+ base size=16 base align=4
+QRect (0x0x7f3bf7558b40) 0
+
+Class QRectF
+ size=32 align=8
+ base size=32 base align=8
+QRectF (0x0x7f3bf7208ba0) 0
+
+Class QResource
+ size=8 align=8
+ base size=8 base align=8
+QResource (0x0x7f3bf72c9cc0) 0
+
+Class QSaveFile::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QSaveFile::QPrivateSignal (0x0x7f3bf72c9f60) 0 empty
+
+Vtable for QSaveFile
+QSaveFile::_ZTV9QSaveFile: 34 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI9QSaveFile)
+16 (int (*)(...))QSaveFile::metaObject
+24 (int (*)(...))QSaveFile::qt_metacast
+32 (int (*)(...))QSaveFile::qt_metacall
+40 (int (*)(...))QSaveFile::~QSaveFile
+48 (int (*)(...))QSaveFile::~QSaveFile
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QFileDevice::isSequential
+120 (int (*)(...))QSaveFile::open
+128 (int (*)(...))QSaveFile::close
+136 (int (*)(...))QFileDevice::pos
+144 (int (*)(...))QFileDevice::size
+152 (int (*)(...))QFileDevice::seek
+160 (int (*)(...))QFileDevice::atEnd
+168 (int (*)(...))QIODevice::reset
+176 (int (*)(...))QIODevice::bytesAvailable
+184 (int (*)(...))QIODevice::bytesToWrite
+192 (int (*)(...))QIODevice::canReadLine
+200 (int (*)(...))QIODevice::waitForReadyRead
+208 (int (*)(...))QIODevice::waitForBytesWritten
+216 (int (*)(...))QFileDevice::readData
+224 (int (*)(...))QFileDevice::readLineData
+232 (int (*)(...))QSaveFile::writeData
+240 (int (*)(...))QSaveFile::fileName
+248 (int (*)(...))QFileDevice::resize
+256 (int (*)(...))QFileDevice::permissions
+264 (int (*)(...))QFileDevice::setPermissions
+
+Class QSaveFile
+ size=16 align=8
+ base size=16 base align=8
+QSaveFile (0x0x7f3bf7289c30) 0
+ vptr=((& QSaveFile::_ZTV9QSaveFile) + 16)
+ QFileDevice (0x0x7f3bf7289c98) 0
+ primary-for QSaveFile (0x0x7f3bf7289c30)
+ QIODevice (0x0x7f3bf7289d00) 0
+ primary-for QFileDevice (0x0x7f3bf7289c98)
+ QObject (0x0x7f3bf72c9f00) 0
+ primary-for QIODevice (0x0x7f3bf7289d00)
+
+Class QSemaphore
+ size=8 align=8
+ base size=8 base align=8
+QSemaphore (0x0x7f3bf73205a0) 0
+
+Class QSemaphoreReleaser
+ size=16 align=8
+ base size=12 base align=8
+QSemaphoreReleaser (0x0x7f3bf7320720) 0
+
+Class QSequentialAnimationGroup::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QSequentialAnimationGroup::QPrivateSignal (0x0x7f3bf73f3360) 0 empty
+
+Vtable for QSequentialAnimationGroup
+QSequentialAnimationGroup::_ZTV25QSequentialAnimationGroup: 18 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI25QSequentialAnimationGroup)
+16 (int (*)(...))QSequentialAnimationGroup::metaObject
+24 (int (*)(...))QSequentialAnimationGroup::qt_metacast
+32 (int (*)(...))QSequentialAnimationGroup::qt_metacall
+40 (int (*)(...))QSequentialAnimationGroup::~QSequentialAnimationGroup
+48 (int (*)(...))QSequentialAnimationGroup::~QSequentialAnimationGroup
+56 (int (*)(...))QSequentialAnimationGroup::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QSequentialAnimationGroup::duration
+120 (int (*)(...))QSequentialAnimationGroup::updateCurrentTime
+128 (int (*)(...))QSequentialAnimationGroup::updateState
+136 (int (*)(...))QSequentialAnimationGroup::updateDirection
+
+Class QSequentialAnimationGroup
+ size=16 align=8
+ base size=16 base align=8
+QSequentialAnimationGroup (0x0x7f3bf73f54e0) 0
+ vptr=((& QSequentialAnimationGroup::_ZTV25QSequentialAnimationGroup) + 16)
+ QAnimationGroup (0x0x7f3bf73f5548) 0
+ primary-for QSequentialAnimationGroup (0x0x7f3bf73f54e0)
+ QAbstractAnimation (0x0x7f3bf73f55b0) 0
+ primary-for QAnimationGroup (0x0x7f3bf73f5548)
+ QObject (0x0x7f3bf73f3300) 0
+ primary-for QAbstractAnimation (0x0x7f3bf73f55b0)
+
+Class QSettings::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QSettings::QPrivateSignal (0x0x7f3bf73f35a0) 0 empty
+
+Vtable for QSettings
+QSettings::_ZTV9QSettings: 14 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI9QSettings)
+16 (int (*)(...))QSettings::metaObject
+24 (int (*)(...))QSettings::qt_metacast
+32 (int (*)(...))QSettings::qt_metacall
+40 (int (*)(...))QSettings::~QSettings
+48 (int (*)(...))QSettings::~QSettings
+56 (int (*)(...))QSettings::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+
+Class QSettings
+ size=16 align=8
+ base size=16 base align=8
+QSettings (0x0x7f3bf73f5618) 0
+ vptr=((& QSettings::_ZTV9QSettings) + 16)
+ QObject (0x0x7f3bf73f3540) 0
+ primary-for QSettings (0x0x7f3bf73f5618)
+
+Class QSharedMemory::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QSharedMemory::QPrivateSignal (0x0x7f3bf73f3a20) 0 empty
+
+Vtable for QSharedMemory
+QSharedMemory::_ZTV13QSharedMemory: 14 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI13QSharedMemory)
+16 (int (*)(...))QSharedMemory::metaObject
+24 (int (*)(...))QSharedMemory::qt_metacast
+32 (int (*)(...))QSharedMemory::qt_metacall
+40 (int (*)(...))QSharedMemory::~QSharedMemory
+48 (int (*)(...))QSharedMemory::~QSharedMemory
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+
+Class QSharedMemory
+ size=16 align=8
+ base size=16 base align=8
+QSharedMemory (0x0x7f3bf73f5680) 0
+ vptr=((& QSharedMemory::_ZTV13QSharedMemory) + 16)
+ QObject (0x0x7f3bf73f39c0) 0
+ primary-for QSharedMemory (0x0x7f3bf73f5680)
+
+Class QSignalMapper::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QSignalMapper::QPrivateSignal (0x0x7f3bf73f3c60) 0 empty
+
+Vtable for QSignalMapper
+QSignalMapper::_ZTV13QSignalMapper: 14 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI13QSignalMapper)
+16 (int (*)(...))QSignalMapper::metaObject
+24 (int (*)(...))QSignalMapper::qt_metacast
+32 (int (*)(...))QSignalMapper::qt_metacall
+40 (int (*)(...))QSignalMapper::~QSignalMapper
+48 (int (*)(...))QSignalMapper::~QSignalMapper
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+
+Class QSignalMapper
+ size=16 align=8
+ base size=16 base align=8
+QSignalMapper (0x0x7f3bf73f56e8) 0
+ vptr=((& QSignalMapper::_ZTV13QSignalMapper) + 16)
+ QObject (0x0x7f3bf73f3c00) 0
+ primary-for QSignalMapper (0x0x7f3bf73f56e8)
+
+Class QSignalTransition::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QSignalTransition::QPrivateSignal (0x0x7f3bf73f3ea0) 0 empty
+
+Vtable for QSignalTransition
+QSignalTransition::_ZTV17QSignalTransition: 16 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI17QSignalTransition)
+16 (int (*)(...))QSignalTransition::metaObject
+24 (int (*)(...))QSignalTransition::qt_metacast
+32 (int (*)(...))QSignalTransition::qt_metacall
+40 (int (*)(...))QSignalTransition::~QSignalTransition
+48 (int (*)(...))QSignalTransition::~QSignalTransition
+56 (int (*)(...))QSignalTransition::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QSignalTransition::eventTest
+120 (int (*)(...))QSignalTransition::onTransition
+
+Class QSignalTransition
+ size=16 align=8
+ base size=16 base align=8
+QSignalTransition (0x0x7f3bf73f5750) 0
+ vptr=((& QSignalTransition::_ZTV17QSignalTransition) + 16)
+ QAbstractTransition (0x0x7f3bf73f57b8) 0
+ primary-for QSignalTransition (0x0x7f3bf73f5750)
+ QObject (0x0x7f3bf73f3e40) 0
+ primary-for QAbstractTransition (0x0x7f3bf73f57b8)
+
+Class QSocketNotifier::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QSocketNotifier::QPrivateSignal (0x0x7f3bf705c180) 0 empty
+
+Vtable for QSocketNotifier
+QSocketNotifier::_ZTV15QSocketNotifier: 14 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI15QSocketNotifier)
+16 (int (*)(...))QSocketNotifier::metaObject
+24 (int (*)(...))QSocketNotifier::qt_metacast
+32 (int (*)(...))QSocketNotifier::qt_metacall
+40 (int (*)(...))QSocketNotifier::~QSocketNotifier
+48 (int (*)(...))QSocketNotifier::~QSocketNotifier
+56 (int (*)(...))QSocketNotifier::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+
+Class QSocketNotifier
+ size=16 align=8
+ base size=16 base align=8
+QSocketNotifier (0x0x7f3bf73f5820) 0
+ vptr=((& QSocketNotifier::_ZTV15QSocketNotifier) + 16)
+ QObject (0x0x7f3bf705c120) 0
+ primary-for QSocketNotifier (0x0x7f3bf73f5820)
+
+Class QSortFilterProxyModel::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QSortFilterProxyModel::QPrivateSignal (0x0x7f3bf705c3c0) 0 empty
+
+Vtable for QSortFilterProxyModel
+QSortFilterProxyModel::_ZTV21QSortFilterProxyModel: 56 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI21QSortFilterProxyModel)
+16 (int (*)(...))QSortFilterProxyModel::metaObject
+24 (int (*)(...))QSortFilterProxyModel::qt_metacast
+32 (int (*)(...))QSortFilterProxyModel::qt_metacall
+40 (int (*)(...))QSortFilterProxyModel::~QSortFilterProxyModel
+48 (int (*)(...))QSortFilterProxyModel::~QSortFilterProxyModel
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QSortFilterProxyModel::index
+120 (int (*)(...))QSortFilterProxyModel::parent
+128 (int (*)(...))QSortFilterProxyModel::sibling
+136 (int (*)(...))QSortFilterProxyModel::rowCount
+144 (int (*)(...))QSortFilterProxyModel::columnCount
+152 (int (*)(...))QSortFilterProxyModel::hasChildren
+160 (int (*)(...))QSortFilterProxyModel::data
+168 (int (*)(...))QSortFilterProxyModel::setData
+176 (int (*)(...))QSortFilterProxyModel::headerData
+184 (int (*)(...))QSortFilterProxyModel::setHeaderData
+192 (int (*)(...))QAbstractProxyModel::itemData
+200 (int (*)(...))QAbstractProxyModel::setItemData
+208 (int (*)(...))QSortFilterProxyModel::mimeTypes
+216 (int (*)(...))QSortFilterProxyModel::mimeData
+224 (int (*)(...))QAbstractProxyModel::canDropMimeData
+232 (int (*)(...))QSortFilterProxyModel::dropMimeData
+240 (int (*)(...))QSortFilterProxyModel::supportedDropActions
+248 (int (*)(...))QAbstractProxyModel::supportedDragActions
+256 (int (*)(...))QSortFilterProxyModel::insertRows
+264 (int (*)(...))QSortFilterProxyModel::insertColumns
+272 (int (*)(...))QSortFilterProxyModel::removeRows
+280 (int (*)(...))QSortFilterProxyModel::removeColumns
+288 (int (*)(...))QAbstractItemModel::moveRows
+296 (int (*)(...))QAbstractItemModel::moveColumns
+304 (int (*)(...))QSortFilterProxyModel::fetchMore
+312 (int (*)(...))QSortFilterProxyModel::canFetchMore
+320 (int (*)(...))QSortFilterProxyModel::flags
+328 (int (*)(...))QSortFilterProxyModel::sort
+336 (int (*)(...))QSortFilterProxyModel::buddy
+344 (int (*)(...))QSortFilterProxyModel::match
+352 (int (*)(...))QSortFilterProxyModel::span
+360 (int (*)(...))QAbstractItemModel::roleNames
+368 (int (*)(...))QAbstractProxyModel::submit
+376 (int (*)(...))QAbstractProxyModel::revert
+384 (int (*)(...))QSortFilterProxyModel::setSourceModel
+392 (int (*)(...))QSortFilterProxyModel::mapToSource
+400 (int (*)(...))QSortFilterProxyModel::mapFromSource
+408 (int (*)(...))QSortFilterProxyModel::mapSelectionToSource
+416 (int (*)(...))QSortFilterProxyModel::mapSelectionFromSource
+424 (int (*)(...))QSortFilterProxyModel::filterAcceptsRow
+432 (int (*)(...))QSortFilterProxyModel::filterAcceptsColumn
+440 (int (*)(...))QSortFilterProxyModel::lessThan
+
+Class QSortFilterProxyModel
+ size=16 align=8
+ base size=16 base align=8
+QSortFilterProxyModel (0x0x7f3bf73f5888) 0
+ vptr=((& QSortFilterProxyModel::_ZTV21QSortFilterProxyModel) + 16)
+ QAbstractProxyModel (0x0x7f3bf73f58f0) 0
+ primary-for QSortFilterProxyModel (0x0x7f3bf73f5888)
+ QAbstractItemModel (0x0x7f3bf73f5958) 0
+ primary-for QAbstractProxyModel (0x0x7f3bf73f58f0)
+ QObject (0x0x7f3bf705c360) 0
+ primary-for QAbstractItemModel (0x0x7f3bf73f5958)
+
+Class QStandardPaths
+ size=1 align=1
+ base size=0 base align=1
+QStandardPaths (0x0x7f3bf705c7e0) 0 empty
+
+Class QState::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QState::QPrivateSignal (0x0x7f3bf70c7120) 0 empty
+
+Vtable for QState
+QState::_ZTV6QState: 16 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI6QState)
+16 (int (*)(...))QState::metaObject
+24 (int (*)(...))QState::qt_metacast
+32 (int (*)(...))QState::qt_metacall
+40 (int (*)(...))QState::~QState
+48 (int (*)(...))QState::~QState
+56 (int (*)(...))QState::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QState::onEntry
+120 (int (*)(...))QState::onExit
+
+Class QState
+ size=16 align=8
+ base size=16 base align=8
+QState (0x0x7f3bf73f5af8) 0
+ vptr=((& QState::_ZTV6QState) + 16)
+ QAbstractState (0x0x7f3bf73f5b60) 0
+ primary-for QState (0x0x7f3bf73f5af8)
+ QObject (0x0x7f3bf70c70c0) 0
+ primary-for QAbstractState (0x0x7f3bf73f5b60)
+
+Class QStateMachine::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QStateMachine::QPrivateSignal (0x0x7f3bf70c75a0) 0 empty
+
+Vtable for QStateMachine::SignalEvent
+QStateMachine::SignalEvent::_ZTVN13QStateMachine11SignalEventE: 4 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTIN13QStateMachine11SignalEventE)
+16 (int (*)(...))QStateMachine::SignalEvent::~SignalEvent
+24 (int (*)(...))QStateMachine::SignalEvent::~SignalEvent
+
+Class QStateMachine::SignalEvent
+ size=48 align=8
+ base size=48 base align=8
+QStateMachine::SignalEvent (0x0x7f3bf73f5d00) 0
+ vptr=((& QStateMachine::SignalEvent::_ZTVN13QStateMachine11SignalEventE) + 16)
+ QEvent (0x0x7f3bf70c7600) 0
+ primary-for QStateMachine::SignalEvent (0x0x7f3bf73f5d00)
+
+Vtable for QStateMachine::WrappedEvent
+QStateMachine::WrappedEvent::_ZTVN13QStateMachine12WrappedEventE: 4 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTIN13QStateMachine12WrappedEventE)
+16 (int (*)(...))QStateMachine::WrappedEvent::~WrappedEvent
+24 (int (*)(...))QStateMachine::WrappedEvent::~WrappedEvent
+
+Class QStateMachine::WrappedEvent
+ size=40 align=8
+ base size=40 base align=8
+QStateMachine::WrappedEvent (0x0x7f3bf73f5d68) 0
+ vptr=((& QStateMachine::WrappedEvent::_ZTVN13QStateMachine12WrappedEventE) + 16)
+ QEvent (0x0x7f3bf70c7660) 0
+ primary-for QStateMachine::WrappedEvent (0x0x7f3bf73f5d68)
+
+Vtable for QStateMachine
+QStateMachine::_ZTV13QStateMachine: 20 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI13QStateMachine)
+16 (int (*)(...))QStateMachine::metaObject
+24 (int (*)(...))QStateMachine::qt_metacast
+32 (int (*)(...))QStateMachine::qt_metacall
+40 (int (*)(...))QStateMachine::~QStateMachine
+48 (int (*)(...))QStateMachine::~QStateMachine
+56 (int (*)(...))QStateMachine::event
+64 (int (*)(...))QStateMachine::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QStateMachine::onEntry
+120 (int (*)(...))QStateMachine::onExit
+128 (int (*)(...))QStateMachine::beginSelectTransitions
+136 (int (*)(...))QStateMachine::endSelectTransitions
+144 (int (*)(...))QStateMachine::beginMicrostep
+152 (int (*)(...))QStateMachine::endMicrostep
+
+Class QStateMachine
+ size=16 align=8
+ base size=16 base align=8
+QStateMachine (0x0x7f3bf73f5bc8) 0
+ vptr=((& QStateMachine::_ZTV13QStateMachine) + 16)
+ QState (0x0x7f3bf73f5c30) 0
+ primary-for QStateMachine (0x0x7f3bf73f5bc8)
+ QAbstractState (0x0x7f3bf73f5c98) 0
+ primary-for QState (0x0x7f3bf73f5c30)
+ QObject (0x0x7f3bf70c7540) 0
+ primary-for QAbstractState (0x0x7f3bf73f5c98)
+
+Class QStorageInfo
+ size=8 align=8
+ base size=8 base align=8
+QStorageInfo (0x0x7f3bf70c7a20) 0
+
+Class QAbstractConcatenable
+ size=1 align=1
+ base size=0 base align=1
+QAbstractConcatenable (0x0x7f3bf71ea7e0) 0 empty
+
+Class QStringListModel::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QStringListModel::QPrivateSignal (0x0x7f3bf6e72b40) 0 empty
+
+Vtable for QStringListModel
+QStringListModel::_ZTV16QStringListModel: 48 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI16QStringListModel)
+16 (int (*)(...))QStringListModel::metaObject
+24 (int (*)(...))QStringListModel::qt_metacast
+32 (int (*)(...))QStringListModel::qt_metacall
+40 (int (*)(...))QStringListModel::~QStringListModel
+48 (int (*)(...))QStringListModel::~QStringListModel
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QAbstractListModel::index
+120 (int (*)(...))QAbstractListModel::parent
+128 (int (*)(...))QStringListModel::sibling
+136 (int (*)(...))QStringListModel::rowCount
+144 (int (*)(...))QAbstractListModel::columnCount
+152 (int (*)(...))QAbstractListModel::hasChildren
+160 (int (*)(...))QStringListModel::data
+168 (int (*)(...))QStringListModel::setData
+176 (int (*)(...))QAbstractItemModel::headerData
+184 (int (*)(...))QAbstractItemModel::setHeaderData
+192 (int (*)(...))QStringListModel::itemData
+200 (int (*)(...))QStringListModel::setItemData
+208 (int (*)(...))QAbstractItemModel::mimeTypes
+216 (int (*)(...))QAbstractItemModel::mimeData
+224 (int (*)(...))QAbstractItemModel::canDropMimeData
+232 (int (*)(...))QAbstractListModel::dropMimeData
+240 (int (*)(...))QStringListModel::supportedDropActions
+248 (int (*)(...))QAbstractItemModel::supportedDragActions
+256 (int (*)(...))QStringListModel::insertRows
+264 (int (*)(...))QAbstractItemModel::insertColumns
+272 (int (*)(...))QStringListModel::removeRows
+280 (int (*)(...))QAbstractItemModel::removeColumns
+288 (int (*)(...))QStringListModel::moveRows
+296 (int (*)(...))QAbstractItemModel::moveColumns
+304 (int (*)(...))QAbstractItemModel::fetchMore
+312 (int (*)(...))QAbstractItemModel::canFetchMore
+320 (int (*)(...))QStringListModel::flags
+328 (int (*)(...))QStringListModel::sort
+336 (int (*)(...))QAbstractItemModel::buddy
+344 (int (*)(...))QAbstractItemModel::match
+352 (int (*)(...))QAbstractItemModel::span
+360 (int (*)(...))QAbstractItemModel::roleNames
+368 (int (*)(...))QAbstractItemModel::submit
+376 (int (*)(...))QAbstractItemModel::revert
+
+Class QStringListModel
+ size=24 align=8
+ base size=24 base align=8
+QStringListModel (0x0x7f3bf6e6f680) 0
+ vptr=((& QStringListModel::_ZTV16QStringListModel) + 16)
+ QAbstractListModel (0x0x7f3bf6e6f6e8) 0
+ primary-for QStringListModel (0x0x7f3bf6e6f680)
+ QAbstractItemModel (0x0x7f3bf6e6f750) 0
+ primary-for QAbstractListModel (0x0x7f3bf6e6f6e8)
+ QObject (0x0x7f3bf6e72ae0) 0
+ primary-for QAbstractItemModel (0x0x7f3bf6e6f750)
+
+Class QSystemSemaphore
+ size=8 align=8
+ base size=8 base align=8
+QSystemSemaphore (0x0x7f3bf6e72c60) 0
+
+Class QTemporaryDir
+ size=8 align=8
+ base size=8 base align=8
+QTemporaryDir (0x0x7f3bf6e72d20) 0
+
+Class QTemporaryFile::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QTemporaryFile::QPrivateSignal (0x0x7f3bf6e72e40) 0 empty
+
+Vtable for QTemporaryFile
+QTemporaryFile::_ZTV14QTemporaryFile: 34 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI14QTemporaryFile)
+16 (int (*)(...))QTemporaryFile::metaObject
+24 (int (*)(...))QTemporaryFile::qt_metacast
+32 (int (*)(...))QTemporaryFile::qt_metacall
+40 (int (*)(...))QTemporaryFile::~QTemporaryFile
+48 (int (*)(...))QTemporaryFile::~QTemporaryFile
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QFileDevice::isSequential
+120 (int (*)(...))QTemporaryFile::open
+128 (int (*)(...))QFileDevice::close
+136 (int (*)(...))QFileDevice::pos
+144 (int (*)(...))QFile::size
+152 (int (*)(...))QFileDevice::seek
+160 (int (*)(...))QFileDevice::atEnd
+168 (int (*)(...))QIODevice::reset
+176 (int (*)(...))QIODevice::bytesAvailable
+184 (int (*)(...))QIODevice::bytesToWrite
+192 (int (*)(...))QIODevice::canReadLine
+200 (int (*)(...))QIODevice::waitForReadyRead
+208 (int (*)(...))QIODevice::waitForBytesWritten
+216 (int (*)(...))QFileDevice::readData
+224 (int (*)(...))QFileDevice::readLineData
+232 (int (*)(...))QFileDevice::writeData
+240 (int (*)(...))QTemporaryFile::fileName
+248 (int (*)(...))QFile::resize
+256 (int (*)(...))QFile::permissions
+264 (int (*)(...))QFile::setPermissions
+
+Class QTemporaryFile
+ size=16 align=8
+ base size=16 base align=8
+QTemporaryFile (0x0x7f3bf6e6f7b8) 0
+ vptr=((& QTemporaryFile::_ZTV14QTemporaryFile) + 16)
+ QFile (0x0x7f3bf6e6f820) 0
+ primary-for QTemporaryFile (0x0x7f3bf6e6f7b8)
+ QFileDevice (0x0x7f3bf6e6f888) 0
+ primary-for QFile (0x0x7f3bf6e6f820)
+ QIODevice (0x0x7f3bf6e6f8f0) 0
+ primary-for QFileDevice (0x0x7f3bf6e6f888)
+ QObject (0x0x7f3bf6e72de0) 0
+ primary-for QIODevice (0x0x7f3bf6e6f8f0)
+
+Class QTextBoundaryFinder
+ size=48 align=8
+ base size=48 base align=8
+QTextBoundaryFinder (0x0x7f3bf6ed01e0) 0
+
+Class QTextCodec::ConverterState
+ size=32 align=8
+ base size=32 base align=8
+QTextCodec::ConverterState (0x0x7f3bf6ed0a20) 0
+
+Vtable for QTextCodec
+QTextCodec::_ZTV10QTextCodec: 9 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI10QTextCodec)
+16 (int (*)(...))__cxa_pure_virtual
+24 (int (*)(...))QTextCodec::aliases
+32 (int (*)(...))__cxa_pure_virtual
+40 (int (*)(...))__cxa_pure_virtual
+48 (int (*)(...))__cxa_pure_virtual
+56 0
+64 0
+
+Class QTextCodec
+ size=8 align=8
+ base size=8 base align=8
+QTextCodec (0x0x7f3bf6ed09c0) 0 nearly-empty
+ vptr=((& QTextCodec::_ZTV10QTextCodec) + 16)
+
+Class QTextEncoder
+ size=40 align=8
+ base size=40 base align=8
+QTextEncoder (0x0x7f3bf6f35420) 0
+
+Class QTextDecoder
+ size=40 align=8
+ base size=40 base align=8
+QTextDecoder (0x0x7f3bf6f35600) 0
+
+Vtable for std::thread::_State
+std::thread::_State::_ZTVNSt6thread6_StateE: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTINSt6thread6_StateE)
+16 0
+24 0
+32 (int (*)(...))__cxa_pure_virtual
+
+Class std::thread::_State
+ size=8 align=8
+ base size=8 base align=8
+std::thread::_State (0x0x7f3bf6f35840) 0 nearly-empty
+ vptr=((& std::thread::_State::_ZTVNSt6thread6_StateE) + 16)
+
+Class std::thread::id
+ size=8 align=8
+ base size=8 base align=8
+std::thread::id (0x0x7f3bf6f358a0) 0
+
+Class std::thread
+ size=8 align=8
+ base size=8 base align=8
+std::thread (0x0x7f3bf6f357e0) 0
+
+Class std::condition_variable
+ size=48 align=8
+ base size=48 base align=8
+std::condition_variable (0x0x7f3bf6dd9c60) 0
+
+Class std::__at_thread_exit_elt
+ size=16 align=8
+ base size=16 base align=8
+std::__at_thread_exit_elt (0x0x7f3bf6a26060) 0
+
+Class std::_V2::condition_variable_any
+ size=64 align=8
+ base size=64 base align=8
+std::_V2::condition_variable_any (0x0x7f3bf6a260c0) 0
+
+Class std::__atomic_futex_unsigned_base
+ size=1 align=1
+ base size=0 base align=1
+std::__atomic_futex_unsigned_base (0x0x7f3bf6b8a3c0) 0 empty
+
+Vtable for std::future_error
+std::future_error::_ZTVSt12future_error: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTISt12future_error)
+16 (int (*)(...))std::future_error::~future_error
+24 (int (*)(...))std::future_error::~future_error
+32 (int (*)(...))std::future_error::what
+
+Class std::future_error
+ size=32 align=8
+ base size=32 base align=8
+std::future_error (0x0x7f3bf6b7bc98) 0
+ vptr=((& std::future_error::_ZTVSt12future_error) + 16)
+ std::logic_error (0x0x7f3bf6b7bd00) 0
+ primary-for std::future_error (0x0x7f3bf6b7bc98)
+ std::exception (0x0x7f3bf6b8aae0) 0 nearly-empty
+ primary-for std::logic_error (0x0x7f3bf6b7bd00)
+
+Class std::__future_base::_Result_base::_Deleter
+ size=1 align=1
+ base size=0 base align=1
+std::__future_base::_Result_base::_Deleter (0x0x7f3bf6bbd240) 0 empty
+
+Vtable for std::__future_base::_Result_base
+std::__future_base::_Result_base::_ZTVNSt13__future_base12_Result_baseE: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTINSt13__future_base12_Result_baseE)
+16 (int (*)(...))__cxa_pure_virtual
+24 0
+32 0
+
+Class std::__future_base::_Result_base
+ size=16 align=8
+ base size=16 base align=8
+std::__future_base::_Result_base (0x0x7f3bf6bbd1e0) 0
+ vptr=((& std::__future_base::_Result_base::_ZTVNSt13__future_base12_Result_baseE) + 16)
+
+Class std::__future_base::_State_baseV2::__exception_ptr_tag
+ size=1 align=1
+ base size=0 base align=1
+std::__future_base::_State_baseV2::__exception_ptr_tag (0x0x7f3bf699a960) 0 empty
+
+Class std::__future_base::_State_baseV2::_Make_ready
+ size=32 align=8
+ base size=32 base align=8
+std::__future_base::_State_baseV2::_Make_ready (0x0x7f3bf69a0548) 0
+ std::__at_thread_exit_elt (0x0x7f3bf699aa20) 0
+
+Vtable for std::__future_base::_State_baseV2
+std::__future_base::_State_baseV2::_ZTVNSt13__future_base13_State_baseV2E: 6 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTINSt13__future_base13_State_baseV2E)
+16 (int (*)(...))std::__future_base::_State_baseV2::~_State_baseV2
+24 (int (*)(...))std::__future_base::_State_baseV2::~_State_baseV2
+32 (int (*)(...))std::__future_base::_State_baseV2::_M_complete_async
+40 (int (*)(...))std::__future_base::_State_baseV2::_M_is_deferred_future
+
+Class std::__future_base::_State_baseV2
+ size=32 align=8
+ base size=28 base align=8
+std::__future_base::_State_baseV2 (0x0x7f3bf6bbd3c0) 0
+ vptr=((& std::__future_base::_State_baseV2::_ZTVNSt13__future_base13_State_baseV2E) + 16)
+
+Class std::__future_base
+ size=1 align=1
+ base size=0 base align=1
+std::__future_base (0x0x7f3bf6bbd180) 0 empty
+
+Vtable for std::__future_base::_Async_state_commonV2
+std::__future_base::_Async_state_commonV2::_ZTVNSt13__future_base21_Async_state_commonV2E: 6 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTINSt13__future_base21_Async_state_commonV2E)
+16 (int (*)(...))std::__future_base::_Async_state_commonV2::~_Async_state_commonV2
+24 (int (*)(...))std::__future_base::_Async_state_commonV2::~_Async_state_commonV2
+32 (int (*)(...))std::__future_base::_Async_state_commonV2::_M_complete_async
+40 (int (*)(...))std::__future_base::_State_baseV2::_M_is_deferred_future
+
+Class std::__future_base::_Async_state_commonV2
+ size=48 align=8
+ base size=44 base align=8
+std::__future_base::_Async_state_commonV2 (0x0x7f3bf6136270) 0
+ vptr=((& std::__future_base::_Async_state_commonV2::_ZTVNSt13__future_base21_Async_state_commonV2E) + 16)
+ std::__future_base::_State_baseV2 (0x0x7f3bf6143a20) 0
+ primary-for std::__future_base::_Async_state_commonV2 (0x0x7f3bf6136270)
+
+Class QThread::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QThread::QPrivateSignal (0x0x7f3bf6177300) 0 empty
+
+Vtable for QThread
+QThread::_ZTV7QThread: 15 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI7QThread)
+16 (int (*)(...))QThread::metaObject
+24 (int (*)(...))QThread::qt_metacast
+32 (int (*)(...))QThread::qt_metacall
+40 (int (*)(...))QThread::~QThread
+48 (int (*)(...))QThread::~QThread
+56 (int (*)(...))QThread::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QThread::run
+
+Class QThread
+ size=16 align=8
+ base size=16 base align=8
+QThread (0x0x7f3bf61365b0) 0
+ vptr=((& QThread::_ZTV7QThread) + 16)
+ QObject (0x0x7f3bf61772a0) 0
+ primary-for QThread (0x0x7f3bf61365b0)
+
+Class QThreadPool::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QThreadPool::QPrivateSignal (0x0x7f3bf61776c0) 0 empty
+
+Vtable for QThreadPool
+QThreadPool::_ZTV11QThreadPool: 14 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI11QThreadPool)
+16 (int (*)(...))QThreadPool::metaObject
+24 (int (*)(...))QThreadPool::qt_metacast
+32 (int (*)(...))QThreadPool::qt_metacall
+40 (int (*)(...))QThreadPool::~QThreadPool
+48 (int (*)(...))QThreadPool::~QThreadPool
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+
+Class QThreadPool
+ size=16 align=8
+ base size=16 base align=8
+QThreadPool (0x0x7f3bf6136618) 0
+ vptr=((& QThreadPool::_ZTV11QThreadPool) + 16)
+ QObject (0x0x7f3bf6177660) 0
+ primary-for QThreadPool (0x0x7f3bf6136618)
+
+Class QThreadStorageData
+ size=4 align=4
+ base size=4 base align=4
+QThreadStorageData (0x0x7f3bf61778a0) 0
+
+Class QTimeLine::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QTimeLine::QPrivateSignal (0x0x7f3bf6177f60) 0 empty
+
+Vtable for QTimeLine
+QTimeLine::_ZTV9QTimeLine: 15 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI9QTimeLine)
+16 (int (*)(...))QTimeLine::metaObject
+24 (int (*)(...))QTimeLine::qt_metacast
+32 (int (*)(...))QTimeLine::qt_metacall
+40 (int (*)(...))QTimeLine::~QTimeLine
+48 (int (*)(...))QTimeLine::~QTimeLine
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QTimeLine::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QTimeLine::valueForTime
+
+Class QTimeLine
+ size=16 align=8
+ base size=16 base align=8
+QTimeLine (0x0x7f3bf6136680) 0
+ vptr=((& QTimeLine::_ZTV9QTimeLine) + 16)
+ QObject (0x0x7f3bf6177f00) 0
+ primary-for QTimeLine (0x0x7f3bf6136680)
+
+Class QTimer::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QTimer::QPrivateSignal (0x0x7f3bf61ca1e0) 0 empty
+
+Vtable for QTimer
+QTimer::_ZTV6QTimer: 14 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI6QTimer)
+16 (int (*)(...))QTimer::metaObject
+24 (int (*)(...))QTimer::qt_metacast
+32 (int (*)(...))QTimer::qt_metacall
+40 (int (*)(...))QTimer::~QTimer
+48 (int (*)(...))QTimer::~QTimer
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QTimer::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+
+Class QTimer
+ size=32 align=8
+ base size=29 base align=8
+QTimer (0x0x7f3bf61366e8) 0
+ vptr=((& QTimer::_ZTV6QTimer) + 16)
+ QObject (0x0x7f3bf61ca180) 0
+ primary-for QTimer (0x0x7f3bf61366e8)
+
+Class QTimeZone::OffsetData
+ size=32 align=8
+ base size=28 base align=8
+QTimeZone::OffsetData (0x0x7f3bf5e02b40) 0
+
+Class QTimeZone
+ size=8 align=8
+ base size=8 base align=8
+QTimeZone (0x0x7f3bf5e02ae0) 0
+
+Class QTranslator::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QTranslator::QPrivateSignal (0x0x7f3bf5ea0c00) 0 empty
+
+Vtable for QTranslator
+QTranslator::_ZTV11QTranslator: 16 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI11QTranslator)
+16 (int (*)(...))QTranslator::metaObject
+24 (int (*)(...))QTranslator::qt_metacast
+32 (int (*)(...))QTranslator::qt_metacall
+40 (int (*)(...))QTranslator::~QTranslator
+48 (int (*)(...))QTranslator::~QTranslator
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QTranslator::translate
+120 (int (*)(...))QTranslator::isEmpty
+
+Class QTranslator
+ size=16 align=8
+ base size=16 base align=8
+QTranslator (0x0x7f3bf5e9fdd0) 0
+ vptr=((& QTranslator::_ZTV11QTranslator) + 16)
+ QObject (0x0x7f3bf5ea0ba0) 0
+ primary-for QTranslator (0x0x7f3bf5e9fdd0)
+
+Class QTransposeProxyModel::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QTransposeProxyModel::QPrivateSignal (0x0x7f3bf5ea0e40) 0 empty
+
+Vtable for QTransposeProxyModel
+QTransposeProxyModel::_ZTV20QTransposeProxyModel: 53 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI20QTransposeProxyModel)
+16 (int (*)(...))QTransposeProxyModel::metaObject
+24 (int (*)(...))QTransposeProxyModel::qt_metacast
+32 (int (*)(...))QTransposeProxyModel::qt_metacall
+40 (int (*)(...))QTransposeProxyModel::~QTransposeProxyModel
+48 (int (*)(...))QTransposeProxyModel::~QTransposeProxyModel
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QTransposeProxyModel::index
+120 (int (*)(...))QTransposeProxyModel::parent
+128 (int (*)(...))QAbstractProxyModel::sibling
+136 (int (*)(...))QTransposeProxyModel::rowCount
+144 (int (*)(...))QTransposeProxyModel::columnCount
+152 (int (*)(...))QAbstractProxyModel::hasChildren
+160 (int (*)(...))QAbstractProxyModel::data
+168 (int (*)(...))QAbstractProxyModel::setData
+176 (int (*)(...))QTransposeProxyModel::headerData
+184 (int (*)(...))QTransposeProxyModel::setHeaderData
+192 (int (*)(...))QTransposeProxyModel::itemData
+200 (int (*)(...))QTransposeProxyModel::setItemData
+208 (int (*)(...))QAbstractProxyModel::mimeTypes
+216 (int (*)(...))QAbstractProxyModel::mimeData
+224 (int (*)(...))QAbstractProxyModel::canDropMimeData
+232 (int (*)(...))QAbstractProxyModel::dropMimeData
+240 (int (*)(...))QAbstractProxyModel::supportedDropActions
+248 (int (*)(...))QAbstractProxyModel::supportedDragActions
+256 (int (*)(...))QTransposeProxyModel::insertRows
+264 (int (*)(...))QTransposeProxyModel::insertColumns
+272 (int (*)(...))QTransposeProxyModel::removeRows
+280 (int (*)(...))QTransposeProxyModel::removeColumns
+288 (int (*)(...))QTransposeProxyModel::moveRows
+296 (int (*)(...))QTransposeProxyModel::moveColumns
+304 (int (*)(...))QAbstractProxyModel::fetchMore
+312 (int (*)(...))QAbstractProxyModel::canFetchMore
+320 (int (*)(...))QAbstractProxyModel::flags
+328 (int (*)(...))QTransposeProxyModel::sort
+336 (int (*)(...))QAbstractProxyModel::buddy
+344 (int (*)(...))QAbstractItemModel::match
+352 (int (*)(...))QTransposeProxyModel::span
+360 (int (*)(...))QAbstractItemModel::roleNames
+368 (int (*)(...))QAbstractProxyModel::submit
+376 (int (*)(...))QAbstractProxyModel::revert
+384 (int (*)(...))QTransposeProxyModel::setSourceModel
+392 (int (*)(...))QTransposeProxyModel::mapToSource
+400 (int (*)(...))QTransposeProxyModel::mapFromSource
+408 (int (*)(...))QAbstractProxyModel::mapSelectionToSource
+416 (int (*)(...))QAbstractProxyModel::mapSelectionFromSource
+
+Class QTransposeProxyModel
+ size=16 align=8
+ base size=16 base align=8
+QTransposeProxyModel (0x0x7f3bf5e9fe38) 0
+ vptr=((& QTransposeProxyModel::_ZTV20QTransposeProxyModel) + 16)
+ QAbstractProxyModel (0x0x7f3bf5e9fea0) 0
+ primary-for QTransposeProxyModel (0x0x7f3bf5e9fe38)
+ QAbstractItemModel (0x0x7f3bf5e9ff08) 0
+ primary-for QAbstractProxyModel (0x0x7f3bf5e9fea0)
+ QObject (0x0x7f3bf5ea0de0) 0
+ primary-for QAbstractItemModel (0x0x7f3bf5e9ff08)
+
+Class QUrlQuery
+ size=8 align=8
+ base size=8 base align=8
+QUrlQuery (0x0x7f3bf5ee2060) 0
+
+Class QWaitCondition
+ size=8 align=8
+ base size=8 base align=8
+QWaitCondition (0x0x7f3bf5fbd540) 0
+
+Class QXmlStreamStringRef
+ size=16 align=8
+ base size=16 base align=8
+QXmlStreamStringRef (0x0x7f3bf5fbd660) 0
+
+Class QXmlStreamAttribute
+ size=80 align=8
+ base size=73 base align=8
+QXmlStreamAttribute (0x0x7f3bf5b50a20) 0
+
+Class QXmlStreamAttributes
+ size=8 align=8
+ base size=8 base align=8
+QXmlStreamAttributes (0x0x7f3bf5bc6208) 0
+ QVector<QXmlStreamAttribute> (0x0x7f3bf5bc7180) 0
+
+Class QXmlStreamNamespaceDeclaration
+ size=40 align=8
+ base size=40 base align=8
+QXmlStreamNamespaceDeclaration (0x0x7f3bf5bc7480) 0
+
+Class QXmlStreamNotationDeclaration
+ size=56 align=8
+ base size=56 base align=8
+QXmlStreamNotationDeclaration (0x0x7f3bf5c51420) 0
+
+Class QXmlStreamEntityDeclaration
+ size=88 align=8
+ base size=88 base align=8
+QXmlStreamEntityDeclaration (0x0x7f3bf5cb0420) 0
+
+Vtable for QXmlStreamEntityResolver
+QXmlStreamEntityResolver::_ZTV24QXmlStreamEntityResolver: 6 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI24QXmlStreamEntityResolver)
+16 (int (*)(...))QXmlStreamEntityResolver::~QXmlStreamEntityResolver
+24 (int (*)(...))QXmlStreamEntityResolver::~QXmlStreamEntityResolver
+32 (int (*)(...))QXmlStreamEntityResolver::resolveEntity
+40 (int (*)(...))QXmlStreamEntityResolver::resolveUndeclaredEntity
+
+Class QXmlStreamEntityResolver
+ size=8 align=8
+ base size=8 base align=8
+QXmlStreamEntityResolver (0x0x7f3bf591a4e0) 0 nearly-empty
+ vptr=((& QXmlStreamEntityResolver::_ZTV24QXmlStreamEntityResolver) + 16)
+
+Class QXmlStreamReader
+ size=8 align=8
+ base size=8 base align=8
+QXmlStreamReader (0x0x7f3bf591a540) 0
+
+Class QXmlStreamWriter
+ size=8 align=8
+ base size=8 base align=8
+QXmlStreamWriter (0x0x7f3bf5977420) 0
+
+Class QNetworkRequest
+ size=8 align=8
+ base size=8 base align=8
+QNetworkRequest (0x0x7f3bf5977600) 0
+
+Class QNetworkCacheMetaData
+ size=8 align=8
+ base size=8 base align=8
+QNetworkCacheMetaData (0x0x7f3bf5a56a80) 0
+
+Class QAbstractNetworkCache::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QAbstractNetworkCache::QPrivateSignal (0x0x7f3bf5725f60) 0 empty
+
+Vtable for QAbstractNetworkCache
+QAbstractNetworkCache::_ZTV21QAbstractNetworkCache: 22 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI21QAbstractNetworkCache)
+16 (int (*)(...))QAbstractNetworkCache::metaObject
+24 (int (*)(...))QAbstractNetworkCache::qt_metacast
+32 (int (*)(...))QAbstractNetworkCache::qt_metacall
+40 0
+48 0
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))__cxa_pure_virtual
+120 (int (*)(...))__cxa_pure_virtual
+128 (int (*)(...))__cxa_pure_virtual
+136 (int (*)(...))__cxa_pure_virtual
+144 (int (*)(...))__cxa_pure_virtual
+152 (int (*)(...))__cxa_pure_virtual
+160 (int (*)(...))__cxa_pure_virtual
+168 (int (*)(...))__cxa_pure_virtual
+
+Class QAbstractNetworkCache
+ size=16 align=8
+ base size=16 base align=8
+QAbstractNetworkCache (0x0x7f3bf5728af8) 0
+ vptr=((& QAbstractNetworkCache::_ZTV21QAbstractNetworkCache) + 16)
+ QObject (0x0x7f3bf5725f00) 0
+ primary-for QAbstractNetworkCache (0x0x7f3bf5728af8)
+
+Class QAbstractSocket::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QAbstractSocket::QPrivateSignal (0x0x7f3bf57491e0) 0 empty
+
+Vtable for QAbstractSocket
+QAbstractSocket::_ZTV15QAbstractSocket: 41 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI15QAbstractSocket)
+16 (int (*)(...))QAbstractSocket::metaObject
+24 (int (*)(...))QAbstractSocket::qt_metacast
+32 (int (*)(...))QAbstractSocket::qt_metacall
+40 (int (*)(...))QAbstractSocket::~QAbstractSocket
+48 (int (*)(...))QAbstractSocket::~QAbstractSocket
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QAbstractSocket::isSequential
+120 (int (*)(...))QIODevice::open
+128 (int (*)(...))QAbstractSocket::close
+136 (int (*)(...))QIODevice::pos
+144 (int (*)(...))QIODevice::size
+152 (int (*)(...))QIODevice::seek
+160 (int (*)(...))QAbstractSocket::atEnd
+168 (int (*)(...))QIODevice::reset
+176 (int (*)(...))QAbstractSocket::bytesAvailable
+184 (int (*)(...))QAbstractSocket::bytesToWrite
+192 (int (*)(...))QAbstractSocket::canReadLine
+200 (int (*)(...))QAbstractSocket::waitForReadyRead
+208 (int (*)(...))QAbstractSocket::waitForBytesWritten
+216 (int (*)(...))QAbstractSocket::readData
+224 (int (*)(...))QAbstractSocket::readLineData
+232 (int (*)(...))QAbstractSocket::writeData
+240 (int (*)(...))QAbstractSocket::resume
+248 (int (*)(...))QAbstractSocket::connectToHost
+256 (int (*)(...))QAbstractSocket::connectToHost
+264 (int (*)(...))QAbstractSocket::disconnectFromHost
+272 (int (*)(...))QAbstractSocket::setReadBufferSize
+280 (int (*)(...))QAbstractSocket::socketDescriptor
+288 (int (*)(...))QAbstractSocket::setSocketDescriptor
+296 (int (*)(...))QAbstractSocket::setSocketOption
+304 (int (*)(...))QAbstractSocket::socketOption
+312 (int (*)(...))QAbstractSocket::waitForConnected
+320 (int (*)(...))QAbstractSocket::waitForDisconnected
+
+Class QAbstractSocket
+ size=16 align=8
+ base size=16 base align=8
+QAbstractSocket (0x0x7f3bf5728b60) 0
+ vptr=((& QAbstractSocket::_ZTV15QAbstractSocket) + 16)
+ QIODevice (0x0x7f3bf5728bc8) 0
+ primary-for QAbstractSocket (0x0x7f3bf5728b60)
+ QObject (0x0x7f3bf5749180) 0
+ primary-for QIODevice (0x0x7f3bf5728bc8)
+
+Class QAuthenticator
+ size=8 align=8
+ base size=8 base align=8
+QAuthenticator (0x0x7f3bf57c5900) 0
+
+Class QDnsDomainNameRecord
+ size=8 align=8
+ base size=8 base align=8
+QDnsDomainNameRecord (0x0x7f3bf57c59c0) 0
+
+Class QDnsHostAddressRecord
+ size=8 align=8
+ base size=8 base align=8
+QDnsHostAddressRecord (0x0x7f3bf589aa80) 0
+
+Class QDnsMailExchangeRecord
+ size=8 align=8
+ base size=8 base align=8
+QDnsMailExchangeRecord (0x0x7f3bf5555b40) 0
+
+Class QDnsServiceRecord
+ size=8 align=8
+ base size=8 base align=8
+QDnsServiceRecord (0x0x7f3bf5611b40) 0
+
+Class QDnsTextRecord
+ size=8 align=8
+ base size=8 base align=8
+QDnsTextRecord (0x0x7f3bf56cca20) 0
+
+Class QDnsLookup::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QDnsLookup::QPrivateSignal (0x0x7f3bf5389a80) 0 empty
+
+Vtable for QDnsLookup
+QDnsLookup::_ZTV10QDnsLookup: 14 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI10QDnsLookup)
+16 (int (*)(...))QDnsLookup::metaObject
+24 (int (*)(...))QDnsLookup::qt_metacast
+32 (int (*)(...))QDnsLookup::qt_metacall
+40 (int (*)(...))QDnsLookup::~QDnsLookup
+48 (int (*)(...))QDnsLookup::~QDnsLookup
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+
+Class QDnsLookup
+ size=16 align=8
+ base size=16 base align=8
+QDnsLookup (0x0x7f3bf538aa90) 0
+ vptr=((& QDnsLookup::_ZTV10QDnsLookup) + 16)
+ QObject (0x0x7f3bf5389a20) 0
+ primary-for QDnsLookup (0x0x7f3bf538aa90)
+
+Class QTcpSocket::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QTcpSocket::QPrivateSignal (0x0x7f3bf5389e40) 0 empty
+
+Vtable for QTcpSocket
+QTcpSocket::_ZTV10QTcpSocket: 41 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI10QTcpSocket)
+16 (int (*)(...))QTcpSocket::metaObject
+24 (int (*)(...))QTcpSocket::qt_metacast
+32 (int (*)(...))QTcpSocket::qt_metacall
+40 (int (*)(...))QTcpSocket::~QTcpSocket
+48 (int (*)(...))QTcpSocket::~QTcpSocket
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QAbstractSocket::isSequential
+120 (int (*)(...))QIODevice::open
+128 (int (*)(...))QAbstractSocket::close
+136 (int (*)(...))QIODevice::pos
+144 (int (*)(...))QIODevice::size
+152 (int (*)(...))QIODevice::seek
+160 (int (*)(...))QAbstractSocket::atEnd
+168 (int (*)(...))QIODevice::reset
+176 (int (*)(...))QAbstractSocket::bytesAvailable
+184 (int (*)(...))QAbstractSocket::bytesToWrite
+192 (int (*)(...))QAbstractSocket::canReadLine
+200 (int (*)(...))QAbstractSocket::waitForReadyRead
+208 (int (*)(...))QAbstractSocket::waitForBytesWritten
+216 (int (*)(...))QAbstractSocket::readData
+224 (int (*)(...))QAbstractSocket::readLineData
+232 (int (*)(...))QAbstractSocket::writeData
+240 (int (*)(...))QAbstractSocket::resume
+248 (int (*)(...))QAbstractSocket::connectToHost
+256 (int (*)(...))QAbstractSocket::connectToHost
+264 (int (*)(...))QAbstractSocket::disconnectFromHost
+272 (int (*)(...))QAbstractSocket::setReadBufferSize
+280 (int (*)(...))QAbstractSocket::socketDescriptor
+288 (int (*)(...))QAbstractSocket::setSocketDescriptor
+296 (int (*)(...))QAbstractSocket::setSocketOption
+304 (int (*)(...))QAbstractSocket::socketOption
+312 (int (*)(...))QAbstractSocket::waitForConnected
+320 (int (*)(...))QAbstractSocket::waitForDisconnected
+
+Class QTcpSocket
+ size=16 align=8
+ base size=16 base align=8
+QTcpSocket (0x0x7f3bf538aaf8) 0
+ vptr=((& QTcpSocket::_ZTV10QTcpSocket) + 16)
+ QAbstractSocket (0x0x7f3bf538ab60) 0
+ primary-for QTcpSocket (0x0x7f3bf538aaf8)
+ QIODevice (0x0x7f3bf538abc8) 0
+ primary-for QAbstractSocket (0x0x7f3bf538ab60)
+ QObject (0x0x7f3bf5389de0) 0
+ primary-for QIODevice (0x0x7f3bf538abc8)
+
+Class QSslCertificate
+ size=8 align=8
+ base size=8 base align=8
+QSslCertificate (0x0x7f3bf53bf720) 0
+
+Class QSslError
+ size=8 align=8
+ base size=8 base align=8
+QSslError (0x0x7f3bf54a7f60) 0
+
+Class QSslSocket::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QSslSocket::QPrivateSignal (0x0x7f3bf5191240) 0 empty
+
+Vtable for QSslSocket
+QSslSocket::_ZTV10QSslSocket: 41 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI10QSslSocket)
+16 (int (*)(...))QSslSocket::metaObject
+24 (int (*)(...))QSslSocket::qt_metacast
+32 (int (*)(...))QSslSocket::qt_metacall
+40 (int (*)(...))QSslSocket::~QSslSocket
+48 (int (*)(...))QSslSocket::~QSslSocket
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QAbstractSocket::isSequential
+120 (int (*)(...))QIODevice::open
+128 (int (*)(...))QSslSocket::close
+136 (int (*)(...))QIODevice::pos
+144 (int (*)(...))QIODevice::size
+152 (int (*)(...))QIODevice::seek
+160 (int (*)(...))QSslSocket::atEnd
+168 (int (*)(...))QIODevice::reset
+176 (int (*)(...))QSslSocket::bytesAvailable
+184 (int (*)(...))QSslSocket::bytesToWrite
+192 (int (*)(...))QSslSocket::canReadLine
+200 (int (*)(...))QSslSocket::waitForReadyRead
+208 (int (*)(...))QSslSocket::waitForBytesWritten
+216 (int (*)(...))QSslSocket::readData
+224 (int (*)(...))QAbstractSocket::readLineData
+232 (int (*)(...))QSslSocket::writeData
+240 (int (*)(...))QSslSocket::resume
+248 (int (*)(...))QSslSocket::connectToHost
+256 (int (*)(...))QAbstractSocket::connectToHost
+264 (int (*)(...))QSslSocket::disconnectFromHost
+272 (int (*)(...))QSslSocket::setReadBufferSize
+280 (int (*)(...))QAbstractSocket::socketDescriptor
+288 (int (*)(...))QSslSocket::setSocketDescriptor
+296 (int (*)(...))QSslSocket::setSocketOption
+304 (int (*)(...))QSslSocket::socketOption
+312 (int (*)(...))QSslSocket::waitForConnected
+320 (int (*)(...))QSslSocket::waitForDisconnected
+
+Class QSslSocket
+ size=16 align=8
+ base size=16 base align=8
+QSslSocket (0x0x7f3bf5180888) 0
+ vptr=((& QSslSocket::_ZTV10QSslSocket) + 16)
+ QTcpSocket (0x0x7f3bf51808f0) 0
+ primary-for QSslSocket (0x0x7f3bf5180888)
+ QAbstractSocket (0x0x7f3bf5180958) 0
+ primary-for QTcpSocket (0x0x7f3bf51808f0)
+ QIODevice (0x0x7f3bf51809c0) 0
+ primary-for QAbstractSocket (0x0x7f3bf5180958)
+ QObject (0x0x7f3bf51911e0) 0
+ primary-for QIODevice (0x0x7f3bf51809c0)
+
+Class QDtlsClientVerifier::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QDtlsClientVerifier::QPrivateSignal (0x0x7f3bf5191480) 0 empty
+
+Class QDtlsClientVerifier::GeneratorParameters
+ size=16 align=8
+ base size=16 base align=8
+QDtlsClientVerifier::GeneratorParameters (0x0x7f3bf51914e0) 0
+
+Vtable for QDtlsClientVerifier
+QDtlsClientVerifier::_ZTV19QDtlsClientVerifier: 14 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI19QDtlsClientVerifier)
+16 (int (*)(...))QDtlsClientVerifier::metaObject
+24 (int (*)(...))QDtlsClientVerifier::qt_metacast
+32 (int (*)(...))QDtlsClientVerifier::qt_metacall
+40 (int (*)(...))QDtlsClientVerifier::~QDtlsClientVerifier
+48 (int (*)(...))QDtlsClientVerifier::~QDtlsClientVerifier
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+
+Class QDtlsClientVerifier
+ size=16 align=8
+ base size=16 base align=8
+QDtlsClientVerifier (0x0x7f3bf5180a28) 0
+ vptr=((& QDtlsClientVerifier::_ZTV19QDtlsClientVerifier) + 16)
+ QObject (0x0x7f3bf5191420) 0
+ primary-for QDtlsClientVerifier (0x0x7f3bf5180a28)
+
+Class QDtls::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QDtls::QPrivateSignal (0x0x7f3bf5191720) 0 empty
+
+Vtable for QDtls
+QDtls::_ZTV5QDtls: 14 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI5QDtls)
+16 (int (*)(...))QDtls::metaObject
+24 (int (*)(...))QDtls::qt_metacast
+32 (int (*)(...))QDtls::qt_metacall
+40 (int (*)(...))QDtls::~QDtls
+48 (int (*)(...))QDtls::~QDtls
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+
+Class QDtls
+ size=16 align=8
+ base size=16 base align=8
+QDtls (0x0x7f3bf5180a90) 0
+ vptr=((& QDtls::_ZTV5QDtls) + 16)
+ QObject (0x0x7f3bf51916c0) 0
+ primary-for QDtls (0x0x7f3bf5180a90)
+
+Class QIPv6Address
+ size=16 align=1
+ base size=16 base align=1
+QIPv6Address (0x0x7f3bf5191960) 0
+
+Class QHostAddress
+ size=8 align=8
+ base size=8 base align=8
+QHostAddress (0x0x7f3bf5191a80) 0
+
+Class QHostInfo
+ size=8 align=8
+ base size=8 base align=8
+QHostInfo (0x0x7f3bf5293840) 0
+
+Class QHstsPolicy
+ size=8 align=8
+ base size=8 base align=8
+QHstsPolicy (0x0x7f3bf4f55f00) 0
+
+Class QHttp2Configuration
+ size=8 align=8
+ base size=8 base align=8
+QHttp2Configuration (0x0x7f3bf5058660) 0
+
+Class QHttpPart
+ size=8 align=8
+ base size=8 base align=8
+QHttpPart (0x0x7f3bf50b0ba0) 0
+
+Class QHttpMultiPart::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QHttpMultiPart::QPrivateSignal (0x0x7f3bf4d79840) 0 empty
+
+Vtable for QHttpMultiPart
+QHttpMultiPart::_ZTV14QHttpMultiPart: 14 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI14QHttpMultiPart)
+16 (int (*)(...))QHttpMultiPart::metaObject
+24 (int (*)(...))QHttpMultiPart::qt_metacast
+32 (int (*)(...))QHttpMultiPart::qt_metacall
+40 (int (*)(...))QHttpMultiPart::~QHttpMultiPart
+48 (int (*)(...))QHttpMultiPart::~QHttpMultiPart
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+
+Class QHttpMultiPart
+ size=16 align=8
+ base size=16 base align=8
+QHttpMultiPart (0x0x7f3bf4d82208) 0
+ vptr=((& QHttpMultiPart::_ZTV14QHttpMultiPart) + 16)
+ QObject (0x0x7f3bf4d797e0) 0
+ primary-for QHttpMultiPart (0x0x7f3bf4d82208)
+
+Class QLocalServer::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QLocalServer::QPrivateSignal (0x0x7f3bf4d79a80) 0 empty
+
+Vtable for QLocalServer
+QLocalServer::_ZTV12QLocalServer: 17 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI12QLocalServer)
+16 (int (*)(...))QLocalServer::metaObject
+24 (int (*)(...))QLocalServer::qt_metacast
+32 (int (*)(...))QLocalServer::qt_metacall
+40 (int (*)(...))QLocalServer::~QLocalServer
+48 (int (*)(...))QLocalServer::~QLocalServer
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QLocalServer::hasPendingConnections
+120 (int (*)(...))QLocalServer::nextPendingConnection
+128 (int (*)(...))QLocalServer::incomingConnection
+
+Class QLocalServer
+ size=16 align=8
+ base size=16 base align=8
+QLocalServer (0x0x7f3bf4d82270) 0
+ vptr=((& QLocalServer::_ZTV12QLocalServer) + 16)
+ QObject (0x0x7f3bf4d79a20) 0
+ primary-for QLocalServer (0x0x7f3bf4d82270)
+
+Class QLocalSocket::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QLocalSocket::QPrivateSignal (0x0x7f3bf4dc7540) 0 empty
+
+Vtable for QLocalSocket
+QLocalSocket::_ZTV12QLocalSocket: 30 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI12QLocalSocket)
+16 (int (*)(...))QLocalSocket::metaObject
+24 (int (*)(...))QLocalSocket::qt_metacast
+32 (int (*)(...))QLocalSocket::qt_metacall
+40 (int (*)(...))QLocalSocket::~QLocalSocket
+48 (int (*)(...))QLocalSocket::~QLocalSocket
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QLocalSocket::isSequential
+120 (int (*)(...))QLocalSocket::open
+128 (int (*)(...))QLocalSocket::close
+136 (int (*)(...))QIODevice::pos
+144 (int (*)(...))QIODevice::size
+152 (int (*)(...))QIODevice::seek
+160 (int (*)(...))QIODevice::atEnd
+168 (int (*)(...))QIODevice::reset
+176 (int (*)(...))QLocalSocket::bytesAvailable
+184 (int (*)(...))QLocalSocket::bytesToWrite
+192 (int (*)(...))QLocalSocket::canReadLine
+200 (int (*)(...))QLocalSocket::waitForReadyRead
+208 (int (*)(...))QLocalSocket::waitForBytesWritten
+216 (int (*)(...))QLocalSocket::readData
+224 (int (*)(...))QIODevice::readLineData
+232 (int (*)(...))QLocalSocket::writeData
+
+Class QLocalSocket
+ size=16 align=8
+ base size=16 base align=8
+QLocalSocket (0x0x7f3bf4d82410) 0
+ vptr=((& QLocalSocket::_ZTV12QLocalSocket) + 16)
+ QIODevice (0x0x7f3bf4d82478) 0
+ primary-for QLocalSocket (0x0x7f3bf4d82410)
+ QObject (0x0x7f3bf4dc74e0) 0
+ primary-for QIODevice (0x0x7f3bf4d82478)
+
+Class QSslConfiguration
+ size=8 align=8
+ base size=8 base align=8
+QSslConfiguration (0x0x7f3bf4dc7720) 0
+
+Class QSslPreSharedKeyAuthenticator
+ size=8 align=8
+ base size=8 base align=8
+QSslPreSharedKeyAuthenticator (0x0x7f3bf4ed2c00) 0
+
+Class QNetworkAccessManager::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QNetworkAccessManager::QPrivateSignal (0x0x7f3bf4bbf2a0) 0 empty
+
+Vtable for QNetworkAccessManager
+QNetworkAccessManager::_ZTV21QNetworkAccessManager: 15 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI21QNetworkAccessManager)
+16 (int (*)(...))QNetworkAccessManager::metaObject
+24 (int (*)(...))QNetworkAccessManager::qt_metacast
+32 (int (*)(...))QNetworkAccessManager::qt_metacall
+40 (int (*)(...))QNetworkAccessManager::~QNetworkAccessManager
+48 (int (*)(...))QNetworkAccessManager::~QNetworkAccessManager
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QNetworkAccessManager::createRequest
+
+Class QNetworkAccessManager
+ size=16 align=8
+ base size=16 base align=8
+QNetworkAccessManager (0x0x7f3bf4bab958) 0
+ vptr=((& QNetworkAccessManager::_ZTV21QNetworkAccessManager) + 16)
+ QObject (0x0x7f3bf4bbf240) 0
+ primary-for QNetworkAccessManager (0x0x7f3bf4bab958)
+
+Class QNetworkConfiguration
+ size=8 align=8
+ base size=8 base align=8
+QNetworkConfiguration (0x0x7f3bf4bbf540) 0
+
+Class QNetworkConfigurationManager::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QNetworkConfigurationManager::QPrivateSignal (0x0x7f3bf4ca6900) 0 empty
+
+Vtable for QNetworkConfigurationManager
+QNetworkConfigurationManager::_ZTV28QNetworkConfigurationManager: 14 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI28QNetworkConfigurationManager)
+16 (int (*)(...))QNetworkConfigurationManager::metaObject
+24 (int (*)(...))QNetworkConfigurationManager::qt_metacast
+32 (int (*)(...))QNetworkConfigurationManager::qt_metacall
+40 (int (*)(...))QNetworkConfigurationManager::~QNetworkConfigurationManager
+48 (int (*)(...))QNetworkConfigurationManager::~QNetworkConfigurationManager
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+
+Class QNetworkConfigurationManager
+ size=16 align=8
+ base size=16 base align=8
+QNetworkConfigurationManager (0x0x7f3bf4c96c30) 0
+ vptr=((& QNetworkConfigurationManager::_ZTV28QNetworkConfigurationManager) + 16)
+ QObject (0x0x7f3bf4ca68a0) 0
+ primary-for QNetworkConfigurationManager (0x0x7f3bf4c96c30)
+
+Class QNetworkCookie
+ size=8 align=8
+ base size=8 base align=8
+QNetworkCookie (0x0x7f3bf4cf9480) 0
+
+Class QNetworkCookieJar::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QNetworkCookieJar::QPrivateSignal (0x0x7f3bf49c8a80) 0 empty
+
+Vtable for QNetworkCookieJar
+QNetworkCookieJar::_ZTV17QNetworkCookieJar: 20 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI17QNetworkCookieJar)
+16 (int (*)(...))QNetworkCookieJar::metaObject
+24 (int (*)(...))QNetworkCookieJar::qt_metacast
+32 (int (*)(...))QNetworkCookieJar::qt_metacall
+40 (int (*)(...))QNetworkCookieJar::~QNetworkCookieJar
+48 (int (*)(...))QNetworkCookieJar::~QNetworkCookieJar
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QNetworkCookieJar::cookiesForUrl
+120 (int (*)(...))QNetworkCookieJar::setCookiesFromUrl
+128 (int (*)(...))QNetworkCookieJar::insertCookie
+136 (int (*)(...))QNetworkCookieJar::updateCookie
+144 (int (*)(...))QNetworkCookieJar::deleteCookie
+152 (int (*)(...))QNetworkCookieJar::validateCookie
+
+Class QNetworkCookieJar
+ size=16 align=8
+ base size=16 base align=8
+QNetworkCookieJar (0x0x7f3bf49bbea0) 0
+ vptr=((& QNetworkCookieJar::_ZTV17QNetworkCookieJar) + 16)
+ QObject (0x0x7f3bf49c8a20) 0
+ primary-for QNetworkCookieJar (0x0x7f3bf49bbea0)
+
+Class QNetworkDatagram
+ size=8 align=8
+ base size=8 base align=8
+QNetworkDatagram (0x0x7f3bf49c8c60) 0
+
+Class QNetworkDiskCache::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QNetworkDiskCache::QPrivateSignal (0x0x7f3bf4aa27e0) 0 empty
+
+Vtable for QNetworkDiskCache
+QNetworkDiskCache::_ZTV17QNetworkDiskCache: 23 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI17QNetworkDiskCache)
+16 (int (*)(...))QNetworkDiskCache::metaObject
+24 (int (*)(...))QNetworkDiskCache::qt_metacast
+32 (int (*)(...))QNetworkDiskCache::qt_metacall
+40 (int (*)(...))QNetworkDiskCache::~QNetworkDiskCache
+48 (int (*)(...))QNetworkDiskCache::~QNetworkDiskCache
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QNetworkDiskCache::metaData
+120 (int (*)(...))QNetworkDiskCache::updateMetaData
+128 (int (*)(...))QNetworkDiskCache::data
+136 (int (*)(...))QNetworkDiskCache::remove
+144 (int (*)(...))QNetworkDiskCache::cacheSize
+152 (int (*)(...))QNetworkDiskCache::prepare
+160 (int (*)(...))QNetworkDiskCache::insert
+168 (int (*)(...))QNetworkDiskCache::clear
+176 (int (*)(...))QNetworkDiskCache::expire
+
+Class QNetworkDiskCache
+ size=16 align=8
+ base size=16 base align=8
+QNetworkDiskCache (0x0x7f3bf4a95d68) 0
+ vptr=((& QNetworkDiskCache::_ZTV17QNetworkDiskCache) + 16)
+ QAbstractNetworkCache (0x0x7f3bf4a95dd0) 0
+ primary-for QNetworkDiskCache (0x0x7f3bf4a95d68)
+ QObject (0x0x7f3bf4aa2780) 0
+ primary-for QAbstractNetworkCache (0x0x7f3bf4a95dd0)
+
+Class QNetworkAddressEntry
+ size=8 align=8
+ base size=8 base align=8
+QNetworkAddressEntry (0x0x7f3bf4aa29c0) 0
+
+Class QNetworkInterface
+ size=8 align=8
+ base size=8 base align=8
+QNetworkInterface (0x0x7f3bf477b960) 0
+
+Class QNetworkProxyQuery
+ size=8 align=8
+ base size=8 base align=8
+QNetworkProxyQuery (0x0x7f3bf4878480) 0
+
+Class QNetworkProxy
+ size=8 align=8
+ base size=8 base align=8
+QNetworkProxy (0x0x7f3bf4555780) 0
+
+Vtable for QNetworkProxyFactory
+QNetworkProxyFactory::_ZTV20QNetworkProxyFactory: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI20QNetworkProxyFactory)
+16 0
+24 0
+32 (int (*)(...))__cxa_pure_virtual
+
+Class QNetworkProxyFactory
+ size=8 align=8
+ base size=8 base align=8
+QNetworkProxyFactory (0x0x7f3bf4660000) 0 nearly-empty
+ vptr=((& QNetworkProxyFactory::_ZTV20QNetworkProxyFactory) + 16)
+
+Class QNetworkReply::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QNetworkReply::QPrivateSignal (0x0x7f3bf46602a0) 0 empty
+
+Vtable for QNetworkReply
+QNetworkReply::_ZTV13QNetworkReply: 36 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI13QNetworkReply)
+16 (int (*)(...))QNetworkReply::metaObject
+24 (int (*)(...))QNetworkReply::qt_metacast
+32 (int (*)(...))QNetworkReply::qt_metacall
+40 0
+48 0
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QNetworkReply::isSequential
+120 (int (*)(...))QIODevice::open
+128 (int (*)(...))QNetworkReply::close
+136 (int (*)(...))QIODevice::pos
+144 (int (*)(...))QIODevice::size
+152 (int (*)(...))QIODevice::seek
+160 (int (*)(...))QIODevice::atEnd
+168 (int (*)(...))QIODevice::reset
+176 (int (*)(...))QIODevice::bytesAvailable
+184 (int (*)(...))QIODevice::bytesToWrite
+192 (int (*)(...))QIODevice::canReadLine
+200 (int (*)(...))QIODevice::waitForReadyRead
+208 (int (*)(...))QIODevice::waitForBytesWritten
+216 (int (*)(...))__cxa_pure_virtual
+224 (int (*)(...))QIODevice::readLineData
+232 (int (*)(...))QNetworkReply::writeData
+240 (int (*)(...))QNetworkReply::setReadBufferSize
+248 (int (*)(...))__cxa_pure_virtual
+256 (int (*)(...))QNetworkReply::ignoreSslErrors
+264 (int (*)(...))QNetworkReply::sslConfigurationImplementation
+272 (int (*)(...))QNetworkReply::setSslConfigurationImplementation
+280 (int (*)(...))QNetworkReply::ignoreSslErrorsImplementation
+
+Class QNetworkReply
+ size=16 align=8
+ base size=16 base align=8
+QNetworkReply (0x0x7f3bf4630208) 0
+ vptr=((& QNetworkReply::_ZTV13QNetworkReply) + 16)
+ QIODevice (0x0x7f3bf4630270) 0
+ primary-for QNetworkReply (0x0x7f3bf4630208)
+ QObject (0x0x7f3bf4660240) 0
+ primary-for QIODevice (0x0x7f3bf4630270)
+
+Class QNetworkSession::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QNetworkSession::QPrivateSignal (0x0x7f3bf4660780) 0 empty
+
+Vtable for QNetworkSession
+QNetworkSession::_ZTV15QNetworkSession: 14 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI15QNetworkSession)
+16 (int (*)(...))QNetworkSession::metaObject
+24 (int (*)(...))QNetworkSession::qt_metacast
+32 (int (*)(...))QNetworkSession::qt_metacall
+40 (int (*)(...))QNetworkSession::~QNetworkSession
+48 (int (*)(...))QNetworkSession::~QNetworkSession
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QNetworkSession::connectNotify
+104 (int (*)(...))QNetworkSession::disconnectNotify
+
+Class QNetworkSession
+ size=24 align=8
+ base size=24 base align=8
+QNetworkSession (0x0x7f3bf46302d8) 0
+ vptr=((& QNetworkSession::_ZTV15QNetworkSession) + 16)
+ QObject (0x0x7f3bf4660720) 0
+ primary-for QNetworkSession (0x0x7f3bf46302d8)
+
+Class QOcspResponse
+ size=8 align=8
+ base size=8 base align=8
+QOcspResponse (0x0x7f3bf46c9000) 0
+
+Class QTcpServer::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QTcpServer::QPrivateSignal (0x0x7f3bf4319840) 0 empty
+
+Vtable for QTcpServer
+QTcpServer::_ZTV10QTcpServer: 17 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI10QTcpServer)
+16 (int (*)(...))QTcpServer::metaObject
+24 (int (*)(...))QTcpServer::qt_metacast
+32 (int (*)(...))QTcpServer::qt_metacall
+40 (int (*)(...))QTcpServer::~QTcpServer
+48 (int (*)(...))QTcpServer::~QTcpServer
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QTcpServer::hasPendingConnections
+120 (int (*)(...))QTcpServer::nextPendingConnection
+128 (int (*)(...))QTcpServer::incomingConnection
+
+Class QTcpServer
+ size=16 align=8
+ base size=16 base align=8
+QTcpServer (0x0x7f3bf430cb60) 0
+ vptr=((& QTcpServer::_ZTV10QTcpServer) + 16)
+ QObject (0x0x7f3bf43197e0) 0
+ primary-for QTcpServer (0x0x7f3bf430cb60)
+
+Class QSslCertificateExtension
+ size=8 align=8
+ base size=8 base align=8
+QSslCertificateExtension (0x0x7f3bf4319a20) 0
+
+Class QSslCipher
+ size=8 align=8
+ base size=8 base align=8
+QSslCipher (0x0x7f3bf43ea9c0) 0
+
+Class QSslDiffieHellmanParameters
+ size=8 align=8
+ base size=8 base align=8
+QSslDiffieHellmanParameters (0x0x7f3bf44afa80) 0
+
+Class QSslEllipticCurve
+ size=4 align=4
+ base size=4 base align=4
+QSslEllipticCurve (0x0x7f3bf41737e0) 0
+
+Class QSslKey
+ size=8 align=8
+ base size=8 base align=8
+QSslKey (0x0x7f3bf41da180) 0
+
+Class QUdpSocket::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QUdpSocket::QPrivateSignal (0x0x7f3bf42a9060) 0 empty
+
+Vtable for QUdpSocket
+QUdpSocket::_ZTV10QUdpSocket: 41 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI10QUdpSocket)
+16 (int (*)(...))QUdpSocket::metaObject
+24 (int (*)(...))QUdpSocket::qt_metacast
+32 (int (*)(...))QUdpSocket::qt_metacall
+40 (int (*)(...))QUdpSocket::~QUdpSocket
+48 (int (*)(...))QUdpSocket::~QUdpSocket
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QAbstractSocket::isSequential
+120 (int (*)(...))QIODevice::open
+128 (int (*)(...))QAbstractSocket::close
+136 (int (*)(...))QIODevice::pos
+144 (int (*)(...))QIODevice::size
+152 (int (*)(...))QIODevice::seek
+160 (int (*)(...))QAbstractSocket::atEnd
+168 (int (*)(...))QIODevice::reset
+176 (int (*)(...))QAbstractSocket::bytesAvailable
+184 (int (*)(...))QAbstractSocket::bytesToWrite
+192 (int (*)(...))QAbstractSocket::canReadLine
+200 (int (*)(...))QAbstractSocket::waitForReadyRead
+208 (int (*)(...))QAbstractSocket::waitForBytesWritten
+216 (int (*)(...))QAbstractSocket::readData
+224 (int (*)(...))QAbstractSocket::readLineData
+232 (int (*)(...))QAbstractSocket::writeData
+240 (int (*)(...))QAbstractSocket::resume
+248 (int (*)(...))QAbstractSocket::connectToHost
+256 (int (*)(...))QAbstractSocket::connectToHost
+264 (int (*)(...))QAbstractSocket::disconnectFromHost
+272 (int (*)(...))QAbstractSocket::setReadBufferSize
+280 (int (*)(...))QAbstractSocket::socketDescriptor
+288 (int (*)(...))QAbstractSocket::setSocketDescriptor
+296 (int (*)(...))QAbstractSocket::setSocketOption
+304 (int (*)(...))QAbstractSocket::socketOption
+312 (int (*)(...))QAbstractSocket::waitForConnected
+320 (int (*)(...))QAbstractSocket::waitForDisconnected
+
+Class QUdpSocket
+ size=16 align=8
+ base size=16 base align=8
+QUdpSocket (0x0x7f3bf42a4138) 0
+ vptr=((& QUdpSocket::_ZTV10QUdpSocket) + 16)
+ QAbstractSocket (0x0x7f3bf42a41a0) 0
+ primary-for QUdpSocket (0x0x7f3bf42a4138)
+ QIODevice (0x0x7f3bf42a4208) 0
+ primary-for QAbstractSocket (0x0x7f3bf42a41a0)
+ QObject (0x0x7f3bf42a9000) 0
+ primary-for QIODevice (0x0x7f3bf42a4208)
+
+Class QRemoteObjectSourceLocationInfo
+ size=16 align=8
+ base size=16 base align=8
+QRemoteObjectSourceLocationInfo (0x0x7f3bf42a92a0) 0
+
+Class QAbstractItemModelReplica::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QAbstractItemModelReplica::QPrivateSignal (0x0x7f3bf3fa9180) 0 empty
+
+Vtable for QAbstractItemModelReplica
+QAbstractItemModelReplica::_ZTV25QAbstractItemModelReplica: 48 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI25QAbstractItemModelReplica)
+16 (int (*)(...))QAbstractItemModelReplica::metaObject
+24 (int (*)(...))QAbstractItemModelReplica::qt_metacast
+32 (int (*)(...))QAbstractItemModelReplica::qt_metacall
+40 (int (*)(...))QAbstractItemModelReplica::~QAbstractItemModelReplica
+48 (int (*)(...))QAbstractItemModelReplica::~QAbstractItemModelReplica
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QAbstractItemModelReplica::index
+120 (int (*)(...))QAbstractItemModelReplica::parent
+128 (int (*)(...))QAbstractItemModel::sibling
+136 (int (*)(...))QAbstractItemModelReplica::rowCount
+144 (int (*)(...))QAbstractItemModelReplica::columnCount
+152 (int (*)(...))QAbstractItemModelReplica::hasChildren
+160 (int (*)(...))QAbstractItemModelReplica::data
+168 (int (*)(...))QAbstractItemModelReplica::setData
+176 (int (*)(...))QAbstractItemModelReplica::headerData
+184 (int (*)(...))QAbstractItemModel::setHeaderData
+192 (int (*)(...))QAbstractItemModel::itemData
+200 (int (*)(...))QAbstractItemModel::setItemData
+208 (int (*)(...))QAbstractItemModel::mimeTypes
+216 (int (*)(...))QAbstractItemModel::mimeData
+224 (int (*)(...))QAbstractItemModel::canDropMimeData
+232 (int (*)(...))QAbstractItemModel::dropMimeData
+240 (int (*)(...))QAbstractItemModel::supportedDropActions
+248 (int (*)(...))QAbstractItemModel::supportedDragActions
+256 (int (*)(...))QAbstractItemModel::insertRows
+264 (int (*)(...))QAbstractItemModel::insertColumns
+272 (int (*)(...))QAbstractItemModel::removeRows
+280 (int (*)(...))QAbstractItemModel::removeColumns
+288 (int (*)(...))QAbstractItemModel::moveRows
+296 (int (*)(...))QAbstractItemModel::moveColumns
+304 (int (*)(...))QAbstractItemModel::fetchMore
+312 (int (*)(...))QAbstractItemModel::canFetchMore
+320 (int (*)(...))QAbstractItemModelReplica::flags
+328 (int (*)(...))QAbstractItemModel::sort
+336 (int (*)(...))QAbstractItemModel::buddy
+344 (int (*)(...))QAbstractItemModel::match
+352 (int (*)(...))QAbstractItemModel::span
+360 (int (*)(...))QAbstractItemModelReplica::roleNames
+368 (int (*)(...))QAbstractItemModel::submit
+376 (int (*)(...))QAbstractItemModel::revert
+
+Class QAbstractItemModelReplica
+ size=24 align=8
+ base size=24 base align=8
+QAbstractItemModelReplica (0x0x7f3bf42e5958) 0
+ vptr=((& QAbstractItemModelReplica::_ZTV25QAbstractItemModelReplica) + 16)
+ QAbstractItemModel (0x0x7f3bf42e59c0) 0
+ primary-for QAbstractItemModelReplica (0x0x7f3bf42e5958)
+ QObject (0x0x7f3bf3fa9120) 0
+ primary-for QAbstractItemModel (0x0x7f3bf42e59c0)
+
+Class ModelIndex
+ size=8 align=4
+ base size=8 base align=4
+ModelIndex (0x0x7f3bf3fa9300) 0
+
+Class IndexValuePair
+ size=40 align=8
+ base size=40 base align=8
+IndexValuePair (0x0x7f3bf3fa9ba0) 0
+
+Class DataEntries
+ size=8 align=8
+ base size=8 base align=8
+DataEntries (0x0x7f3bf4070420) 0
+
+Class MetaAndDataEntries
+ size=24 align=8
+ base size=24 base align=8
+MetaAndDataEntries (0x0x7f3bf4073dd0) 0
+ DataEntries (0x0x7f3bf4070e40) 0
+
+Class QRemoteObjectReplica::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QRemoteObjectReplica::QPrivateSignal (0x0x7f3bf3da21e0) 0 empty
+
+Vtable for QRemoteObjectReplica
+QRemoteObjectReplica::_ZTV20QRemoteObjectReplica: 16 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI20QRemoteObjectReplica)
+16 (int (*)(...))QRemoteObjectReplica::metaObject
+24 (int (*)(...))QRemoteObjectReplica::qt_metacast
+32 (int (*)(...))QRemoteObjectReplica::qt_metacall
+40 (int (*)(...))QRemoteObjectReplica::~QRemoteObjectReplica
+48 (int (*)(...))QRemoteObjectReplica::~QRemoteObjectReplica
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QRemoteObjectReplica::setNode
+120 (int (*)(...))QRemoteObjectReplica::initialize
+
+Class QRemoteObjectReplica
+ size=32 align=8
+ base size=32 base align=8
+QRemoteObjectReplica (0x0x7f3bf3d5f068) 0
+ vptr=((& QRemoteObjectReplica::_ZTV20QRemoteObjectReplica) + 16)
+ QObject (0x0x7f3bf3da2180) 0
+ primary-for QRemoteObjectReplica (0x0x7f3bf3d5f068)
+
+Vtable for QRemoteObjectDynamicReplica
+QRemoteObjectDynamicReplica::_ZTV27QRemoteObjectDynamicReplica: 16 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI27QRemoteObjectDynamicReplica)
+16 (int (*)(...))QRemoteObjectDynamicReplica::metaObject
+24 (int (*)(...))QRemoteObjectDynamicReplica::qt_metacast
+32 (int (*)(...))QRemoteObjectDynamicReplica::qt_metacall
+40 (int (*)(...))QRemoteObjectDynamicReplica::~QRemoteObjectDynamicReplica
+48 (int (*)(...))QRemoteObjectDynamicReplica::~QRemoteObjectDynamicReplica
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QRemoteObjectReplica::setNode
+120 (int (*)(...))QRemoteObjectReplica::initialize
+
+Class QRemoteObjectDynamicReplica
+ size=32 align=8
+ base size=32 base align=8
+QRemoteObjectDynamicReplica (0x0x7f3bf3d5f0d0) 0
+ vptr=((& QRemoteObjectDynamicReplica::_ZTV27QRemoteObjectDynamicReplica) + 16)
+ QRemoteObjectReplica (0x0x7f3bf3d5f138) 0
+ primary-for QRemoteObjectDynamicReplica (0x0x7f3bf3d5f0d0)
+ QObject (0x0x7f3bf3da2420) 0
+ primary-for QRemoteObjectReplica (0x0x7f3bf3d5f138)
+
+Class QRemoteObjectRegistry::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QRemoteObjectRegistry::QPrivateSignal (0x0x7f3bf3da24e0) 0 empty
+
+Vtable for QRemoteObjectRegistry
+QRemoteObjectRegistry::_ZTV21QRemoteObjectRegistry: 16 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI21QRemoteObjectRegistry)
+16 (int (*)(...))QRemoteObjectRegistry::metaObject
+24 (int (*)(...))QRemoteObjectRegistry::qt_metacast
+32 (int (*)(...))QRemoteObjectRegistry::qt_metacall
+40 (int (*)(...))QRemoteObjectRegistry::~QRemoteObjectRegistry
+48 (int (*)(...))QRemoteObjectRegistry::~QRemoteObjectRegistry
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QRemoteObjectReplica::setNode
+120 (int (*)(...))QRemoteObjectRegistry::initialize
+
+Class QRemoteObjectRegistry
+ size=32 align=8
+ base size=32 base align=8
+QRemoteObjectRegistry (0x0x7f3bf3d5f1a0) 0
+ vptr=((& QRemoteObjectRegistry::_ZTV21QRemoteObjectRegistry) + 16)
+ QRemoteObjectReplica (0x0x7f3bf3d5f208) 0
+ primary-for QRemoteObjectRegistry (0x0x7f3bf3d5f1a0)
+ QObject (0x0x7f3bf3da2480) 0
+ primary-for QRemoteObjectReplica (0x0x7f3bf3d5f208)
+
+Class QRemoteObjectAbstractPersistedStore::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QRemoteObjectAbstractPersistedStore::QPrivateSignal (0x0x7f3bf3da2720) 0 empty
+
+Vtable for QRemoteObjectAbstractPersistedStore
+QRemoteObjectAbstractPersistedStore::_ZTV35QRemoteObjectAbstractPersistedStore: 16 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI35QRemoteObjectAbstractPersistedStore)
+16 (int (*)(...))QRemoteObjectAbstractPersistedStore::metaObject
+24 (int (*)(...))QRemoteObjectAbstractPersistedStore::qt_metacast
+32 (int (*)(...))QRemoteObjectAbstractPersistedStore::qt_metacall
+40 0
+48 0
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))__cxa_pure_virtual
+120 (int (*)(...))__cxa_pure_virtual
+
+Class QRemoteObjectAbstractPersistedStore
+ size=16 align=8
+ base size=16 base align=8
+QRemoteObjectAbstractPersistedStore (0x0x7f3bf3d5f270) 0
+ vptr=((& QRemoteObjectAbstractPersistedStore::_ZTV35QRemoteObjectAbstractPersistedStore) + 16)
+ QObject (0x0x7f3bf3da26c0) 0
+ primary-for QRemoteObjectAbstractPersistedStore (0x0x7f3bf3d5f270)
+
+Class QRemoteObjectNode::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QRemoteObjectNode::QPrivateSignal (0x0x7f3bf3da29c0) 0 empty
+
+Vtable for QRemoteObjectNode
+QRemoteObjectNode::_ZTV17QRemoteObjectNode: 16 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI17QRemoteObjectNode)
+16 (int (*)(...))QRemoteObjectNode::metaObject
+24 (int (*)(...))QRemoteObjectNode::qt_metacast
+32 (int (*)(...))QRemoteObjectNode::qt_metacall
+40 (int (*)(...))QRemoteObjectNode::~QRemoteObjectNode
+48 (int (*)(...))QRemoteObjectNode::~QRemoteObjectNode
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QRemoteObjectNode::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QRemoteObjectNode::setName
+120 (int (*)(...))QRemoteObjectNode::setRegistryUrl
+
+Class QRemoteObjectNode
+ size=16 align=8
+ base size=16 base align=8
+QRemoteObjectNode (0x0x7f3bf3d5f2d8) 0
+ vptr=((& QRemoteObjectNode::_ZTV17QRemoteObjectNode) + 16)
+ QObject (0x0x7f3bf3da2960) 0
+ primary-for QRemoteObjectNode (0x0x7f3bf3d5f2d8)
+
+Class QRemoteObjectHostBase::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QRemoteObjectHostBase::QPrivateSignal (0x0x7f3bf3da2d80) 0 empty
+
+Vtable for QRemoteObjectHostBase
+QRemoteObjectHostBase::_ZTV21QRemoteObjectHostBase: 18 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI21QRemoteObjectHostBase)
+16 (int (*)(...))QRemoteObjectHostBase::metaObject
+24 (int (*)(...))QRemoteObjectHostBase::qt_metacast
+32 (int (*)(...))QRemoteObjectHostBase::qt_metacall
+40 (int (*)(...))QRemoteObjectHostBase::~QRemoteObjectHostBase
+48 (int (*)(...))QRemoteObjectHostBase::~QRemoteObjectHostBase
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QRemoteObjectNode::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QRemoteObjectHostBase::setName
+120 (int (*)(...))QRemoteObjectNode::setRegistryUrl
+128 (int (*)(...))QRemoteObjectHostBase::hostUrl
+136 (int (*)(...))QRemoteObjectHostBase::setHostUrl
+
+Class QRemoteObjectHostBase
+ size=16 align=8
+ base size=16 base align=8
+QRemoteObjectHostBase (0x0x7f3bf3d5f340) 0
+ vptr=((& QRemoteObjectHostBase::_ZTV21QRemoteObjectHostBase) + 16)
+ QRemoteObjectNode (0x0x7f3bf3d5f3a8) 0
+ primary-for QRemoteObjectHostBase (0x0x7f3bf3d5f340)
+ QObject (0x0x7f3bf3da2d20) 0
+ primary-for QRemoteObjectNode (0x0x7f3bf3d5f3a8)
+
+Class QRemoteObjectHost::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QRemoteObjectHost::QPrivateSignal (0x0x7f3bf3eba000) 0 empty
+
+Vtable for QRemoteObjectHost
+QRemoteObjectHost::_ZTV17QRemoteObjectHost: 18 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI17QRemoteObjectHost)
+16 (int (*)(...))QRemoteObjectHost::metaObject
+24 (int (*)(...))QRemoteObjectHost::qt_metacast
+32 (int (*)(...))QRemoteObjectHost::qt_metacall
+40 (int (*)(...))QRemoteObjectHost::~QRemoteObjectHost
+48 (int (*)(...))QRemoteObjectHost::~QRemoteObjectHost
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QRemoteObjectNode::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QRemoteObjectHostBase::setName
+120 (int (*)(...))QRemoteObjectNode::setRegistryUrl
+128 (int (*)(...))QRemoteObjectHost::hostUrl
+136 (int (*)(...))QRemoteObjectHost::setHostUrl
+
+Class QRemoteObjectHost
+ size=16 align=8
+ base size=16 base align=8
+QRemoteObjectHost (0x0x7f3bf3e95c30) 0
+ vptr=((& QRemoteObjectHost::_ZTV17QRemoteObjectHost) + 16)
+ QRemoteObjectHostBase (0x0x7f3bf3e95c98) 0
+ primary-for QRemoteObjectHost (0x0x7f3bf3e95c30)
+ QRemoteObjectNode (0x0x7f3bf3e95d00) 0
+ primary-for QRemoteObjectHostBase (0x0x7f3bf3e95c98)
+ QObject (0x0x7f3bf3e91f60) 0
+ primary-for QRemoteObjectNode (0x0x7f3bf3e95d00)
+
+Class QRemoteObjectRegistryHost::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QRemoteObjectRegistryHost::QPrivateSignal (0x0x7f3bf3eba240) 0 empty
+
+Vtable for QRemoteObjectRegistryHost
+QRemoteObjectRegistryHost::_ZTV25QRemoteObjectRegistryHost: 18 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI25QRemoteObjectRegistryHost)
+16 (int (*)(...))QRemoteObjectRegistryHost::metaObject
+24 (int (*)(...))QRemoteObjectRegistryHost::qt_metacast
+32 (int (*)(...))QRemoteObjectRegistryHost::qt_metacall
+40 (int (*)(...))QRemoteObjectRegistryHost::~QRemoteObjectRegistryHost
+48 (int (*)(...))QRemoteObjectRegistryHost::~QRemoteObjectRegistryHost
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QRemoteObjectNode::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QRemoteObjectHostBase::setName
+120 (int (*)(...))QRemoteObjectRegistryHost::setRegistryUrl
+128 (int (*)(...))QRemoteObjectHostBase::hostUrl
+136 (int (*)(...))QRemoteObjectHostBase::setHostUrl
+
+Class QRemoteObjectRegistryHost
+ size=16 align=8
+ base size=16 base align=8
+QRemoteObjectRegistryHost (0x0x7f3bf3e95d68) 0
+ vptr=((& QRemoteObjectRegistryHost::_ZTV25QRemoteObjectRegistryHost) + 16)
+ QRemoteObjectHostBase (0x0x7f3bf3e95dd0) 0
+ primary-for QRemoteObjectRegistryHost (0x0x7f3bf3e95d68)
+ QRemoteObjectNode (0x0x7f3bf3e95e38) 0
+ primary-for QRemoteObjectHostBase (0x0x7f3bf3e95dd0)
+ QObject (0x0x7f3bf3eba1e0) 0
+ primary-for QRemoteObjectNode (0x0x7f3bf3e95e38)
+
+Class QRemoteObjectPendingCall
+ size=8 align=8
+ base size=8 base align=8
+QRemoteObjectPendingCall (0x0x7f3bf3eba420) 0
+
+Class QRemoteObjectPendingCallWatcher::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QRemoteObjectPendingCallWatcher::QPrivateSignal (0x0x7f3bf3eba780) 0 empty
+
+Vtable for QRemoteObjectPendingCallWatcher
+QRemoteObjectPendingCallWatcher::_ZTV31QRemoteObjectPendingCallWatcher: 14 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI31QRemoteObjectPendingCallWatcher)
+16 (int (*)(...))QRemoteObjectPendingCallWatcher::metaObject
+24 (int (*)(...))QRemoteObjectPendingCallWatcher::qt_metacast
+32 (int (*)(...))QRemoteObjectPendingCallWatcher::qt_metacall
+40 (int (*)(...))QRemoteObjectPendingCallWatcher::~QRemoteObjectPendingCallWatcher
+48 (int (*)(...))QRemoteObjectPendingCallWatcher::~QRemoteObjectPendingCallWatcher
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+
+Class QRemoteObjectPendingCallWatcher
+ size=24 align=8
+ base size=24 base align=8
+QRemoteObjectPendingCallWatcher (0x0x7f3bf3ee53f0) 0
+ vptr=((& QRemoteObjectPendingCallWatcher::_ZTV31QRemoteObjectPendingCallWatcher) + 16)
+ QObject (0x0x7f3bf3eba6c0) 0
+ primary-for QRemoteObjectPendingCallWatcher (0x0x7f3bf3ee53f0)
+ QRemoteObjectPendingCall (0x0x7f3bf3eba720) 16
+
+Class QRemoteObjectSettingsStore::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QRemoteObjectSettingsStore::QPrivateSignal (0x0x7f3bf3ebac60) 0 empty
+
+Vtable for QRemoteObjectSettingsStore
+QRemoteObjectSettingsStore::_ZTV26QRemoteObjectSettingsStore: 16 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI26QRemoteObjectSettingsStore)
+16 (int (*)(...))QRemoteObjectSettingsStore::metaObject
+24 (int (*)(...))QRemoteObjectSettingsStore::qt_metacast
+32 (int (*)(...))QRemoteObjectSettingsStore::qt_metacall
+40 (int (*)(...))QRemoteObjectSettingsStore::~QRemoteObjectSettingsStore
+48 (int (*)(...))QRemoteObjectSettingsStore::~QRemoteObjectSettingsStore
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QRemoteObjectSettingsStore::saveProperties
+120 (int (*)(...))QRemoteObjectSettingsStore::restoreProperties
+
+Class QRemoteObjectSettingsStore
+ size=16 align=8
+ base size=16 base align=8
+QRemoteObjectSettingsStore (0x0x7f3bf3ef70d0) 0
+ vptr=((& QRemoteObjectSettingsStore::_ZTV26QRemoteObjectSettingsStore) + 16)
+ QRemoteObjectAbstractPersistedStore (0x0x7f3bf3ef7138) 0
+ primary-for QRemoteObjectSettingsStore (0x0x7f3bf3ef70d0)
+ QObject (0x0x7f3bf3ebac00) 0
+ primary-for QRemoteObjectAbstractPersistedStore (0x0x7f3bf3ef7138)
+
+Class QtPrivate::QMetaObjectPrivate
+ size=56 align=4
+ base size=56 base align=4
+QtPrivate::QMetaObjectPrivate (0x0x7f3bf3b311e0) 0
+
+Class ModelInfo
+ size=24 align=8
+ base size=24 base align=8
+ModelInfo (0x0x7f3bf3b31ea0) 0
+
+Vtable for SourceApiMap
+SourceApiMap::_ZTV12SourceApiMap: 32 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI12SourceApiMap)
+16 0
+24 0
+32 (int (*)(...))__cxa_pure_virtual
+40 (int (*)(...))__cxa_pure_virtual
+48 (int (*)(...))SourceApiMap::className
+56 (int (*)(...))__cxa_pure_virtual
+64 (int (*)(...))__cxa_pure_virtual
+72 (int (*)(...))__cxa_pure_virtual
+80 (int (*)(...))__cxa_pure_virtual
+88 (int (*)(...))__cxa_pure_virtual
+96 (int (*)(...))__cxa_pure_virtual
+104 (int (*)(...))__cxa_pure_virtual
+112 (int (*)(...))__cxa_pure_virtual
+120 (int (*)(...))__cxa_pure_virtual
+128 (int (*)(...))__cxa_pure_virtual
+136 (int (*)(...))__cxa_pure_virtual
+144 (int (*)(...))__cxa_pure_virtual
+152 (int (*)(...))__cxa_pure_virtual
+160 (int (*)(...))__cxa_pure_virtual
+168 (int (*)(...))__cxa_pure_virtual
+176 (int (*)(...))__cxa_pure_virtual
+184 (int (*)(...))__cxa_pure_virtual
+192 (int (*)(...))__cxa_pure_virtual
+200 (int (*)(...))__cxa_pure_virtual
+208 (int (*)(...))__cxa_pure_virtual
+216 (int (*)(...))__cxa_pure_virtual
+224 (int (*)(...))SourceApiMap::isDynamic
+232 (int (*)(...))SourceApiMap::isAdapterSignal
+240 (int (*)(...))SourceApiMap::isAdapterMethod
+248 (int (*)(...))SourceApiMap::isAdapterProperty
+
+Class SourceApiMap
+ size=24 align=8
+ base size=24 base align=8
+SourceApiMap (0x0x7f3bf3b31f00) 0
+ vptr=((& SourceApiMap::_ZTV12SourceApiMap) + 16)
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long int; _Ret = int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Save_errno
+ size=4 align=4
+ base size=4 base align=4
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long int; _Ret = int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Save_errno (0x0x7f3bf3bf3900) 0
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long int; _Ret = int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Range_chk
+ size=1 align=1
+ base size=0 base align=1
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long int; _Ret = int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Range_chk (0x0x7f3bf3bf3c60) 0 empty
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long int; _Ret = long int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Save_errno
+ size=4 align=4
+ base size=4 base align=4
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long int; _Ret = long int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Save_errno (0x0x7f3bf3bf3e40) 0
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long int; _Ret = long int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Range_chk
+ size=1 align=1
+ base size=0 base align=1
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long int; _Ret = long int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Range_chk (0x0x7f3bf3c241e0) 0 empty
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long unsigned int; _Ret = long unsigned int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Save_errno
+ size=4 align=4
+ base size=4 base align=4
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long unsigned int; _Ret = long unsigned int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Save_errno (0x0x7f3bf3c243c0) 0
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long unsigned int; _Ret = long unsigned int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Range_chk
+ size=1 align=1
+ base size=0 base align=1
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long unsigned int; _Ret = long unsigned int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Range_chk (0x0x7f3bf3c24720) 0 empty
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long long int; _Ret = long long int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Save_errno
+ size=4 align=4
+ base size=4 base align=4
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long long int; _Ret = long long int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Save_errno (0x0x7f3bf3c24900) 0
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long long int; _Ret = long long int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Range_chk
+ size=1 align=1
+ base size=0 base align=1
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long long int; _Ret = long long int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Range_chk (0x0x7f3bf3c24c60) 0 empty
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long long unsigned int; _Ret = long long unsigned int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Save_errno
+ size=4 align=4
+ base size=4 base align=4
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long long unsigned int; _Ret = long long unsigned int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Save_errno (0x0x7f3bf3c24e40) 0
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long long unsigned int; _Ret = long long unsigned int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Range_chk
+ size=1 align=1
+ base size=0 base align=1
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long long unsigned int; _Ret = long long unsigned int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Range_chk (0x0x7f3bf3c591e0) 0 empty
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = float; _Ret = float; _CharT = char; _Base = {}; std::size_t = long unsigned int]::_Save_errno
+ size=4 align=4
+ base size=4 base align=4
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = float; _Ret = float; _CharT = char; _Base = {}; std::size_t = long unsigned int]::_Save_errno (0x0x7f3bf3c593c0) 0
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = float; _Ret = float; _CharT = char; _Base = {}; std::size_t = long unsigned int]::_Range_chk
+ size=1 align=1
+ base size=0 base align=1
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = float; _Ret = float; _CharT = char; _Base = {}; std::size_t = long unsigned int]::_Range_chk (0x0x7f3bf3c59720) 0 empty
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = double; _Ret = double; _CharT = char; _Base = {}; std::size_t = long unsigned int]::_Save_errno
+ size=4 align=4
+ base size=4 base align=4
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = double; _Ret = double; _CharT = char; _Base = {}; std::size_t = long unsigned int]::_Save_errno (0x0x7f3bf3c59900) 0
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = double; _Ret = double; _CharT = char; _Base = {}; std::size_t = long unsigned int]::_Range_chk
+ size=1 align=1
+ base size=0 base align=1
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = double; _Ret = double; _CharT = char; _Base = {}; std::size_t = long unsigned int]::_Range_chk (0x0x7f3bf3c59c60) 0 empty
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long double; _Ret = long double; _CharT = char; _Base = {}; std::size_t = long unsigned int]::_Save_errno
+ size=4 align=4
+ base size=4 base align=4
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long double; _Ret = long double; _CharT = char; _Base = {}; std::size_t = long unsigned int]::_Save_errno (0x0x7f3bf3c59e40) 0
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long double; _Ret = long double; _CharT = char; _Base = {}; std::size_t = long unsigned int]::_Range_chk
+ size=1 align=1
+ base size=0 base align=1
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long double; _Ret = long double; _CharT = char; _Base = {}; std::size_t = long unsigned int]::_Range_chk (0x0x7f3bf3c911e0) 0 empty
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long int; _Ret = int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Save_errno
+ size=4 align=4
+ base size=4 base align=4
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long int; _Ret = int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Save_errno (0x0x7f3bf3cbb6c0) 0
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long int; _Ret = int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Range_chk
+ size=1 align=1
+ base size=0 base align=1
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long int; _Ret = int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Range_chk (0x0x7f3bf3cbba20) 0 empty
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long int; _Ret = long int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Save_errno
+ size=4 align=4
+ base size=4 base align=4
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long int; _Ret = long int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Save_errno (0x0x7f3bf3cbbba0) 0
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long int; _Ret = long int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Range_chk
+ size=1 align=1
+ base size=0 base align=1
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long int; _Ret = long int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Range_chk (0x0x7f3bf3cbbf00) 0 empty
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long unsigned int; _Ret = long unsigned int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Save_errno
+ size=4 align=4
+ base size=4 base align=4
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long unsigned int; _Ret = long unsigned int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Save_errno (0x0x7f3bf3ceb0c0) 0
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long unsigned int; _Ret = long unsigned int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Range_chk
+ size=1 align=1
+ base size=0 base align=1
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long unsigned int; _Ret = long unsigned int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Range_chk (0x0x7f3bf3ceb420) 0 empty
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long long int; _Ret = long long int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Save_errno
+ size=4 align=4
+ base size=4 base align=4
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long long int; _Ret = long long int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Save_errno (0x0x7f3bf3ceb5a0) 0
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long long int; _Ret = long long int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Range_chk
+ size=1 align=1
+ base size=0 base align=1
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long long int; _Ret = long long int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Range_chk (0x0x7f3bf3ceb900) 0 empty
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long long unsigned int; _Ret = long long unsigned int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Save_errno
+ size=4 align=4
+ base size=4 base align=4
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long long unsigned int; _Ret = long long unsigned int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Save_errno (0x0x7f3bf3ceba80) 0
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long long unsigned int; _Ret = long long unsigned int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Range_chk
+ size=1 align=1
+ base size=0 base align=1
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long long unsigned int; _Ret = long long unsigned int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Range_chk (0x0x7f3bf3cebde0) 0 empty
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = float; _Ret = float; _CharT = wchar_t; _Base = {}; std::size_t = long unsigned int]::_Save_errno
+ size=4 align=4
+ base size=4 base align=4
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = float; _Ret = float; _CharT = wchar_t; _Base = {}; std::size_t = long unsigned int]::_Save_errno (0x0x7f3bf3cebf60) 0
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = float; _Ret = float; _CharT = wchar_t; _Base = {}; std::size_t = long unsigned int]::_Range_chk
+ size=1 align=1
+ base size=0 base align=1
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = float; _Ret = float; _CharT = wchar_t; _Base = {}; std::size_t = long unsigned int]::_Range_chk (0x0x7f3bf389f300) 0 empty
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = double; _Ret = double; _CharT = wchar_t; _Base = {}; std::size_t = long unsigned int]::_Save_errno
+ size=4 align=4
+ base size=4 base align=4
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = double; _Ret = double; _CharT = wchar_t; _Base = {}; std::size_t = long unsigned int]::_Save_errno (0x0x7f3bf389f480) 0
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = double; _Ret = double; _CharT = wchar_t; _Base = {}; std::size_t = long unsigned int]::_Range_chk
+ size=1 align=1
+ base size=0 base align=1
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = double; _Ret = double; _CharT = wchar_t; _Base = {}; std::size_t = long unsigned int]::_Range_chk (0x0x7f3bf389f7e0) 0 empty
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long double; _Ret = long double; _CharT = wchar_t; _Base = {}; std::size_t = long unsigned int]::_Save_errno
+ size=4 align=4
+ base size=4 base align=4
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long double; _Ret = long double; _CharT = wchar_t; _Base = {}; std::size_t = long unsigned int]::_Save_errno (0x0x7f3bf389f960) 0
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long double; _Ret = long double; _CharT = wchar_t; _Base = {}; std::size_t = long unsigned int]::_Range_chk
+ size=1 align=1
+ base size=0 base align=1
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long double; _Ret = long double; _CharT = wchar_t; _Base = {}; std::size_t = long unsigned int]::_Range_chk (0x0x7f3bf389fcc0) 0 empty
+
--- /dev/null
+# This is an automatic test for the CMake configuration files.
+# To run it manually,
+# 1) mkdir build # Create a build directory
+# 2) cd build
+# 3) # Run cmake on this directory
+# `$qt_prefix/bin/qt-cmake ..` or `cmake -DCMAKE_PREFIX_PATH=/path/to/qt ..`
+# 4) ctest # Run ctest
+
+cmake_minimum_required(VERSION 3.16)
+project(remoteobjects_cmake_tests)
+enable_testing()
+
+set(required_packages Core Network RemoteObjects)
+
+# Setup the test when called as a completely standalone project.
+if(TARGET Qt6::Core)
+ # Tests are built as part of the repository's build tree.
+ # Setup paths so that the Qt packages are found.
+ qt_internal_set_up_build_dir_package_paths()
+endif()
+
+find_package(Qt6 REQUIRED COMPONENTS ${required_packages})
+
+# Setup common test variables which were previously set by ctest_testcase_common.prf.
+set(CMAKE_MODULES_UNDER_TEST "${required_packages}")
+
+foreach(qt_package ${CMAKE_MODULES_UNDER_TEST})
+ set(package_name "${QT_CMAKE_EXPORT_NAMESPACE}${qt_package}")
+ if(${package_name}_FOUND)
+ set(CMAKE_${qt_package}_MODULE_MAJOR_VERSION "${${package_name}_VERSION_MAJOR}")
+ set(CMAKE_${qt_package}_MODULE_MINOR_VERSION "${${package_name}_VERSION_MINOR}")
+ set(CMAKE_${qt_package}_MODULE_PATCH_VERSION "${${package_name}_VERSION_PATCH}")
+ endif()
+endforeach()
+
+include("${_Qt6CTestMacros}")
+
+set(module_includes
+ RemoteObjects QRemoteObjectNode
+)
+
+_qt_internal_test_module_includes(
+ ${module_includes}
+)
+
+_qt_internal_test_expect_pass(test_cmake_macros)
--- /dev/null
+cmake_minimum_required(VERSION 3.16)
+
+project(test_qremoteobjects_module)
+
+find_package(Qt6RemoteObjects REQUIRED)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(MAIN_SRCS main.cpp)
+add_executable(mainapp ${MAIN_SRCS})
+qt6_add_repc_replicas(mainapp ../../integration/pod.rep)
+
+target_link_libraries(mainapp Qt::RemoteObjects)
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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 with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QRemoteObjectNode>
+
+#include "rep_pod_replica.h"
+
+int main(int argc, char **argv)
+{
+ QRemoteObjectNode node;
+
+ MyClassReplica replica;
+
+ return 0;
+}
--- /dev/null
+
+add_subdirectory(sslTestServer)
+add_subdirectory(tst_client)
--- /dev/null
+<RCC>
+ <qresource prefix="/sslcert">
+ <file>client.crt</file>
+ <file>client.key</file>
+ <file>rootCA.key</file>
+ <file>rootCA.pem</file>
+ <file>rootCA.srl</file>
+ <file>server.crt</file>
+ <file>server.key</file>
+ </qresource>
+</RCC>
--- /dev/null
+-----BEGIN CERTIFICATE-----
+MIICrTCCAZUCFHOQggvUf1o8c5i3yNyiGLNcLC4pMA0GCSqGSIb3DQEBCwUAMBIx
+EDAOBgNVBAMMB1F0Uk8gQ0EwHhcNMjEwMjI0MTEzMzU1WhcNMjMwNTMwMTEzMzU1
+WjAUMRIwEAYDVQQDDAkxMjcuMC4wLjEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
+ggEKAoIBAQDbl9iuedw0oSbtpC2m30YdzwRmemijasP9SQGQ6+piUOFUKCZsoGWc
+RcEnLGzC+KJ7FXh8jA1kTXSW6ghqvrUysN8VzjgmcCLFee4JAkCUY8yNrlq13ciR
+19BE09kJdOPZeI57pCSBNA6iy03Q4nc/GJpG63QTqJv/WUUgMek0UsmZIzDcWaqr
+MCMnLMaRi5oKFCnnl8E0XDuRm1nqPAzT+us/4upMv+7Q2xs4QFXbLUpSIToNc1wm
+tP6OAGaYClbJZgZbUNowj0wJeCUAwGGcDpliYj1JB8R015z8Kd8pDCvdD7XL35JR
+rT+eaBFNLUrl30aIl3lWf/buv3OoRmuVAgMBAAEwDQYJKoZIhvcNAQELBQADggEB
+AJjdfuy2pb3KgnpxYiXfKXCqGlN7E1RyoCIsMhldWcxAN5cwIJCrvde5MNI8kDvd
+0SfDpRpCP/hZqpR6DsR9iNYJprXlQNZ7Rs41Eswwlb66DqmBlb5ZQcYl8KsKV5fw
+7PhvLpjC5hEg1OBg1Ooz+aNvI9OJYIRFUJ1smtRzwXWuQd5QoqYVRpzvmrFawnGa
+2NHywiwgKyGvY/y82pPuj1rt0L+bae85cZm32f6gp1me9OuLIqA2G5UafSiigWBY
+YL249Rd4rrT87GAeaiBo8ZxZ8de8O7TOBjSNrfAMySepDWjfFfoNpyp+4foRKmpE
+aZmgGTIj5rfhYh4Gcj1nZBw=
+-----END CERTIFICATE-----
--- /dev/null
+-----BEGIN RSA PRIVATE KEY-----
+MIIEogIBAAKCAQEA25fYrnncNKEm7aQtpt9GHc8EZnpoo2rD/UkBkOvqYlDhVCgm
+bKBlnEXBJyxswviiexV4fIwNZE10luoIar61MrDfFc44JnAixXnuCQJAlGPMja5a
+td3IkdfQRNPZCXTj2XiOe6QkgTQOostN0OJ3PxiaRut0E6ib/1lFIDHpNFLJmSMw
+3FmqqzAjJyzGkYuaChQp55fBNFw7kZtZ6jwM0/rrP+LqTL/u0NsbOEBV2y1KUiE6
+DXNcJrT+jgBmmApWyWYGW1DaMI9MCXglAMBhnA6ZYmI9SQfEdNec/CnfKQwr3Q+1
+y9+SUa0/nmgRTS1K5d9GiJd5Vn/27r9zqEZrlQIDAQABAoIBAEDLm4pQNuPosV3p
+1fapZz0gesHqWLnvpQk145ppom2ERBjbCAuBgLoN8yKl/ynAx+DdwwGtKb5xBHgL
+cpRc1YaxngIHKZZd/ESc59oMqhWfJRqhWe7UFHzEW5YTlLUvopPm+NQO6R6ex7rN
+lpaOXHVnww4uJ8AtPmqoYrdPQurG/txveRMLo84JJT+IH2YVWOzccp809zw4WZZD
+qBcgm/dV8ir+8nUHQlR+loMMrEoKeacNxtHUXWL6d6P93Q72L07t41/l0XmXXq7I
+cVJnGxcJtkeqj03FSHqDU3XM5fRg6f+XnnSnhnd4AUmHe8cvyeCnEf4bdh4UpzBG
+sCie+XkCgYEA93FU0X6ttWdb+rJNHRnHmb4DxOVo2LeXEk1A1ul+Yj+jFP+TwJH+
+bm8PbV7ALdyH2u66ElQG60gW9ztu86xl5ZLVdhijWJpjHKB45eXVhnRcb2Fy9tDc
+pUeRs8+IrrYbWDrNZZYWby83MqPHimCLTmAZl11NMB2ohyFDxr5voGMCgYEA4y/0
+2WN8r74H9I3L2Ghfe8e3i/W35BpjtElJxiL3L1vzGdU5Wo1hDnvjoHvdTxB7LtGU
+I+P0l77fwuAC8G8bh4SZ59jcxlqCmbXy7wDAyrYaCja5OWK9xWXvYuya5CCPrg6h
+wo7TcrxjdEvEVQ97PMZcq6HVBOtINZGfJeSieacCgYAHyQsQJFo20O+17ZI7jioX
+jkD0Gvu3hd889i1KFcKiOLpa2Me/UVieBOSJXmfRiZTEsKouFXK6SGRglwAgrpXu
+KTaKJrBNA16G8g2bviV/u32FC53gYiXvFVdiPu9f/97QYdlAjv5ZtTSZZUnL8smv
+R5rGhmr9TpGU3tkREcDVXQKBgBUfJ0dyvWvlYf31lOcYxQ/QAJuNi7w0S+K+EZLP
+O2X2yYI0VbG6hTSAhigse+XW5Wzz5S71CY92Gn2WsA9EdS3DQT/R5Ky4S34Y8W4R
+BtuR1JfwgIX6TSRmFrx+vOPKtzD6gUWCW9xF8YUlaipyVwXOd10pnZFogn0gfchb
+GlPvAoGAG2xikjlCTrnKv7KRF9sxO1eLixfzHwWKiAhrtFBoHSM4AwynrpAb0eMf
+ObSIjXeBy93LhTluVOsD5J9iXA/SKYoXqt/tDMCHRdwpTsJNBa56GMkpFHHLo6oC
+si20nmMXP949gpRIvrYsgYC8WObbi+RQEWDVutv7hVPCF0QvUHs=
+-----END RSA PRIVATE KEY-----
--- /dev/null
+#!/bin/sh
+#############################################################################
+##
+## Copyright (C) 2021 The Qt Company Ltd.
+## Contact: https://www.qt.io/licensing/
+##
+## This file is the build configuration utility of the Qt Toolkit.
+##
+## $QT_BEGIN_LICENSE:GPL-EXCEPT$
+## Commercial License Usage
+## Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+## and conditions see https://www.qt.io/terms-conditions. For further
+## information use the contact form at https://www.qt.io/contact-us.
+##
+## 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 with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+## included in the packaging of this file. Please review the following
+## information to ensure the GNU General Public License requirements will
+## be met: https://www.gnu.org/licenses/gpl-3.0.html.
+##
+## $QT_END_LICENSE$
+##
+#############################################################################
+
+# Generate the CA key
+openssl genrsa -out rootCA.key 2048
+# Generate the CA cert
+openssl req -x509 -key rootCA.key -out rootCA.pem -sha256 -nodes -subj "/CN=QtRO CA" -days 836
+
+# genFiles stem [extra args to signing]
+genFiles () {
+ stem=$1
+ shift
+ # Generate key
+ openssl genrsa -out $stem.key 2048
+ # Generate certificate-signing request
+ openssl req -new -key $stem.key -out $stem.csr -subj "/CN=127.0.0.1"
+ # Generate and sign the certificate
+ openssl x509 -req -in $stem.csr -out $stem.crt \
+ -CA rootCA.pem -CAkey rootCA.key -CAcreateserial -days 825 -sha256 "$@"
+ # Delete the signing request, no longer needed
+ rm $stem.csr
+}
+genFiles server -extfile server-req.ext
+genFiles client
+
+dest1="../../../../examples/remoteobjects/ssl/sslserver/cert/"
+dest2="../../../../examples/remoteobjects/websockets/common/cert/"
+
+cp -f "client.crt" $dest1
+cp -f "client.crt" $dest2
+cp -f "client.key" $dest1
+cp -f "client.key" $dest2
+
+cp -f "server.crt" $dest1
+cp -f "server.crt" $dest2
+cp -f "server.key" $dest1
+cp -f "server.key" $dest2
+
+cp -f "rootCA.pem" $dest1
+cp -f "rootCA.key" $dest1
+cp -f "rootCA.srl" $dest1
+cp -f "rootCA.pem" $dest2
+cp -f "rootCA.key" $dest2
+cp -f "rootCA.srl" $dest2
--- /dev/null
+-----BEGIN RSA PRIVATE KEY-----
+MIIEowIBAAKCAQEAulVnnHwRF6e2aAThSi1cZpUlO3ZdqzPIuf75NBbRY2y9Vm+F
+cyCqUquNxP/qDE02nfQFBd/PUKqUWQs0EXVEVZPEG6s/l7ionYHkMmWSjh+AAWp7
+Iwx3MlHFNi9c5Xrod7iS1igg0YhDQlnT0xGfTXZasUJ/s6NuNoZiN5L6sEKYDSAu
+kzyyqS23WrqE4RvsGAaoaaJqu1MT8DBqI9xoPpIvwb/4gdOZn4YClW2WWrVjCTT2
+zEzUAh1BjdH3dktXogiFfXHuOP4W8suOx46NXDcZ3f5LF8CT/2uq9l8vta+pV2ci
+BAIctGu5z+fEdTCojvCWOvCzYmjtep/yTukT+QIDAQABAoIBAQCRvRjkCRnpUZDW
+vPJk7SO3THIplwPeUwtthqLtfedaB4PzphhPmr39GRcyfSNXadENK/39wTbKlhCf
+sKaR/RFsib26EnATwCeJwj10uYMuTC73bIxRNn/ISLKiFdtn1YEbmq6meA5rNFO/
+Arkt/juF/8shl6yAGZSrauJJK1mOH8ItMaGR+6tVPWLIZOLk6TiOJhj9SXvMTCw/
+HzgNZMgFGfqnbctg1ki/CY0BkIkYNUTCjhoCwjcgBJl4ERCfTQS6UeEG9Ad+beIH
+g8WKzpfjF5+Jnjzqw87aWx1200OdlEdouTt677RXHJFN5naUc+GJZGpmA3RGZA17
+LqA4zBYNAoGBAOGwtg7JQkBOmUC0SiKdXnxG1hVnS4N3DMIDVX2tAe/wWIrP168e
+0UpCvswLD+JqO1IgWqw9+QUPnhJSQ9JbYB+678esOTLsT5Yd18VcsiRxSacvQfUw
+H4YJaHrFuuFlnxYMlMdPYS3knbIPsft9DVQLFBLL7qPVHbrJ3V6Sn4XrAoGBANNb
+mfhgVr5m0n3sQVTlYhWwbJq5K+Htzzl7Xl3JHpMLm2C/GoorP/2zLVhbH20lsE3A
+FyIfjcwRxGRu2TXCVnMc4GttlMX5leTxykEd2VrZuEVnTdrudm45Z6sZQpdf1QTg
+WebwKgN1eCg7Jkuk5YlRX/KwMtuq4MVzPtOvR+CrAoGAA8uC5DDCKm6n6QyfCoH2
+6sQOKYH5JRbFYiXINDrKg4xZEMx55fnwrvz8VFYDSF1c7f6ZR7grDci7cbdsaIcc
+0KvGCGd+9ro+hFmwHSN342D8ShFjXIoYnZpe5WGZyNx6llZT0h4lli338NyOs5ng
+tX8SMVa4hoy42UE3tbVldU0CgYA0l/K0b6SmNIfkdcm8Cmhh5UjhJ3rX+Yk7UIum
+4skM5jJ/3I4KG8EMrG14MxSa4GoCru4Su69ZPIKWS08ZpYZFlsXxdY8zxGucUN53
+XaochVjpTE9/Tx+BRh+Z3+tGJ76mO/2jDdgmjDCeMjnRUPMdPHaXuWiuaNMNzyOv
+IUrNiQKBgGvxEQ0Oe3d/om2Lp/cHbkhZkw/jO/FG5HtodxiO3+1YLhExsDOc5GVn
++x2eNv+dQSIrGagko9TJe1p9WqFnD19Ls+ezqfw2fR5Amg1KHKGUA7k1+Qe/QgoK
+D+T4/RkvdGRoBv/il+Rj1rfmMAhEzdD7Axek9a6rUj8geO22kp7I
+-----END RSA PRIVATE KEY-----
--- /dev/null
+-----BEGIN CERTIFICATE-----
+MIIDBTCCAe2gAwIBAgIUV9eILCYaC+qwZHR7OO23uyd2UjwwDQYJKoZIhvcNAQEL
+BQAwEjEQMA4GA1UEAwwHUXRSTyBDQTAeFw0yMTAyMjQxMTMzNTVaFw0yMzA2MTAx
+MTMzNTVaMBIxEDAOBgNVBAMMB1F0Uk8gQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IB
+DwAwggEKAoIBAQC6VWecfBEXp7ZoBOFKLVxmlSU7dl2rM8i5/vk0FtFjbL1Wb4Vz
+IKpSq43E/+oMTTad9AUF389QqpRZCzQRdURVk8Qbqz+XuKidgeQyZZKOH4ABansj
+DHcyUcU2L1zleuh3uJLWKCDRiENCWdPTEZ9NdlqxQn+zo242hmI3kvqwQpgNIC6T
+PLKpLbdauoThG+wYBqhpomq7UxPwMGoj3Gg+ki/Bv/iB05mfhgKVbZZatWMJNPbM
+TNQCHUGN0fd2S1eiCIV9ce44/hbyy47Hjo1cNxnd/ksXwJP/a6r2Xy+1r6lXZyIE
+Ahy0a7nP58R1MKiO8JY68LNiaO16n/JO6RP5AgMBAAGjUzBRMB0GA1UdDgQWBBSu
+ehS/XLejTiDbCddGU2mMZ1t3CjAfBgNVHSMEGDAWgBSuehS/XLejTiDbCddGU2mM
+Z1t3CjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQB8JzSuhHPK
+cjhLqOHUGMKtKWOd5p9g2D45cAWh6jdzU/AhmslMPbsO5hZkqfE+3xARtcMmQfF2
+k1Qyp3hDTN1ZqHSM6Urq9uR33/wXZbNRUNCD8lAmqKyzF9NF7Q+tmC//IMRtVQhK
+aMN3LciyYGQjT0XhDKFWEz9/AvUQD97mLow2m0/izqE4SI6ekQDNL26IiCWFgFjh
+ScZjcJ1ogluD2a6sEUGywRXLNV/bdSjRgkAbpvJFrok7dDZ8xCNhOg4xJJQJRWm7
+ZusUydiVyfgrFan6MD+EdldRHjAs8S9BJfZ0RTOWnD9V8auKuVomzKDed54QlXXi
+zwowb3Objpqh
+-----END CERTIFICATE-----
--- /dev/null
+7390820BD47F5A3C7398B7C8DCA218B35C2C2E29
--- /dev/null
+authorityKeyIdentifier=keyid,issuer
+basicConstraints=CA:FALSE
+keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
+extendedKeyUsage = serverAuth
+subjectAltName = @alt_names
+
+[alt_names]
+IP.1 = 127.0.0.1
--- /dev/null
+-----BEGIN CERTIFICATE-----
+MIIDFTCCAf2gAwIBAgIUc5CCC9R/WjxzmLfI3KIYs1wsLigwDQYJKoZIhvcNAQEL
+BQAwEjEQMA4GA1UEAwwHUXRSTyBDQTAeFw0yMTAyMjQxMTMzNTVaFw0yMzA1MzAx
+MTMzNTVaMBQxEjAQBgNVBAMMCTEyNy4wLjAuMTCCASIwDQYJKoZIhvcNAQEBBQAD
+ggEPADCCAQoCggEBAOKHte9tB66OD+Um/WkqxHtW3sKrBs4IxKuWAef0UMRt3ld6
+5HvWk+xsCZdPxeL53nMOIy9FS6wKGvEWTwYRR4Id9iX2XQsI4cRJWl25qgCYohnm
+Eet9CUkXa3ywbyrSBWFD0r956sS+mwhHU9z05jphd6iZEonHu2b4BFFXMN7+prwj
+00EtGbte5wSWWE9ZfXzeGYd4cZBReNCRjaS5XJ3IgjZ4tfxsB3JzBjVafCfnth7r
+Is8a2SKCGnhYmV+A6Agth4xtSKDho+BSDYSuMux3dftM/eqtxF0wXzlnX5ApNwGB
+zWjcoUL63vjjy17oNEtbs5X2e1g8bGRaGRxGUHUCAwEAAaNhMF8wHwYDVR0jBBgw
+FoAUrnoUv1y3o04g2wnXRlNpjGdbdwowCQYDVR0TBAIwADALBgNVHQ8EBAMCBPAw
+EwYDVR0lBAwwCgYIKwYBBQUHAwEwDwYDVR0RBAgwBocEfwAAATANBgkqhkiG9w0B
+AQsFAAOCAQEAqhBhxRgG9N1ZghwWC3ZhWSx4BFl3YrStWlQcjffcQ6p8NDxsrkFc
+gMG51TmJdaz8J4v2AZW8k9GJlEIaZdV/8czeyEwvjKD4vrUw88waeW7n6o8H+8k+
+ak9fRFvnerFrLEWNpyRqbjJWwm8bQ4T5UKsVNXkZnNLyG2Ha29L9gUHffgSMiyLO
+hWqcanPxsMJaDVhw/Gd8JwqaEC1nRPCGxhog2/D2sh4vCj1UykykjPwNz5fP/vfA
+VujNCA23eXAdgD3lALHu2WrmyPkQCM7Z61g4k8+v0KjhyJjdLSVTwkPePEo87Fv4
+sn4Jp5gPPBf7jDFKp8PDdbPmk0qN+Wm8gA==
+-----END CERTIFICATE-----
--- /dev/null
+-----BEGIN RSA PRIVATE KEY-----
+MIIEogIBAAKCAQEA4oe1720Hro4P5Sb9aSrEe1bewqsGzgjEq5YB5/RQxG3eV3rk
+e9aT7GwJl0/F4vnecw4jL0VLrAoa8RZPBhFHgh32JfZdCwjhxElaXbmqAJiiGeYR
+630JSRdrfLBvKtIFYUPSv3nqxL6bCEdT3PTmOmF3qJkSice7ZvgEUVcw3v6mvCPT
+QS0Zu17nBJZYT1l9fN4Zh3hxkFF40JGNpLlcnciCNni1/GwHcnMGNVp8J+e2Husi
+zxrZIoIaeFiZX4DoCC2HjG1IoOGj4FINhK4y7Hd1+0z96q3EXTBfOWdfkCk3AYHN
+aNyhQvre+OPLXug0S1uzlfZ7WDxsZFoZHEZQdQIDAQABAoIBAGuKEYzALc1oE5Ot
+ls++RdhnvQidOHXHI9ZxOCZtjYoyvkK5TI6dp0utXkA+1qqSBFCKfZmLRAlAItog
+xRMUUOYsYxZShokehk8wo32rDlGKJCo3Vnp8uVPBkn13JM8nNPafxASyVAlikyay
+9dUHTeSZML0RLgPKleSkCSi0Q7cYOFG/HB9aNjp8F5rdut02KrmC3cxlHKF7QXXG
+VU+op1Z9o0V2/iUFJnF5CR40sW2THEbBJkkeYwbvUTnavz4XQtZst//DKsDQEe2r
+UrhsIHduvG4tWiBE77m1vyigTxUWCsLQ2KCnn9O+4KyTg9HWCiQ2QSU3istX/rpI
+zN2lOgECgYEA9PVVMnY+t59Q73IQ9LRg5KRqg6YyGQOrwJKbCUxDrA6ikh3MDgwV
+CkC6Jdl6e4DMog51l3CizrfR2+mtNSTUJDGFE1iGgI+Faem4aopRtFRiLWJ8n4m7
+U8pl3XTP0XFT68aBCAE6O/xVPXs0I/eKNvaF5vokB5zm4R79o37WP+UCgYEA7L26
+TiCFA73Fil/bPupqWJnvm896RlO1S+IBOKlPyCHVvxiGLvtv+YTucCFwXQ4FeNRh
+bQEWlURsgeNr7PHATtFUZ/zo/7l1WYNLXZDZwWD+JYllVPwskJOJMx5Rc77Q0aQ6
+7v60XMGwD5cxQ29RHuJs09Iwc9b1WqwOAEJAJVECgYBNsxQXMZKrRAm0KgZe2Ghz
+ngN7RthVPujX6KjsxhghF3NRzcnQGt0Bp45kOxuy2SQPs25xXvUFhSE4FGMwnEH+
+SQbhIA9p8BxtgAlTIhTQkoOhyb+mC1Y0Odsd59OTp9Lq0shS9bC3Hk8bdV0Qm5Bn
+5sKKhYWwNIC3n9Dsb2seUQKBgAS7biPtpnsCqhYwAFPrn6CRwyZcKVeKiM8xf1DA
+oaWgd4NQXC5IPF7Cd3mqUXKquxVFOYVSRj9JlNmr0BZ2Zp+ss4E4nvetn1jgtPrz
+0EZ7R9k8O9hNCh8Bs/ZfnsUvhUELhVoNoVFRVdGZ9hQg/4AcioxZYTqPi2v6kHUU
+3e9hAoGAec7anF5TiTx2jjcDFS9hrRw0w2PsNX24qjqPFqeuzDIorh6rq4Ip4aA0
+7rxeIXmxjmYA7pPCT9rPxtpEp4BQovF9kHMutd8lyB4rGbLpNpOY4m5v8Oo7cLQ3
+kLAwE+jrEwLNtuq+kUlGwK7YLeiGUm4Rsof5IXlSkXzL/99gHC4=
+-----END RSA PRIVATE KEY-----
--- /dev/null
+#include <QtCore>
+
+class PingPong
+{
+ SLOT(void ping(const QString &message));
+ SLOT(void quit());
+ SIGNAL(pong(const QString &message));
+};
--- /dev/null
+
+#####################################################################
+## sslTestServer Binary:
+#####################################################################
+
+qt_internal_add_executable(sslTestServer
+ OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
+ SOURCES
+ main.cpp
+ pingpong.cpp pingpong.h
+ sslserver.cpp sslserver.h
+ INCLUDE_DIRECTORIES
+ ${CMAKE_CURRENT_SOURCE_DIR}
+ PUBLIC_LIBRARIES
+ Qt::RemoteObjects
+ Qt::Test
+)
+
+# Resources:
+set(cert_resource_files
+ "../cert/client.crt"
+ "../cert/client.key"
+ "../cert/rootCA.key"
+ "../cert/rootCA.pem"
+ "../cert/rootCA.srl"
+ "../cert/server.crt"
+ "../cert/server.key"
+)
+
+qt_internal_add_resource(sslTestServer "cert"
+ PREFIX
+ "/sslcert"
+ BASE
+ "../cert"
+ FILES
+ ${cert_resource_files}
+)
+
+qt6_add_repc_sources(sslTestServer
+ ../pingpong.rep
+)
+
+#### Keys ignored in scope 1:.:.:sslTestServer.pro:<TRUE>:
+# TEMPLATE = "app"
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2018 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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 with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "pingpong.h"
+#include "sslserver.h"
+
+#include <QCoreApplication>
+#include <QDebug>
+#include <QSslConfiguration>
+
+#include <QRemoteObjectHost>
+
+int main(int argc, char *argv[])
+{
+ QCoreApplication app(argc, argv);
+ QRemoteObjectHost host;
+ auto config = QSslConfiguration::defaultConfiguration();
+ config.setCaCertificates(QSslCertificate::fromPath(QStringLiteral(":/sslcert/rootCA.pem")));
+ QSslConfiguration::setDefaultConfiguration(config);
+ SslServer server;
+ server.listen(QHostAddress::Any, 65111);
+ host.setHostUrl(server.serverAddress().toString(), QRemoteObjectHost::AllowExternalRegistration);
+ QObject::connect(&server, &SslServer::encryptedSocketReady, &server, [&host](QSslSocket *socket){
+ QObject::connect(socket, &QSslSocket::errorOccurred,
+ socket, [](QAbstractSocket::SocketError error){
+ qDebug() << "QSslSocket::error" << error;
+ exit(1);
+ });
+ host.addHostSideConnection(socket);
+ });
+
+ PingPong pp;
+ host.enableRemoting(&pp);
+ return app.exec();
+}
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2018 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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 with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QCoreApplication>
+#include <QDebug>
+#include <QTimer>
+#include "pingpong.h"
+
+PingPong::PingPong(QObject *parent)
+ : PingPongSimpleSource(parent)
+{}
+
+void PingPong::ping(const QString &message)
+{
+ emit pong("Pong " + message);
+}
+
+void PingPong::quit()
+{
+ // Kill me softly
+ QMetaObject::invokeMethod(qApp, "quit", Qt::QueuedConnection);
+}
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2018 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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 with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef PINGPONG_H
+#define PINGPONG_H
+
+#include "rep_pingpong_source.h"
+
+class PingPong : public PingPongSimpleSource
+{
+public:
+ PingPong(QObject *parent = nullptr);
+
+ // PingPongSource interface
+public slots:
+ void ping(const QString &message) override;
+ void quit() override;
+};
+
+#endif // PINGPONG_H
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2018 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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 with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "sslserver.h"
+#include <QSslSocket>
+
+SslServer::SslServer(QObject *parent)
+ : QTcpServer(parent)
+{}
+
+
+void SslServer::incomingConnection(qintptr socketDescriptor)
+{
+ auto serverSocket = new QSslSocket;
+ if (serverSocket->setSocketDescriptor(socketDescriptor)) {
+ addPendingConnection(serverSocket);
+ connect(serverSocket, &QSslSocket::encrypted, this, [this, serverSocket] {
+ Q_EMIT encryptedSocketReady(serverSocket);
+ });
+ connect(serverSocket, static_cast<void (QSslSocket::*)(const QList<QSslError>&)>(&QSslSocket::sslErrors),
+ this, [serverSocket](const QList<QSslError>& errors){
+ qWarning() << "Error:" << serverSocket << errors;
+ delete serverSocket;
+ });
+ serverSocket->setPeerVerifyMode(QSslSocket::VerifyPeer);
+ serverSocket->setLocalCertificate(QStringLiteral(":/sslcert/server.crt"));
+ serverSocket->setPrivateKey(QStringLiteral(":/sslcert/server.key"));
+ serverSocket->startServerEncryption();
+ } else {
+ delete serverSocket;
+ }
+}
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2018 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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 with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef SSLSERVER_H
+#define SSLSERVER_H
+
+#include <QTcpServer>
+
+QT_BEGIN_NAMESPACE
+class QSslSocket;
+QT_END_NAMESPACE
+
+class SslServer : public QTcpServer
+{
+ Q_OBJECT
+public:
+ SslServer(QObject *parent=nullptr);
+ void incomingConnection(qintptr socketDescriptor) override;
+
+signals:
+ void encryptedSocketReady(QSslSocket *socket);
+};
+
+
+#endif // SSLSERVER_H
--- /dev/null
+
+#####################################################################
+## tst_external_IODevice Test:
+#####################################################################
+
+qt_internal_add_test(tst_external_IODevice
+ OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
+ SOURCES
+ tst_client.cpp
+ PUBLIC_LIBRARIES
+ Qt::RemoteObjects
+)
+
+# Resources:
+set(cert_resource_files
+ "../cert/client.crt"
+ "../cert/client.key"
+ "../cert/rootCA.key"
+ "../cert/rootCA.pem"
+ "../cert/rootCA.srl"
+ "../cert/server.crt"
+ "../cert/server.key"
+)
+
+qt_internal_add_resource(tst_external_IODevice "cert"
+ PREFIX
+ "/sslcert"
+ BASE
+ "../cert"
+ FILES
+ ${cert_resource_files}
+)
+
+qt6_add_repc_replicas(tst_external_IODevice
+ ../pingpong.rep
+)
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2018 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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 with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtTest/QtTest>
+#include <QRemoteObjectNode>
+#include <QScopedPointer>
+#include "rep_pingpong_replica.h"
+
+#include "../../../shared/testutils.h"
+
+class tst_clientSSL: public QObject
+{
+ Q_OBJECT
+public:
+ tst_clientSSL() = default;
+
+private slots:
+ void initTestCase()
+ {
+ QVERIFY(TestUtils::init("tst_client"));
+ }
+ void testRun()
+ {
+ QProcess serverProc;
+ serverProc.setProcessChannelMode(QProcess::ForwardedChannels);
+ serverProc.start(TestUtils::findExecutable("sslTestServer", "/sslTestServer"),
+ QStringList());
+ QVERIFY(serverProc.waitForStarted());
+
+ // wait for server start
+ QTest::qWait(200);
+ QRemoteObjectNode m_client;
+ auto config = QSslConfiguration::defaultConfiguration();
+ config.setCaCertificates(QSslCertificate::fromPath(QStringLiteral(":/sslcert/rootCA.pem")));
+ QSslConfiguration::setDefaultConfiguration(config);
+
+ QScopedPointer<QSslSocket> socketClient{new QSslSocket};
+ socketClient->setLocalCertificate(QStringLiteral(":/sslcert/client.crt"));
+ socketClient->setPrivateKey(QStringLiteral(":/sslcert/client.key"));
+ socketClient->setPeerVerifyMode(QSslSocket::VerifyPeer);
+ socketClient->connectToHostEncrypted(QStringLiteral("127.0.0.1"), 65111);
+ QVERIFY(socketClient->waitForEncrypted(-1));
+
+ connect(socketClient.data(), &QSslSocket::errorOccurred,
+ socketClient.data(), [](QAbstractSocket::SocketError error){
+ QCOMPARE(error, QAbstractSocket::RemoteHostClosedError);
+ });
+ m_client.addClientSideConnection(socketClient.data());
+
+ QScopedPointer<PingPongReplica> pp{m_client.acquire<PingPongReplica>()};
+ QVERIFY(pp->waitForSource());
+
+ QString pongStr;
+ connect(pp.data(), &PingPongReplica::pong, [&pongStr](const QString &str) {
+ pongStr = str;
+ });
+ pp->ping("yahoo");
+ QTRY_COMPARE(pongStr, "Pong yahoo");
+ pp->ping("one more");
+ QTRY_COMPARE(pongStr, "Pong one more");
+ pp->ping("last one");
+ QTRY_COMPARE(pongStr, "Pong last one");
+ pp->quit();
+ QTRY_VERIFY(serverProc.state() != QProcess::Running);
+ QCOMPARE(serverProc.exitCode(), 0);
+ }
+};
+
+QTEST_MAIN(tst_clientSSL)
+
+#include "tst_client.moc"
--- /dev/null
+
+#####################################################################
+## tst_integration Test:
+#####################################################################
+
+qt_internal_add_test(tst_integration
+ SOURCES
+ engine.cpp engine.h
+ speedometer.cpp speedometer.h
+ temperature.h
+ tst_integration.cpp
+ PUBLIC_LIBRARIES
+ Qt::RemoteObjects
+)
+qt6_add_repc_sources(tst_integration
+ engine.rep
+ ../repfiles/localdatacenter.rep
+ ../repfiles/tcpdatacenter.rep
+)
+qt6_add_repc_replicas(tst_integration
+ engine.rep
+ ../repfiles/localdatacenter.rep
+ ../repfiles/tcpdatacenter.rep
+)
+qt6_add_repc_merged(tst_integration
+ speedometer.rep
+ enum.rep
+ pod.rep
+)
+
+add_dependencies(tst_integration localsockettestserver)
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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 with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "engine.h"
+
+Engine::Engine(int cylinders, QObject *parent) :
+ EngineSimpleSource(cylinders, parent)
+{
+ setRpm(0);
+ setpurchasedPart(false);
+}
+
+Engine::~Engine()
+{
+}
+
+bool Engine::start()
+{
+ if (started())
+ return false; // already started
+
+ setStarted(true);
+ return true;
+}
+
+void Engine::increaseRpm(int deltaRpm)
+{
+ setRpm(rpm() + deltaRpm);
+}
+
+Temperature Engine::temperature()
+{
+ return _temperature;
+}
+
+void Engine::setTemperature(const Temperature &value)
+{
+ _temperature = value;
+}
+
+void Engine::setpurchasedPart(bool value)
+{
+ _purchasedPart = value;
+}
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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 with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef TESTS_ENGINE_H
+#define TESTS_ENGINE_H
+
+#include "rep_engine_source.h"
+
+class Engine : public EngineSimpleSource
+{
+ Q_OBJECT
+ Q_PROPERTY(bool purchasedPart READ purchasedPart WRITE setpurchasedPart)
+
+public:
+ Engine(int cylinders = 4, QObject *parent = nullptr);
+ ~Engine() override;
+
+ bool start() override;
+ void increaseRpm(int deltaRpm) override;
+
+ void unnormalizedSignature(int, int) override {}
+
+ Temperature temperature() override;
+ void setTemperature(const Temperature &value);
+
+ void setSharedTemperature(const Temperature::Ptr &) override {}
+
+ bool purchasedPart() {return _purchasedPart;}
+
+public Q_SLOTS:
+ void setpurchasedPart(bool value);
+
+ QString myTestString() override { return _myTestString; }
+ void setMyTestString(QString value) override { _myTestString = value; }
+
+private:
+ bool _purchasedPart;
+ QString _myTestString;
+ Temperature _temperature;
+};
+
+#endif
--- /dev/null
+#include "temperature.h"
+
+class Engine
+{
+ ENUM EngineType { GAS=0, ELECTRIC=1, HYBRID=2 }
+ PROP(int cylinders = 4 CONSTANT);
+ PROP(bool started);
+ PROP(int rpm READWRITE);
+ PROP(EngineType engineType=GAS PERSISTED)
+
+ SLOT(bool start());
+ SLOT(void increaseRpm(int deltaRpm));
+
+ SLOT(void unnormalizedSignature(int a, int b));
+
+ SLOT(Temperature temperature())
+ SLOT(void setSharedTemperature(const Temperature::Ptr &sharedTemperature))
+
+ SLOT(QString myTestString())
+ SLOT(setMyTestString(QString value))
+};
--- /dev/null
+ENUM Test {TRUE, FALSE}
+
+class TestClass
+{
+ ENUM ClassEnum {Null, One, Two}
+ PROP(TestEnum::Test testEnum)
+ PROP(ClassEnum classEnum)
+ PROP(ClassEnum classEnumRW READWRITE)
+}
--- /dev/null
+POD MyPOD(int i, float f, QString s)
+
+class MyClass
+{
+ PROP(MyPOD myPOD)
+}
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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 with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "speedometer.h"
+
+Speedometer::Speedometer(QObject *parent) :
+ SpeedometerSimpleSource(parent)
+{
+}
+
+Speedometer::~Speedometer()
+{
+}
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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 with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef TESTS_SPEEDOMETER_H
+#define TESTS_SPEEDOMETER_H
+
+#include "rep_speedometer_merged.h"
+
+class Speedometer : public SpeedometerSimpleSource
+{
+ Q_OBJECT
+public:
+ Speedometer(QObject *parent = nullptr);
+ ~Speedometer() override;
+
+private:
+ int speed;
+};
+
+#endif
--- /dev/null
+class Speedometer
+{
+ PROP(int mph);
+};
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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 with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef TEMPERATURE_H
+#define TEMPERATURE_H
+
+#include <QSharedPointer>
+#include <QString>
+
+class Temperature
+{
+public:
+ typedef QSharedPointer<Temperature> Ptr;
+
+ Temperature() : _value(0) {}
+ Temperature(double value, const QString &unit) : _value(value), _unit(unit) {}
+
+ void setValue(double arg) { _value = arg; }
+ double value() const { return _value; }
+
+ void setUnit(const QString &arg) { _unit = arg; }
+ QString unit() const { return _unit; }
+
+private:
+ double _value;
+ QString _unit;
+};
+
+inline bool operator==(const Temperature &lhs, const Temperature &rhs)
+{
+ return lhs.unit() == rhs.unit() &&
+ lhs.value() == rhs.value();
+}
+
+inline bool operator!=(const Temperature &lhs, const Temperature &rhs)
+{
+ return !(lhs == rhs);
+}
+
+inline QDataStream &operator<<(QDataStream &out, const Temperature &temperature)
+{
+ out << temperature.value();
+ out << temperature.unit();
+ return out;
+}
+
+inline QDataStream &operator>>(QDataStream &in, Temperature &temperature)
+{
+ double value;
+ in >> value;
+ temperature.setValue(value);
+
+ QString unit;
+ in >> unit;
+ temperature.setUnit(unit);
+ return in;
+}
+
+inline QDataStream &operator>>(QDataStream &out, const Temperature::Ptr& temperaturePtr)
+{
+ out << *temperaturePtr;
+ return out;
+}
+
+inline QDataStream &operator>>(QDataStream &in, Temperature::Ptr& temperaturePtr)
+{
+ Temperature *temperature = new Temperature;
+ in >> *temperature;
+ temperaturePtr.reset(temperature);
+ return in;
+}
+
+Q_DECLARE_METATYPE(Temperature);
+Q_DECLARE_METATYPE(Temperature::Ptr);
+
+#endif
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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 with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "../../shared/testutils.h"
+
+#include <QtTest/QtTest>
+#include <QMetaType>
+#if QT_CONFIG(process)
+#include <QProcess>
+#endif
+#include <QFileInfo>
+#include <QTcpServer>
+#include <QTcpSocket>
+
+#include <QRemoteObjectReplica>
+#include <QRemoteObjectNode>
+#include <QRemoteObjectSettingsStore>
+#include "engine.h"
+#include "speedometer.h"
+#include "rep_engine_replica.h"
+#include "rep_speedometer_merged.h"
+#include "rep_enum_merged.h"
+#include "rep_pod_merged.h"
+#include "rep_localdatacenter_source.h"
+#include "rep_tcpdatacenter_source.h"
+#include "rep_localdatacenter_replica.h"
+#include "rep_tcpdatacenter_replica.h"
+
+#define SET_NODE_NAME(obj) (obj).setName(QLatin1String(#obj))
+
+//DUMMY impl for variant comparison
+bool operator<(const QList<int> &lhs, const QList<int> &rhs)
+{
+ return lhs.size() < rhs.size();
+}
+
+class TestLargeData: public QObject
+{
+ Q_OBJECT
+
+Q_SIGNALS:
+ void send(const QByteArray &data);
+};
+
+class TestDynamicBase : public QObject
+{
+ Q_OBJECT
+public:
+ TestDynamicBase(QObject *parent=nullptr) : QObject(parent) {}
+
+signals:
+ void otherValueChanged();
+};
+
+
+class TestDynamic : public TestDynamicBase
+{
+ Q_OBJECT
+ Q_PROPERTY(int value READ value WRITE setValue NOTIFY valueChanged)
+ Q_PROPERTY(int otherValue READ otherValue WRITE setOtherValue NOTIFY otherValueChanged)
+public:
+ TestDynamic(QObject *parent=nullptr) :
+ TestDynamicBase(parent),
+ m_value(0),
+ m_otherValue(0) {}
+
+ int value() const { return m_value; }
+ void setValue(int value)
+ {
+ if (m_value == value)
+ return;
+
+ m_value = value;
+ emit valueChanged();
+ }
+
+ int otherValue() const { return m_otherValue; }
+ void setOtherValue(int otherValue)
+ {
+ if (m_otherValue == otherValue)
+ return;
+
+ m_otherValue = otherValue;
+ emit otherValueChanged();
+ }
+
+signals:
+ void valueChanged();
+
+private:
+ int m_value;
+ int m_otherValue;
+};
+
+class TestPersistedStore : public QRemoteObjectAbstractPersistedStore
+{
+ Q_OBJECT
+
+public:
+ TestPersistedStore() : type(EngineReplica::HYBRID) {}
+ void saveProperties(const QString &, const QByteArray &, const QVariantList &values) override
+ {
+ type = values.at(0).value<EngineReplica::EngineType>();
+ }
+ QVariantList restoreProperties(const QString &, const QByteArray &) override
+ {
+ return QVariantList() << QVariant::fromValue(type);
+ }
+private:
+ EngineReplica::EngineType type;
+};
+
+class tst_Integration: public QObject
+{
+ Q_OBJECT
+
+ void setupTcp()
+ {
+ if (!tcpServer) {
+ tcpServer = new QTcpServer;
+ tcpServer->listen(QHostAddress::Any, 65511);
+ socketClient = new QTcpSocket;
+ socketClient->connectToHost(QHostAddress::LocalHost, tcpServer->serverPort());
+ QVERIFY(socketClient->waitForConnected(5000));
+
+ QVERIFY(tcpServer->waitForNewConnection(5000));
+ QVERIFY(tcpServer->hasPendingConnections());
+ socketServer = tcpServer->nextPendingConnection();
+ }
+ }
+
+ void setupHost(bool useRegistry=false)
+ {
+ QFETCH_GLOBAL(QUrl, hostUrl);
+ QFETCH_GLOBAL(QUrl, registryUrl);
+ host = new QRemoteObjectHost;
+ SET_NODE_NAME(*host);
+ if (!hostUrl.isEmpty()) {
+ host->setHostUrl(hostUrl);
+ if (useRegistry)
+ host->setRegistryUrl(registryUrl);
+ } else {
+ setupTcp();
+ host->addHostSideConnection(socketServer);
+ }
+ }
+
+ void setupClient(bool useRegistry=false)
+ {
+ QFETCH_GLOBAL(QUrl, hostUrl);
+ QFETCH_GLOBAL(QUrl, registryUrl);
+ client = new QRemoteObjectNode;
+ Q_SET_OBJECT_NAME(*client);
+ if (!hostUrl.isEmpty())
+ {
+ if (useRegistry)
+ client->setRegistryUrl(registryUrl);
+ else {
+ client->connectToNode(hostUrl);
+ }
+ } else {
+ setupTcp();
+ client->addClientSideConnection(socketClient);
+ }
+ }
+
+ void setupRegistry()
+ {
+ QFETCH_GLOBAL(QUrl, registryUrl);
+ registry = new QRemoteObjectRegistryHost(registryUrl);
+ SET_NODE_NAME(*registry);
+ }
+
+signals:
+ void forwardResult(int);
+
+private:
+ QRemoteObjectHost *host;
+ QRemoteObjectNode *client;
+ QRemoteObjectRegistryHost *registry;
+ QTcpServer *tcpServer;
+ QPointer<QTcpSocket> socketClient, socketServer;
+
+private slots:
+ void initTestCase_data()
+ {
+ QTest::addColumn<QUrl>("hostUrl");
+ QTest::addColumn<QUrl>("registryUrl");
+
+ QTest::newRow("tcp") << QUrl(QLatin1String("tcp://127.0.0.1:65511")) << QUrl(QLatin1String("tcp://127.0.0.1:65512"));
+#ifdef __QNXNTO__
+ QTest::newRow("qnx") << QUrl(QLatin1String("qnx:replica")) << QUrl(QLatin1String("qnx:registry"));
+#endif
+ QTest::newRow("local") << QUrl(QLatin1String("local:replicaLocalIntegration")) << QUrl(QLatin1String("local:registryLocalIntegration"));
+#ifdef Q_OS_LINUX
+ QTest::newRow("localabstract") << QUrl(QLatin1String("localabstract:replicaAbstractIntegration")) << QUrl(QLatin1String("localabstract:registryAbstractIntegration"));
+#endif
+ QTest::newRow("external") << QUrl() << QUrl();
+ }
+
+ void initTestCase()
+ {
+ QVERIFY(TestUtils::init("integration"));
+ QLoggingCategory::setFilterRules("qt.remoteobjects.warning=false");
+
+ // use different paths in QRemoteObjectSettingsStore
+ QCoreApplication::setOrganizationName(QLatin1String("QtProject"));
+ QStandardPaths::setTestModeEnabled(true);
+ }
+
+ void init()
+ {
+ registry = nullptr;
+ host = nullptr;
+ client = nullptr;
+ tcpServer = nullptr;
+ socketClient = nullptr;
+ socketServer = nullptr;
+ }
+
+ void cleanup()
+ {
+ delete registry;
+ delete host;
+ delete client;
+ delete tcpServer;
+ if (socketClient) {
+ socketClient->deleteLater();
+ }
+ if (socketServer) {
+ socketServer->deleteLater();
+ }
+ // wait for delivery of RemoveObject events to the source
+ QTest::qWait(200);
+ }
+
+ void basicTest()
+ {
+ setupHost();
+ Engine e;
+ e.setRpm(1234);
+ host->enableRemoting(&e);
+
+ setupClient();
+ const QScopedPointer<EngineReplica> engine_r(client->acquire<EngineReplica>());
+ engine_r->waitForSource();
+ QCOMPARE(engine_r->rpm(), e.rpm());
+ }
+
+ void persistRestoreTest()
+ {
+ QRemoteObjectNode _client;
+ Q_SET_OBJECT_NAME(_client);
+ TestPersistedStore store;
+ _client.setPersistedStore(&store);
+
+ const QScopedPointer<EngineReplica> engine_r(_client.acquire<EngineReplica>());
+ QCOMPARE(engine_r->engineType(), EngineReplica::HYBRID);
+ }
+
+ void persistTest()
+ {
+ QRemoteObjectSettingsStore store;
+
+ setupHost();
+ Engine e;
+ e.setEngineType(EngineSimpleSource::ELECTRIC);
+ host->enableRemoting(&e);
+
+ setupClient();
+ client->setPersistedStore(&store);
+
+ QScopedPointer<EngineReplica> engine_r(client->acquire<EngineReplica>());
+ engine_r->waitForSource();
+ QCOMPARE(engine_r->engineType(), EngineReplica::ELECTRIC);
+
+ // Delete to persist
+ engine_r.reset();
+ host->disableRemoting(&e);
+
+ engine_r.reset(client->acquire<EngineReplica>());
+ QCOMPARE(engine_r->waitForSource(1000), false);
+ QCOMPARE(engine_r->engineType(), EngineReplica::ELECTRIC);
+ }
+
+ // ensure we don't crash when ObjectList iterates over in process replicas
+ void inProcessObjectList()
+ {
+ setupRegistry();
+ setupHost(true);
+ setupClient(true);
+ Engine e;
+ host->enableRemoting(&e);
+ e.setStarted(false);
+
+ const QScopedPointer<EngineReplica> engine_r(host->acquire<EngineReplica>());
+ const QScopedPointer<EngineReplica> engine_r2(client->acquire<EngineReplica>());
+ engine_r->waitForSource(1000);
+ engine_r2->waitForSource(1000);
+ QCOMPARE(engine_r->started(), false);
+ QCOMPARE(engine_r2->started(), false);
+ engine_r->pushStarted(true);
+
+ QTRY_COMPARE(engine_r->started(), true);
+ QTRY_COMPARE(engine_r2->started(), true);
+ }
+
+ void enumTest()
+ {
+ setupHost();
+
+ setupClient();
+
+ TestClassSimpleSource tc;
+ tc.setTestEnum(TestEnum::FALSE);
+ tc.setClassEnum(TestClassSimpleSource::One);
+ tc.setClassEnumRW(TestClassSimpleSource::One);
+ host->enableRemoting(&tc);
+ const QScopedPointer<TestClassReplica> tc_rep(client->acquire<TestClassReplica>());
+ tc_rep->waitForSource();
+ QCOMPARE(tc.testEnum(), tc_rep->testEnum());
+ QCOMPARE(qint32(tc.classEnum()), qint32(TestClassSimpleSource::One));
+
+ // set property on the replica (test property change packet)
+ {
+ QSignalSpy spy(tc_rep.data(), &TestClassReplica::classEnumChanged);
+ QVERIFY(spy.isValid());
+ tc_rep->pushClassEnum(TestClassReplica::Two);
+ QVERIFY(spy.count() || spy.wait());
+
+ QCOMPARE(qint32(tc.classEnum()), qint32(tc_rep->classEnum()));
+ }
+
+ // set property on the source (test property change packet)
+ {
+ QSignalSpy spy(tc_rep.data(), &TestClassReplica::classEnumChanged);
+ tc.setClassEnum(TestClassSimpleSource::One);
+ QVERIFY(spy.wait());
+
+ QCOMPARE(qint32(tc.classEnum()), qint32(tc_rep->classEnum()));
+ }
+
+ QScopedPointer<QRemoteObjectDynamicReplica> tc_repDynamic(client->acquireDynamic(QStringLiteral("TestClass")));
+
+ tc_repDynamic->waitForSource(1000);
+ QVERIFY(tc_repDynamic->isInitialized());
+
+ const QMetaObject *metaObject = tc_repDynamic->metaObject();
+
+ int propertyIndex = metaObject->indexOfProperty("classEnumRW");
+ QVERIFY(propertyIndex >= 0);
+
+ QMetaProperty property = metaObject->property(propertyIndex);
+ QVERIFY(property.isValid());
+ QCOMPARE(property.typeName(), "TestClassReplica::ClassEnum");
+
+ // read enum on the dynamic replica
+ {
+ QCOMPARE(property.read(tc_repDynamic.data()).value<TestClassReplica::ClassEnum>(), TestClassReplica::One);
+ }
+
+ // write enum on the dynamic replica
+ {
+ QSignalSpy spy(tc_rep.data(), &TestClassReplica::classEnumRWChanged);
+ property.write(tc_repDynamic.data(), TestClassReplica::Two);
+ QVERIFY(spy.wait());
+
+ QCOMPARE(tc_rep->classEnumRW(), TestClassReplica::Two);
+ }
+
+ propertyIndex = metaObject->indexOfProperty("classEnum");
+ QVERIFY(propertyIndex >= 0);
+
+ property = metaObject->property(propertyIndex);
+ QVERIFY(property.isValid());
+ QCOMPARE(property.typeName(), "TestClassReplica::ClassEnum");
+
+ // read enum on the dynamic replica
+ {
+ QCOMPARE(property.read(tc_repDynamic.data()).value<TestClassReplica::ClassEnum>(), TestClassReplica::One);
+ }
+
+ // ensure write enum fails on ReadPush
+ {
+ QSignalSpy spy(tc_rep.data(), &TestClassReplica::classEnumChanged);
+ bool res = property.write(tc_repDynamic.data(), TestClassReplica::Two);
+ QVERIFY(!res);
+ int methodIndex = metaObject->indexOfMethod("pushClassEnum(TestClassReplica::ClassEnum)");
+ QVERIFY(methodIndex >= 0);
+ QMetaMethod method = metaObject->method(methodIndex);
+ QVERIFY(method.isValid());
+
+ QVERIFY(method.invoke(tc_repDynamic.data(), Q_ARG(TestClassReplica::ClassEnum, TestClassReplica::Two)));
+ QVERIFY(spy.wait());
+
+ QCOMPARE(tc_rep->classEnum(), TestClassReplica::Two);
+ }
+ }
+
+ void namedObjectTest()
+ {
+ setupHost();
+
+ setupClient();
+
+ Engine e;
+ e.setRpm(3333);
+ Engine *e2 = new Engine();
+ QScopedPointer<Engine> engineSave;
+ engineSave.reset(e2);
+ e2->setRpm(4444);
+ host->enableRemoting(&e);
+ host->enableRemoting(e2, QStringLiteral("MyTestEngine"));
+
+ const QScopedPointer<EngineReplica> engine_r(client->acquire<EngineReplica>());
+ const QScopedPointer<EngineReplica> namedEngine_r(client->acquire<EngineReplica>(QStringLiteral("MyTestEngine")));
+ engine_r->waitForSource();
+ QCOMPARE(engine_r->cylinders(), e.cylinders());
+ QCOMPARE(engine_r->rpm(), 3333);
+ namedEngine_r->waitForSource();
+ QCOMPARE(namedEngine_r->cylinders(), e2->cylinders());
+ QCOMPARE(namedEngine_r->rpm(), 4444);
+
+ engineSave.reset();
+ //Deleting the object before disable remoting will cause disable remoting to
+ //return false;
+ QVERIFY(!host->disableRemoting(e2));
+ }
+
+ void multipleInstancesTest()
+ {
+ setupHost();
+ Engine e;
+ host->enableRemoting(&e);
+
+ setupClient();
+
+ auto instances = client->instances<EngineReplica>();
+ QCOMPARE(instances, QStringList());
+
+ Engine e2;
+ host->enableRemoting(&e2, QStringLiteral("Engine2"));
+
+ const QScopedPointer<EngineReplica> engine_r(client->acquire<EngineReplica>());
+ const QScopedPointer<EngineReplica> engine2_r(client->acquire<EngineReplica>(QStringLiteral("Engine2")));
+ const QScopedPointer<EngineReplica> engine3_r(client->acquire<EngineReplica>(QStringLiteral("Engine_doesnotexist")));
+ QVERIFY(engine_r->waitForSource());
+ QVERIFY(engine2_r->waitForSource());
+ QVERIFY(!engine3_r->waitForSource(500));
+
+ instances = client->instances<EngineReplica>();
+ QCOMPARE(instances, QStringList({"Engine", "Engine2"}));
+
+ QSignalSpy spy(engine_r.data(), &QRemoteObjectReplica::stateChanged);
+ host->disableRemoting(&e);
+ spy.wait();
+ QCOMPARE(spy.count(), 1);
+
+ instances = client->instances<EngineReplica>();
+ QCOMPARE(instances, QStringList({"Engine2"}));
+ }
+
+ void registrySourceLocationBindings()
+ {
+ QFETCH_GLOBAL(QUrl, registryUrl);
+ QFETCH_GLOBAL(QUrl, hostUrl);
+ if (registryUrl.isEmpty())
+ QSKIP("Skipping registry tests for external QIODevice types.");
+
+ setupRegistry();
+ setupHost(true);
+ setupClient(true);
+
+ QVERIFY(host->registry()->sourceLocations().empty());
+ QVERIFY(client->registry()->sourceLocations().empty());
+
+ QVERIFY(host->registry()->bindableSourceLocations().isReadOnly());
+ QVERIFY(client->registry()->bindableSourceLocations().isReadOnly());
+
+ Engine e1;
+ const auto engine1 = QStringLiteral("Engine1");
+ Engine e2;
+ const auto engine2 = QStringLiteral("Engine2");
+
+ QRemoteObjectSourceLocations expectedSourceLocations;
+ expectedSourceLocations[engine1] = { QStringLiteral("Engine"), hostUrl };
+
+ int hostSrcLocationsChanged = 0;
+ auto hostHandler = host->registry()->bindableSourceLocations().onValueChanged([&] {
+ QCOMPARE(host->registry()->sourceLocations(), expectedSourceLocations);
+ ++hostSrcLocationsChanged;
+ });
+
+ int clientSrcLocationsChanged = 0;
+ auto clientHandler = client->registry()->bindableSourceLocations().onValueChanged([&] {
+ QCOMPARE(client->registry()->sourceLocations(), expectedSourceLocations);
+ ++clientSrcLocationsChanged;
+ });
+
+ QProperty<QRemoteObjectSourceLocations> hostObserver;
+ hostObserver.setBinding([&] { return host->registry()->sourceLocations(); });
+
+ QProperty<QRemoteObjectSourceLocations> clientObserver;
+ clientObserver.setBinding([&] { return client->registry()->sourceLocations(); });
+
+ QSignalSpy hostSpy(host->registry(), &QRemoteObjectRegistry::remoteObjectAdded);
+ QSignalSpy clientSpy(client->registry(), &QRemoteObjectRegistry::remoteObjectAdded);
+
+ host->enableRemoting(&e1, engine1);
+ QTRY_COMPARE(hostSpy.count(), 1);
+ QTRY_COMPARE(clientSpy.count(), 1);
+ QCOMPARE(hostObserver.value(), host->registry()->sourceLocations());
+ QCOMPARE(clientObserver.value(), client->registry()->sourceLocations());
+ QCOMPARE(hostObserver.value(), clientObserver.value());
+ QCOMPARE(hostObserver.value(), expectedSourceLocations);
+ QCOMPARE(hostSrcLocationsChanged, 1);
+ QCOMPARE(clientSrcLocationsChanged, 1);
+
+ expectedSourceLocations[engine2] = { QStringLiteral("Engine"), hostUrl };
+ host->enableRemoting(&e2, engine2);
+ QTRY_COMPARE(hostSpy.count(), 2);
+ QTRY_COMPARE(clientSpy.count(), 2);
+ QCOMPARE(hostObserver.value(), host->registry()->sourceLocations());
+ QCOMPARE(clientObserver.value(), client->registry()->sourceLocations());
+ QCOMPARE(hostObserver.value(), clientObserver.value());
+ QCOMPARE(hostObserver.value(), expectedSourceLocations);
+ QCOMPARE(hostSrcLocationsChanged, 2);
+ QCOMPARE(clientSrcLocationsChanged, 2);
+
+ // Test source removal
+ host->disableRemoting(&e1);
+ expectedSourceLocations.remove(engine1);
+ QSignalSpy srcRemovedHostSpy(host->registry(), &QRemoteObjectRegistry::remoteObjectRemoved);
+ QSignalSpy srcRemovedClientSpy(client->registry(),
+ &QRemoteObjectRegistry::remoteObjectRemoved);
+
+ QTRY_COMPARE(srcRemovedHostSpy.count(), 1);
+ QTRY_COMPARE(srcRemovedClientSpy.count(), 1);
+ QCOMPARE(hostObserver.value(), host->registry()->sourceLocations());
+ QCOMPARE(clientObserver.value(), client->registry()->sourceLocations());
+ QCOMPARE(hostObserver.value(), clientObserver.value());
+ QCOMPARE(hostObserver.value(), expectedSourceLocations);
+ QCOMPARE(hostSrcLocationsChanged, 3);
+ QCOMPARE(clientSrcLocationsChanged, 3);
+ }
+
+ void registryAddedTest()
+ {
+ QFETCH_GLOBAL(QUrl, registryUrl);
+ if (registryUrl.isEmpty())
+ QSKIP("Skipping registry tests for external QIODevice types.");
+ setupRegistry();
+
+ setupHost(true);
+
+ setupClient(true);
+
+ QScopedPointer<EngineReplica> regBase, regNamed;
+ QScopedPointer<QRemoteObjectDynamicReplica> regDynamic, regDynamicNamed;
+
+ int regAdded = 0;
+ connect(client->registry(), &QRemoteObjectRegistry::remoteObjectAdded, [&](QRemoteObjectSourceLocation entry)
+ {
+ if (entry.first == QLatin1String("Engine")) {
+ ++regAdded;
+ //Add regular replica first, then dynamic one
+ regBase.reset(client->acquire<EngineReplica>());
+ regDynamic.reset(client->acquireDynamic(QStringLiteral("Engine")));
+ }
+ if (entry.first == QLatin1String("MyTestEngine")) {
+ regAdded += 2;
+ //Now add dynamic replica first, then regular one
+ regDynamicNamed.reset(client->acquireDynamic(QStringLiteral("MyTestEngine")));
+ regNamed.reset(client->acquire<EngineReplica>(QStringLiteral("MyTestEngine")));
+ }
+ });
+
+ QSignalSpy addedSpy(client->registry(), &QRemoteObjectRegistry::remoteObjectAdded);
+
+ Engine e;
+ e.setRpm(1111);
+ host->enableRemoting(&e);
+ Engine e2;
+ e2.setRpm(2222);
+ host->enableRemoting(&e2, QStringLiteral("MyTestEngine"));
+ while (regAdded < 3) {
+ addedSpy.wait(100);
+ }
+ regBase->waitForSource(100);
+ regNamed->waitForSource(100);
+ regDynamic->waitForSource(100);
+ regDynamicNamed->waitForSource(100);
+ QVERIFY(regBase->isInitialized());
+ QCOMPARE(regBase->rpm(),e.rpm());
+ QVERIFY(regNamed->isInitialized());
+ QCOMPARE(regNamed->rpm(),e2.rpm());
+
+ QVERIFY(regDynamic->isInitialized());
+ const QMetaObject *metaObject = regDynamic->metaObject();
+
+ const int propertyIndex = metaObject->indexOfProperty("rpm");
+ QVERIFY(propertyIndex >= 0);
+ const QMetaProperty property = metaObject->property(propertyIndex);
+ QVERIFY(property.isValid());
+
+ QCOMPARE(property.read(regDynamic.data()).toInt(),e.rpm());
+
+ QVERIFY(regDynamicNamed->isInitialized());
+ QCOMPARE(property.read(regDynamicNamed.data()).toInt(),e2.rpm());
+
+ QVERIFY(host->disableRemoting(&e));
+ QVERIFY(host->disableRemoting(&e2));
+ }
+
+ void registryTest()
+ {
+ QFETCH_GLOBAL(QUrl, registryUrl);
+ if (registryUrl.isEmpty())
+ QSKIP("Skipping registry tests for external QIODevice types.");
+ setupRegistry();
+ TcpDataCenterSimpleSource source1;
+ source1.setData1(5);
+ source1.setData2(5.0);
+ source1.setData3(QStringLiteral("tcp"));
+ source1.setData4(QList<int> { 1, 2, 3, 4, 5 });
+ registry->enableRemoting(&source1);
+
+ setupHost(true);
+ LocalDataCenterSimpleSource source2;
+ source2.setData1(5);
+ source2.setData2(5.0);
+ source2.setData3(QStringLiteral("local"));
+ source2.setData4(QList<int> { 1, 2, 3, 4, 5 });
+ host->enableRemoting(&source2);
+ QVERIFY(host->waitForRegistry(1000));
+
+ setupClient(true);
+
+ const QScopedPointer<TcpDataCenterReplica> tcpCentre(client->acquire<TcpDataCenterReplica>());
+ const QScopedPointer<LocalDataCenterReplica> localCentre(client->acquire<LocalDataCenterReplica>());
+ QTRY_VERIFY(localCentre->waitForSource(100));
+ QTRY_VERIFY(tcpCentre->waitForSource(100));
+
+ QCOMPARE(client->registry()->sourceLocations(), host->registry()->sourceLocations());
+ QCOMPARE(client->registry()->sourceLocations(), registry->registry()->sourceLocations());
+ QTRY_VERIFY(localCentre->isInitialized());
+ QTRY_VERIFY(tcpCentre->isInitialized());
+
+ const QList<int> expected = { 1, 2, 3, 4, 5 };
+ QCOMPARE(tcpCentre->data1(), 5 );
+ QCOMPARE(tcpCentre->data2(), 5.0);
+ QCOMPARE(tcpCentre->data3(), QStringLiteral("tcp"));
+ QCOMPARE(tcpCentre->data4(), expected);
+
+ QCOMPARE(localCentre->data1(), 5);
+ QCOMPARE(localCentre->data2(), 5.0);
+ QCOMPARE(localCentre->data3(), QStringLiteral("local"));
+ QCOMPARE(localCentre->data4(), expected);
+ }
+
+ void invalidUrlsTest()
+ {
+ QFETCH_GLOBAL(QUrl, hostUrl);
+ QFETCH_GLOBAL(QUrl, registryUrl);
+ const QUrl invalidUrl;
+ {
+ QRemoteObjectHost _host(invalidUrl, registryUrl);
+ SET_NODE_NAME(_host);
+ const bool res = _host.waitForRegistry(3000);
+ QVERIFY(!res);
+ }
+
+ {
+ QRemoteObjectHost _host(hostUrl, invalidUrl);
+ SET_NODE_NAME(_host);
+ const bool res = _host.waitForRegistry(3000);
+ QVERIFY(!res);
+ }
+
+ {
+ QRemoteObjectHost _host(invalidUrl, invalidUrl);
+ SET_NODE_NAME(_host);
+ const bool res = _host.waitForRegistry(3000);
+ QVERIFY(!res);
+ }
+ }
+
+ void noRegistryTest()
+ {
+ QFETCH_GLOBAL(QUrl, registryUrl);
+ if (registryUrl.isEmpty())
+ QSKIP("Skipping registry tests for external QIODevice types.");
+ setupHost(true);
+ const bool res = host->waitForRegistry(3000);
+ QVERIFY(!res);
+ QCOMPARE(host->registry()->isInitialized(), false);
+ const QScopedPointer<Engine> localEngine(new Engine);
+ host->enableRemoting(localEngine.data());
+ QCOMPARE(host->registry()->sourceLocations().keys().isEmpty(), true);
+ }
+
+ void delayedRegistryTest()
+ {
+ QFETCH_GLOBAL(QUrl, hostUrl);
+ QFETCH_GLOBAL(QUrl, registryUrl);
+ if (registryUrl.isEmpty())
+ QSKIP("Skipping registry tests for external QIODevice types.");
+ setupClient(true);
+
+ // create a replica before the registry host started
+ // to check whether it gets valid later on
+ const QScopedPointer<EngineReplica> engine_r(client->acquire<EngineReplica>());
+ Q_SET_OBJECT_NAME(engine_r.data());
+ QTRY_VERIFY(!engine_r->waitForSource(100));
+
+ setupHost(true);
+ const bool res = host->waitForRegistry(3000);
+ QVERIFY(!res);
+ QCOMPARE(host->registry()->isInitialized(), false);
+
+ const QScopedPointer<Engine> localEngine(new Engine);
+ host->enableRemoting(localEngine.data());
+ QCOMPARE(host->registry()->sourceLocations().keys().isEmpty(), true);
+
+ QSignalSpy spy(host->registry(), &QRemoteObjectRegistry::initialized);
+ QSignalSpy addedSpy(host->registry(), &QRemoteObjectRegistry::remoteObjectAdded);
+ setupRegistry();
+ bool added = addedSpy.wait();
+ QVERIFY(spy.count() > 0);
+ QCOMPARE(added, true);
+ QCOMPARE(host->registry()->sourceLocations().keys().isEmpty(), false);
+ QCOMPARE(host->registry()->sourceLocations().keys().at(0), QStringLiteral("Engine"));
+ QCOMPARE(host->registry()->sourceLocations().value(QStringLiteral("Engine")).hostUrl, hostUrl);
+
+ // the replicate should be valid now
+ QTRY_VERIFY(engine_r->isInitialized());
+ QTRY_VERIFY(engine_r->isReplicaValid());
+
+ //This should produce a warning...
+ registry->enableRemoting(localEngine.data());
+ QVERIFY(host->registry()->sourceLocations().value(QStringLiteral("Engine")).hostUrl != registryUrl);
+ }
+
+ void defaultValueTest()
+ {
+ setupHost();
+ Engine e;
+ host->enableRemoting(&e);
+
+ setupClient();
+
+ const QScopedPointer<EngineReplica> engine_r(client->acquire<EngineReplica>());
+ engine_r->waitForSource();
+ QCOMPARE(engine_r->cylinders(), 4);
+ }
+
+ void notifyTest()
+ {
+ setupHost();
+ Engine e;
+ host->enableRemoting(&e);
+
+ setupClient();
+
+ const QScopedPointer<EngineReplica> engine_r(client->acquire<EngineReplica>());
+ QSignalSpy spy(engine_r.data(), &EngineReplica::rpmChanged);
+ e.setRpm(2345);
+
+ spy.wait();
+ QCOMPARE(spy.count(), 1);
+ const QList<QVariant> &arguments = spy.first();
+ bool ok;
+ int res = arguments.at(0).toInt(&ok);
+ QVERIFY(ok);
+ QCOMPARE(res, e.rpm());
+ QCOMPARE(engine_r->rpm(), e.rpm());
+ }
+
+ void dynamicNotifyTest()
+ {
+ setupHost();
+ Engine e;
+ host->enableRemoting(&e);
+
+ setupClient();
+
+ QSignalSpy spy(this, &tst_Integration::forwardResult);
+ QScopedPointer<QRemoteObjectDynamicReplica> engine_dr(client->acquireDynamic(QStringLiteral("Engine")));
+ connect(engine_dr.data(), &QRemoteObjectDynamicReplica::initialized, [&]()
+ {
+ const QMetaObject *metaObject = engine_dr->metaObject();
+ const int propIndex = metaObject->indexOfProperty("rpm");
+ QVERIFY(propIndex >= 0);
+ const QMetaProperty mp = metaObject->property(propIndex);
+ QVERIFY(connect(engine_dr.data(), QByteArray(QByteArrayLiteral("2")+mp.notifySignal().methodSignature().constData()), this, SIGNAL(forwardResult(int))));
+ });
+ e.setRpm(3456);
+ spy.wait();
+ QCOMPARE(spy.count(), 1);
+ const QList<QVariant> &arguments = spy.first();
+ bool ok;
+ int res = arguments.at(0).toInt(&ok);
+ QVERIFY(ok);
+ QCOMPARE(res, e.rpm());
+ }
+
+ void slotTest()
+ {
+ setupHost();
+ Engine e;
+ host->enableRemoting(&e);
+
+ setupClient();
+ e.setStarted(false);
+
+ const QScopedPointer<EngineReplica> engine_r(client->acquire<EngineReplica>());
+ QEventLoop loop;
+ QTimer::singleShot(100, &loop, &QEventLoop::quit);
+ connect(engine_r.data(), &EngineReplica::initialized, &loop, &QEventLoop::quit);
+ if (!engine_r->isInitialized())
+ loop.exec();
+ QCOMPARE(engine_r->started(), false);
+
+ QRemoteObjectPendingReply<bool> reply = engine_r->start();
+ QCOMPARE(reply.error(), QRemoteObjectPendingCall::InvalidMessage);
+ QVERIFY(reply.waitForFinished());
+ QVERIFY(reply.isFinished());
+ QCOMPARE(reply.returnValue(), true);
+ QCOMPARE(reply.error(), QRemoteObjectPendingCall::NoError);
+
+ QCOMPARE(engine_r->started(), true);
+ }
+
+ void slotTestWithWatcher()
+ {
+ setupHost();
+ Engine e;
+ host->enableRemoting(&e);
+
+ setupClient();
+ e.setStarted(false);
+
+ const QScopedPointer<EngineReplica> engine_r(client->acquire<EngineReplica>());
+ QEventLoop loop;
+ QTimer::singleShot(100, &loop, &QEventLoop::quit);
+ connect(engine_r.data(), &EngineReplica::initialized, &loop, &QEventLoop::quit);
+ if (!engine_r->isInitialized())
+ loop.exec();
+ QCOMPARE(engine_r->started(), false);
+
+ QRemoteObjectPendingReply<bool> reply = engine_r->start();
+ QCOMPARE(reply.error(), QRemoteObjectPendingCall::InvalidMessage);
+
+ QRemoteObjectPendingCallWatcher watcher(reply);
+ QSignalSpy spy(&watcher, &QRemoteObjectPendingCallWatcher::finished);
+ spy.wait();
+ QCOMPARE(spy.count(), 1);
+
+ QVERIFY(reply.isFinished());
+ QCOMPARE(reply.returnValue(), true);
+ QCOMPARE(engine_r->started(), true);
+ }
+
+ void slotTestDynamicReplica()
+ {
+ setupHost();
+ Engine e;
+ host->enableRemoting(&e);
+
+ setupClient();
+ e.setStarted(false);
+
+ const QScopedPointer<QRemoteObjectDynamicReplica> engine_r(client->acquireDynamic(QStringLiteral("Engine")));
+ Q_ASSERT(engine_r);
+ QEventLoop loop;
+ QTimer::singleShot(100, &loop, &QEventLoop::quit);
+ connect(engine_r.data(), &EngineReplica::initialized, &loop, &QEventLoop::quit);
+ if (!engine_r->isInitialized())
+ loop.exec();
+
+ const QMetaObject *metaObject = engine_r->metaObject();
+ const int propIndex = metaObject->indexOfProperty("started");
+ QVERIFY(propIndex >= 0);
+ const QMetaProperty property = metaObject->property(propIndex);
+ bool started = property.read(engine_r.data()).value<bool>();
+ QCOMPARE(started, false);
+
+ const int methodIndex = metaObject->indexOfMethod("start()");
+ QVERIFY(methodIndex >= 0);
+ const QMetaMethod method = metaObject->method(methodIndex);
+ QRemoteObjectPendingCall call;
+ QVERIFY(method.invoke(engine_r.data(), Q_RETURN_ARG(QRemoteObjectPendingCall, call)));
+ QCOMPARE(call.error(), QRemoteObjectPendingCall::InvalidMessage);
+ QVERIFY(call.waitForFinished());
+ QVERIFY(call.isFinished());
+ QCOMPARE(call.returnValue().metaType(), QMetaType::fromType<bool>());
+ QCOMPARE(call.returnValue().toBool(), true);
+ started = property.read(engine_r.data()).value<bool>();
+ QCOMPARE(started, true);
+ }
+
+ void slotTestDynamicReplicaWithArguments()
+ {
+ setupHost();
+ Engine e;
+ host->enableRemoting(&e);
+
+ setupClient();
+
+ const QScopedPointer<QRemoteObjectDynamicReplica> engine_r(client->acquireDynamic(QStringLiteral("Engine")));
+ Q_ASSERT(engine_r);
+ bool ok = engine_r->waitForSource();
+ QVERIFY(ok);
+ const QMetaObject *metaObject = engine_r->metaObject();
+
+ int methodIndex = metaObject->indexOfMethod("setMyTestString(QString)");
+ QVERIFY(methodIndex >= 0);
+ QMetaMethod method = metaObject->method(methodIndex);
+ QVERIFY(method.isValid());
+
+ // The slot has no return-value, calling it with a Q_RETURN_ARG should fail.
+ QRemoteObjectPendingCall setCall;
+ QString s = QLatin1String("Hello World 1");
+ QVERIFY(!method.invoke(engine_r.data(), Q_RETURN_ARG(QRemoteObjectPendingCall, setCall), Q_ARG(QString, s)));
+ QVERIFY(!setCall.waitForFinished());
+ QVERIFY(!setCall.isFinished());
+ QCOMPARE(setCall.error(), QRemoteObjectPendingCall::InvalidMessage);
+
+ // Now call the method without return-value, that should succeed.
+ s = QLatin1String("Hello World 2");
+ QVERIFY(method.invoke(engine_r.data(), Q_ARG(QString, s)));
+
+ // Verify that the passed argument was proper set.
+ methodIndex = metaObject->indexOfMethod("myTestString()");
+ QVERIFY(methodIndex >= 0);
+ method = metaObject->method(methodIndex);
+ QRemoteObjectPendingCall getCall;
+ QVERIFY(method.invoke(engine_r.data(), Q_RETURN_ARG(QRemoteObjectPendingCall, getCall)));
+ QVERIFY(getCall.waitForFinished());
+ QVERIFY(getCall.isFinished());
+ QCOMPARE(getCall.error(), QRemoteObjectPendingCall::NoError);
+ QCOMPARE(getCall.returnValue().metaType(), QMetaType::fromType<QString>());
+ QCOMPARE(getCall.returnValue().toString(), s);
+ }
+
+ void expapiTestDynamicReplica()
+ {
+ setupHost();
+ Engine e;
+ host->enableRemoting(&e);
+
+ setupClient();
+
+ const QScopedPointer<QRemoteObjectDynamicReplica> engine_r(client->acquireDynamic(QStringLiteral("Engine")));
+ const QMetaObject *metaObject = engine_r->metaObject();
+ const int propIndex = metaObject->indexOfProperty("purchasedPart");
+ QVERIFY(propIndex < 0);
+ const int methodIndex = metaObject->indexOfMethod("setpurchasedPart(bool)");
+ QVERIFY(methodIndex < 0);
+ }
+
+ void slotTestInProcess()
+ {
+ setupHost();
+ Engine e;
+ host->enableRemoting(&e);
+ e.setStarted(false);
+
+ const QScopedPointer<EngineReplica> engine_r(host->acquire<EngineReplica>());
+ engine_r->waitForSource();
+ QCOMPARE(engine_r->started(), false);
+
+ QRemoteObjectPendingReply<bool> reply = engine_r->start();
+ QVERIFY(reply.waitForFinished());
+ QVERIFY(reply.isFinished());
+ QCOMPARE(reply.returnValue(), true);
+ QCOMPARE(reply.error(), QRemoteObjectPendingCall::NoError);
+
+ QCOMPARE(engine_r->started(), true);
+ }
+
+ void slotTestWithUnnormalizedSignature()
+ {
+ setupHost();
+ Engine e;
+ host->enableRemoting(&e);
+
+ setupClient();
+
+ const QScopedPointer<EngineReplica> engine_r(client->acquire<EngineReplica>());
+ engine_r->waitForSource();
+
+ engine_r->unnormalizedSignature(0, 0);
+ }
+
+ void setterTest()
+ {
+ setupHost();
+ Engine e(6);
+ QCOMPARE(e.cylinders(), 6);
+ host->enableRemoting(&e);
+
+ setupClient();
+
+ const QScopedPointer<EngineReplica> engine_r(client->acquire<EngineReplica>());
+ QCOMPARE(engine_r->cylinders(), 4); // Default value
+ engine_r->waitForSource();
+ QCOMPARE(engine_r->cylinders(), 6);
+ QSignalSpy spy(engine_r.data(), &EngineReplica::rpmChanged);
+ engine_r->setRpm(42);
+ spy.wait();
+ QCOMPARE(spy.count(), 1);
+ QCOMPARE(engine_r->rpm(), 42);
+ }
+
+ void pushTest()
+ {
+ setupHost();
+ Engine e;
+ host->enableRemoting(&e);
+
+ setupClient();
+
+ const QScopedPointer<EngineReplica> engine_r(client->acquire<EngineReplica>());
+ engine_r->waitForSource();
+ QCOMPARE(engine_r->started(), false);
+ QSignalSpy spy(engine_r.data(), &EngineReplica::startedChanged);
+ engine_r->pushStarted(true);
+ spy.wait();
+ QCOMPARE(spy.count(), 1);
+ QCOMPARE(engine_r->started(), true);
+ }
+
+ void dynamicSetterTest()
+ {
+ setupHost();
+ Engine e(6);
+ QCOMPARE(e.cylinders(), 6);
+ host->enableRemoting(&e);
+
+ setupClient();
+
+ const QScopedPointer<QRemoteObjectDynamicReplica> engine_dr(client->acquireDynamic(QStringLiteral("Engine")));
+ engine_dr->waitForSource();
+ const QMetaObject *metaObject = engine_dr->metaObject();
+ const QMetaProperty const_mp = metaObject->property(metaObject->indexOfProperty("cylinders"));
+ QCOMPARE(const_mp.read(engine_dr.data()).toInt(), 6);
+ const int propIndex = metaObject->indexOfProperty("rpm");
+ const QMetaProperty mp = metaObject->property(propIndex);
+ QSignalSpy spy(engine_dr.data(), QByteArray(QByteArrayLiteral("2")+mp.notifySignal().methodSignature().constData()));
+ mp.write(engine_dr.data(), 44);
+ spy.wait();
+ QCOMPARE(spy.count(), 1);
+ QCOMPARE(mp.read(engine_dr.data()).toInt(), 44);
+ }
+
+ void slotWithParameterTest()
+ {
+ setupHost();
+ Engine e;
+ host->enableRemoting(&e);
+ e.setRpm(0);
+
+ setupClient();
+
+ const QScopedPointer<EngineReplica> engine_r(client->acquire<EngineReplica>());
+ engine_r->waitForSource();
+ QCOMPARE(engine_r->rpm(), 0);
+
+ QSignalSpy spy(engine_r.data(), &EngineReplica::rpmChanged);
+ engine_r->increaseRpm(1000);
+ spy.wait();
+ QCOMPARE(spy.count(), 1);
+ QCOMPARE(engine_r->rpm(), 1000);
+ }
+
+ void slotWithUserReturnTypeTest() {
+ setupHost();
+ Engine e;
+ host->enableRemoting(&e);
+
+ setupClient();
+
+ e.setTemperature(Temperature(400, QStringLiteral("Kelvin")));
+
+ const QScopedPointer<EngineReplica> engine_r(client->acquire<EngineReplica>());
+ engine_r->waitForSource();
+ QRemoteObjectPendingReply<Temperature> pendingReply = engine_r->temperature();
+ pendingReply.waitForFinished();
+ Temperature temperature = pendingReply.returnValue();
+ QCOMPARE(temperature, Temperature(400, QStringLiteral("Kelvin")));
+ }
+
+ void sequentialReplicaTest()
+ {
+ setupHost();
+ Engine e;
+ host->enableRemoting(&e);
+
+ setupClient();
+
+ e.setRpm(3456);
+
+ QScopedPointer<EngineReplica> engine_r(client->acquire<EngineReplica>());
+ engine_r->waitForSource();
+ QCOMPARE(engine_r->rpm(), e.rpm());
+
+ engine_r.reset(client->acquire<EngineReplica>());
+ engine_r->waitForSource();
+ QCOMPARE(engine_r->rpm(), e.rpm());
+ }
+
+ void doubleReplicaTest()
+ {
+ setupHost();
+ Engine e;
+ host->enableRemoting(&e);
+ e.setRpm(3412);
+
+ setupClient();
+
+ const QScopedPointer<EngineReplica> engine_r1(client->acquire< EngineReplica >());
+ const QScopedPointer<EngineReplica> engine_r2(client->acquire< EngineReplica >());
+
+ engine_r1->waitForSource();
+ engine_r2->waitForSource();
+
+ QCOMPARE(engine_r1->rpm(), e.rpm());
+ QCOMPARE(engine_r2->rpm(), e.rpm());
+ }
+
+ // verify that our second replica emits "Changed" signals when initialized
+ void doubleReplicaTest2()
+ {
+ setupHost();
+ Engine e;
+ host->enableRemoting(&e);
+ e.setRpm(3412);
+
+ setupClient();
+
+ const QScopedPointer<EngineReplica> engine_r1(client->acquire< EngineReplica >());
+ QSignalSpy spy_r1(engine_r1.data(), &EngineReplica::rpmChanged);
+ engine_r1->waitForSource();
+ QCOMPARE(engine_r1->rpm(), e.rpm());
+ QCOMPARE(spy_r1.count(), 1);
+
+ // NOTE: A second replica will have initialized and notify signals emitted as part of acquire,
+ // which leads to different semantics for first and second replicas. Specifically, there is no
+ // way to hook in to initialized and the initial notify signals. We should consider changing this.
+ const QScopedPointer<EngineReplica> engine_r2(client->acquire< EngineReplica >());
+// QSignalSpy spy_r2(engine_r2.data(), &EngineReplica::rpmChanged);
+// engine_r2->waitForSource();
+ QCOMPARE(engine_r2->rpm(), e.rpm());
+// QCOMPARE(spy_r2.count(), 1);
+ }
+
+ void twoReplicaTest() {
+ setupHost();
+ Engine e;
+ Speedometer s;
+ host->enableRemoting(&e);
+ host->enableRemoting(&s);
+
+ setupClient();
+
+ e.setRpm(1234);
+ s.setMph(70);
+
+ const QScopedPointer<EngineReplica> engine_r(client->acquire<EngineReplica>());
+ engine_r->waitForSource();
+ const QScopedPointer<SpeedometerReplica> speedometer_r(client->acquire<SpeedometerReplica>());
+ speedometer_r->waitForSource();
+
+ QCOMPARE(engine_r->rpm(), e.rpm());
+ QCOMPARE(speedometer_r->mph(), s.mph());
+ }
+
+ void rawDynamicReplicaTest()
+ {
+ setupHost();
+ TestDynamic source;
+ host->enableRemoting(&source, "TestDynamic");
+
+ setupClient();
+
+ const QScopedPointer<QRemoteObjectDynamicReplica> replica(client->acquireDynamic(QStringLiteral("TestDynamic")));
+ replica->waitForSource();
+ QVERIFY(replica->isInitialized());
+
+ QSignalSpy spy(replica.data(), SIGNAL(valueChanged()));
+
+ const QMetaObject *metaObject = replica->metaObject();
+ const int propIndex = metaObject->indexOfProperty("value");
+ QVERIFY(propIndex != -1);
+ const int signalIndex = metaObject->indexOfSignal("valueChanged()");
+ QVERIFY(signalIndex != -1);
+
+ // replica gets source change
+ source.setValue(1);
+ QTRY_COMPARE(spy.count(), 1);
+ QCOMPARE(replica->property("value"), QVariant(1));
+
+ // source gets replica change
+ replica->setProperty("value", 2);
+ QTRY_COMPARE(replica->property("value"), QVariant(2));
+ QCOMPARE(source.value(), 2);
+
+ // test parent NOTIFY
+ QSignalSpy otherSpy(replica.data(), SIGNAL(otherValueChanged()));
+
+ const int baseSignalIndex = metaObject->indexOfSignal("otherValueChanged()");
+ QVERIFY(baseSignalIndex != -1);
+
+ // replica gets source change
+ source.setOtherValue(1);
+ QTRY_COMPARE(otherSpy.count(), 1);
+ QCOMPARE(replica->property("otherValue"), QVariant(1));
+
+ // source gets replica change
+ replica->setProperty("otherValue", 2);
+ QTRY_COMPARE(replica->property("otherValue"), QVariant(2));
+ QCOMPARE(source.otherValue(), 2);
+ }
+
+ void dynamicReplicaTest()
+ {
+ setupHost();
+ TcpDataCenterSimpleSource t;
+ LocalDataCenterSimpleSource l;
+ host->enableRemoting(&t);
+ host->enableRemoting(&l);
+
+ setupClient();
+
+ const QScopedPointer<QRemoteObjectDynamicReplica> rep1(client->acquireDynamic(QStringLiteral("TcpDataCenter")));
+ const QScopedPointer<QRemoteObjectDynamicReplica> rep2(client->acquireDynamic(QStringLiteral("TcpDataCenter")));
+ const QScopedPointer<QRemoteObjectDynamicReplica> rep3(client->acquireDynamic(QStringLiteral("LocalDataCenter")));
+ rep1->waitForSource();
+ rep2->waitForSource();
+ rep3->waitForSource();
+ const QMetaObject *metaTcpRep1 = rep1->metaObject();
+ const QMetaObject *metaLocalRep1 = rep3->metaObject();
+ const QMetaObject *metaTcpSource = t.metaObject();
+ const QMetaObject *metaLocalSource = l.metaObject();
+ QVERIFY(rep1->isInitialized());
+ QVERIFY(rep2->isInitialized());
+ QVERIFY(rep3->isInitialized());
+
+ for (int i = 0; i < metaTcpRep1->propertyCount(); ++i)
+ {
+ const QMetaProperty propLhs = metaTcpRep1->property(i);
+ if (qstrcmp(propLhs.name(), "isReplicaValid") == 0 || qstrcmp(propLhs.name(), "state") == 0 || qstrcmp(propLhs.name(), "node") == 0) //Ignore properties only on the Replica side
+ continue;
+ const QMetaProperty propRhs = metaTcpSource->property(metaTcpSource->indexOfProperty(propLhs.name()));
+ if (propLhs.notifySignalIndex() == -1)
+ QCOMPARE(propRhs.hasNotifySignal(), false);
+ else {
+ QCOMPARE(propRhs.notifySignalIndex() != -1, true);
+ QCOMPARE(metaTcpRep1->method(propLhs.notifySignalIndex()).name(), metaTcpSource->method(propRhs.notifySignalIndex()).name());
+ }
+ QCOMPARE(propLhs.read(rep1.data()), propRhs.read(&t));
+ }
+ for (int i = 0; i < metaLocalRep1->propertyCount(); ++i )
+ {
+ const QMetaProperty propLhs = metaLocalRep1->property(i);
+ if (qstrcmp(propLhs.name(), "isReplicaValid") == 0 || qstrcmp(propLhs.name(), "state") == 0 || qstrcmp(propLhs.name(), "node") == 0) //Ignore properties only on the Replica side
+ continue;
+ const QMetaProperty propRhs = metaLocalSource->property(metaTcpSource->indexOfProperty(propLhs.name()));
+ if (propLhs.notifySignalIndex() == -1)
+ QCOMPARE(propRhs.hasNotifySignal(), false);
+ else {
+ QCOMPARE(propRhs.notifySignalIndex() != -1, true);
+ QCOMPARE(metaTcpRep1->method(propLhs.notifySignalIndex()).name(), metaTcpSource->method(propRhs.notifySignalIndex()).name());
+ }
+ QCOMPARE(propLhs.read(rep3.data()), propRhs.read(&l));
+ }
+
+ }
+
+ void apiTest()
+ {
+ setupHost();
+ Engine e;
+ host->enableRemoting<EngineSourceAPI>(&e);
+ e.setRpm(1234);
+
+ setupClient();
+
+ const QScopedPointer<EngineReplica> engine_r(client->acquire<EngineReplica>());
+ engine_r->waitForSource();
+
+ QCOMPARE(engine_r->rpm(), e.rpm());
+ }
+
+ void apiInProcTest()
+ {
+ setupHost();
+ Engine e;
+ host->enableRemoting<EngineSourceAPI>(&e);
+ e.setRpm(1234);
+
+ const QScopedPointer<EngineReplica> engine_r_inProc(host->acquire<EngineReplica>());
+ engine_r_inProc->waitForSource();
+
+ QCOMPARE(engine_r_inProc->rpm(), e.rpm());
+ }
+
+ void errorSignalTest()
+ {
+ QRemoteObjectNode _client;
+ Q_SET_OBJECT_NAME(_client);
+ QSignalSpy errorSpy(&_client, &QRemoteObjectNode::error);
+ QVERIFY(!_client.connectToNode(QUrl(QLatin1String("invalid:invalid"))));
+ QCOMPARE(errorSpy.count(), 1);
+ auto emittedErrorCode = errorSpy.first().at(0).value<QRemoteObjectNode::ErrorCode>();
+ QCOMPARE(emittedErrorCode, QRemoteObjectNode::RegistryNotAcquired);
+ QCOMPARE(_client.lastError(), QRemoteObjectNode::RegistryNotAcquired);
+ }
+
+ void clientBeforeServerTest() {
+ setupClient();
+ const QScopedPointer<EngineReplica> engine_d(client->acquire<EngineReplica>());
+
+ setupHost();
+ Engine e;
+ host->enableRemoting<EngineSourceAPI>(&e);
+ QSignalSpy spy(engine_d.data(), &EngineReplica::rpmChanged);
+ e.setRpm(50);
+
+ spy.wait();
+ QCOMPARE(spy.count(), 1);
+
+ QCOMPARE(engine_d->rpm(), e.rpm());
+ }
+
+ void largeDataTest()
+ {
+ TestLargeData t;
+ setupHost();
+ host->enableRemoting(&t, QStringLiteral("large"));
+
+ setupClient();
+ const QScopedPointer<QRemoteObjectDynamicReplica> rep(client->acquireDynamic(QStringLiteral("large")));
+ rep->waitForSource();
+ QVERIFY(rep->isInitialized());
+ const QMetaObject *metaObject = rep->metaObject();
+ const int sigIndex = metaObject->indexOfSignal("send(QByteArray)");
+ QVERIFY(sigIndex != -1);
+ const QMetaMethod mm = metaObject->method(sigIndex);
+ QSignalSpy spy(rep.data(), QByteArray(QByteArrayLiteral("2")+mm.methodSignature().constData()));
+ const QByteArray data(16384,'y');
+ emit t.send(data);
+ spy.wait();
+ QCOMPARE(spy.count(), 1);
+ const QList<QVariant> &arguments = spy.first();
+ QVERIFY(arguments.at(0).toByteArray() == data);
+ QVERIFY(host->disableRemoting(&t));
+ }
+
+ void PODTest()
+ {
+ setupHost();
+
+ setupClient();
+
+ MyPOD shouldPass(1, 2.0, QStringLiteral("pass"));
+ MyPOD shouldFail(1, 2.0, QStringLiteral("fail"));
+ MyClassSimpleSource m;
+ m.setMyPOD(shouldPass);
+ host->enableRemoting(&m);
+ const QScopedPointer<MyClassReplica> myclass_r(client->acquire<MyClassReplica>());
+ myclass_r->waitForSource();
+
+ QVERIFY(myclass_r->myPOD() == m.myPOD());
+ QVERIFY(myclass_r->myPOD() != shouldFail);
+ }
+
+ void SchemeTest()
+ {
+ QFETCH_GLOBAL(QUrl, hostUrl);
+ QFETCH_GLOBAL(QUrl, registryUrl);
+ QRemoteObjectHost valid(hostUrl);
+ QVERIFY(valid.lastError() == QRemoteObjectNode::NoError);
+ QRemoteObjectHost invalid(QUrl(QLatin1String("invalid:invalid")));
+ QVERIFY(invalid.lastError() == QRemoteObjectNode::HostUrlInvalid);
+ QRemoteObjectHost validExternal(QUrl(QLatin1String("invalid:invalid")), registryUrl, QRemoteObjectHost::AllowExternalRegistration);
+ QVERIFY(validExternal.lastError() == QRemoteObjectNode::NoError);
+ QRemoteObjectNode invalidRegistry(QUrl(QLatin1String("invalid:invalid")));
+ QVERIFY(invalidRegistry.lastError() == QRemoteObjectNode::RegistryNotAcquired);
+ }
+
+#if QT_CONFIG(process) && (defined(Q_OS_LINUX) || defined(Q_OS_DARWIN))
+ void localServerConnectionTest()
+ {
+ QFETCH_GLOBAL(QUrl, hostUrl);
+ if (hostUrl.scheme() != QRemoteObjectStringLiterals::local())
+ QSKIP("Skipping 'local' specific backend for non-local test.");
+ const auto progName = TestUtils::findExecutable("localsockettestserver", "/localsockettestserver");
+
+ //create a fake socket as killing doesn't produce a necessarily unusable socket
+ QFile fake(QDir::temp().absoluteFilePath(QStringLiteral("crashMe")));
+ fake.remove();
+ QVERIFY(fake.open(QFile::Truncate | QFile::WriteOnly));
+ QFileInfo info(QDir::temp().absoluteFilePath(QStringLiteral("crashMe")));
+ QVERIFY(info.exists());
+
+ QRemoteObjectNode localSocketTestClient;
+ const QUrl connection = QUrl(QStringLiteral("local:crashMe"));
+ const QString objectname = QStringLiteral("connectme");
+ localSocketTestClient.connectToNode(connection);
+ QVERIFY(localSocketTestClient.lastError() == QRemoteObjectNode::NoError);
+ QScopedPointer<QRemoteObjectDynamicReplica> replica;
+ replica.reset(localSocketTestClient.acquireDynamic(objectname));
+
+ QProcess testServer;
+ testServer.start(progName, QStringList());
+ QVERIFY(testServer.waitForStarted());
+ QVERIFY(localSocketTestClient.lastError() == QRemoteObjectNode::NoError);
+ replica->waitForSource(1000);
+ QVERIFY(replica->isInitialized());
+ testServer.terminate();
+ QVERIFY(testServer.waitForFinished());
+ }
+ // Tests to take over an existing socket if its still valid
+ void localServerConnectionTest2()
+ {
+ QFETCH_GLOBAL(QUrl, hostUrl);
+ if (hostUrl.scheme() != QRemoteObjectStringLiterals::local())
+ QSKIP("Skipping 'local' specific backend for non-local test.");
+ const auto progName = TestUtils::findExecutable("localsockettestserver", "/localsockettestserver");
+
+ QProcess testServer;
+ testServer.start(progName, QStringList());
+ QVERIFY(testServer.waitForStarted());
+ QFileInfo info(QDir::temp().absoluteFilePath(QStringLiteral("crashMe")));
+ QVERIFY(info.exists());
+ testServer.kill();
+ testServer.waitForFinished();
+ QVERIFY(info.exists());
+
+ QRemoteObjectNode localSocketTestClient;
+ const QUrl connection = QUrl(QStringLiteral("local:crashMe"));
+ const QString objectname = QStringLiteral("connectme");
+ localSocketTestClient.connectToNode(connection);
+ QVERIFY(localSocketTestClient.lastError() == QRemoteObjectNode::NoError);
+ QScopedPointer<QRemoteObjectDynamicReplica> replica;
+ replica.reset(localSocketTestClient.acquireDynamic(objectname));
+
+ testServer.start(progName, QStringList());
+ QVERIFY(testServer.waitForStarted());
+ QVERIFY(localSocketTestClient.lastError() == QRemoteObjectNode::NoError);
+ replica->waitForSource(1000);
+ QVERIFY(replica->isInitialized());
+ testServer.terminate();
+ QVERIFY(testServer.waitForFinished());
+ }
+#endif
+
+ void tcpListenFailedTest()
+ {
+ QFETCH_GLOBAL(QUrl, registryUrl);
+
+ if (registryUrl.scheme() != QRemoteObjectStringLiterals::tcp())
+ QSKIP("Skipping test for local and external backends.");
+
+ // Need the Host or Registry running so that the port is in use.
+ setupRegistry();
+ QRemoteObjectHost badHost;
+ badHost.setHostUrl(registryUrl);
+ QCOMPARE(badHost.lastError(), QRemoteObjectNode::ListenFailed);
+
+ }
+
+ void invalidExternalTest()
+ {
+ QFETCH_GLOBAL(QUrl, hostUrl);
+ if (hostUrl.scheme() != QRemoteObjectStringLiterals::tcp())
+ QSKIP("Skipping test for tcp and external backends.");
+ QRemoteObjectHost srcNode;
+ QTest::ignoreMessage(QtWarningMsg, " Overriding a valid QtRO url ( QUrl(\"tcp://127.0.0.1:65511\") ) with AllowExternalRegistration is not allowed.");
+ srcNode.setHostUrl(hostUrl, QRemoteObjectHost::AllowExternalRegistration);
+ QCOMPARE(srcNode.lastError(), QRemoteObjectNode::HostUrlInvalid);
+ Engine e;
+ bool res = srcNode.enableRemoting(&e);
+ QVERIFY(res == false);
+ }
+
+ void startClientWithoutHost()
+ {
+ setupClient();
+ QScopedPointer<EngineReplica> replica(client->acquire<EngineReplica>());
+ client->setHeartbeatInterval(10);
+ // Wait, to make sure there's no crash (QTBUG-94513)
+ QTest::qWait(200);
+
+ // Make sure creating the host afterwards works
+ setupHost();
+ Engine e;
+ e.setRpm(42);
+ host->enableRemoting(&e);
+
+ QVERIFY(replica->waitForSource());
+ QCOMPARE(replica->rpm(), e.rpm());
+ }
+};
+
+QTEST_MAIN(tst_Integration)
+
+#include "tst_integration.moc"
--- /dev/null
+
+add_subdirectory(client)
+add_subdirectory(server)
+add_subdirectory(external)
--- /dev/null
+#include <QtCore>
+
+class MyInterface
+{
+ ENUM Enum1 { First, Second, Third }
+ PROP(Enum1 enum1 = First READWRITE)
+
+ PROP(bool started = false)
+
+ SLOT(bool start())
+ SLOT(bool stop())
+ SLOT(bool quit())
+ SLOT(bool next())
+ SLOT(void testEnumParamsInSlots(Enum1 enumSlotParam, bool slotParam2, int))
+
+ SIGNAL(advance())
+ SIGNAL(testEnumParamsInSignals(Enum1 enumSignalParam, bool signalParam2, QString))
+};
--- /dev/null
+
+#####################################################################
+## integration_external_client Binary:
+#####################################################################
+
+qt_internal_add_executable(integration_external_client
+ OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
+ SOURCES
+ main.cpp
+ INCLUDE_DIRECTORIES
+ ${CMAKE_CURRENT_SOURCE_DIR}
+ PUBLIC_LIBRARIES
+ Qt::RemoteObjects
+ Qt::Test
+)
+qt6_add_repc_replicas(integration_external_client
+ ../MyInterface.rep
+)
+
+#### Keys ignored in scope 1:.:.:client.pro:<TRUE>:
+# TEMPLATE = "app"
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2018 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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 with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "rep_MyInterface_replica.h"
+
+#include <QCoreApplication>
+#include <QtRemoteObjects/qremoteobjectnode.h>
+#include <QtTest/QtTest>
+#include <QTcpSocket>
+
+const QUrl registryUrl = QUrl(QStringLiteral("tcp://127.0.0.1:65212"));
+
+class tst_Client_Process : public QObject
+{
+ Q_OBJECT
+
+private Q_SLOTS:
+ void initTestCase()
+ {
+ m_repNode.setRegistryUrl(registryUrl);
+ QRemoteObjectNode::RemoteObjectSchemaHandler setupTcp = [this](QUrl url) {
+ QTcpSocket *socket = new QTcpSocket(&this->m_repNode);
+ connect(socket, &QTcpSocket::connected,
+ [socket, this]() {
+ this->m_repNode.addClientSideConnection(socket);
+ });
+ connect(socket, &QTcpSocket::errorOccurred,
+ [socket](QAbstractSocket::SocketError error) {
+ qDebug() << "SocketError" << error;
+ delete socket;
+ });
+ socket->connectToHost(url.host(), quint16(url.port()));
+ };
+ m_repNode.registerExternalSchema(QStringLiteral("exttcp"), setupTcp);
+ QVERIFY(m_repNode.waitForRegistry(3000));
+ m_rep.reset(m_repNode.acquire<MyInterfaceReplica>());
+ }
+
+ void testRun()
+ {
+
+ QVERIFY(m_rep->waitForSource());
+ auto reply = m_rep->start();
+ QVERIFY(reply.waitForFinished());
+
+ // BEGIN: Testing
+ QSignalSpy advanceSpy(m_rep.data(), &MyInterfaceReplica::advance);
+
+ QSignalSpy spy(m_rep.data(), &MyInterfaceReplica::enum1Changed);
+ QVERIFY(advanceSpy.wait());
+
+ QCOMPARE(spy.count(), 2);
+ // END: Testing
+
+ reply = m_rep->stop();
+ QVERIFY(reply.waitForFinished());
+ }
+
+ void testEnumDetails()
+ {
+ QHash<QByteArray, int> kvs = {{"First", 0}, {"Second", 1}, {"Third", 2}};
+ QScopedPointer<QRemoteObjectDynamicReplica> rep(m_repNode.acquireDynamic("MyInterface"));
+ QVERIFY(rep->waitForSource());
+
+ auto mo = rep->metaObject();
+ int enumIdx = mo->indexOfEnumerator("Enum1");
+ QVERIFY(enumIdx != -1);
+ auto enumerator = mo->enumerator(enumIdx);
+ QCOMPARE(enumerator.name(), "Enum1");
+ QCOMPARE(enumerator.keyCount(), 3);
+ for (int i = 0; i < 3; ++i) {
+ auto key = enumerator.key(i);
+ auto val = enumerator.value(i);
+ auto it = kvs.find(key);
+ QVERIFY(it != kvs.end());
+ QCOMPARE(*it, val);
+ kvs.erase(it);
+ }
+
+ int propIdx = mo->indexOfProperty("enum1");
+ QVERIFY(propIdx != -1);
+ auto property = mo->property(propIdx);
+ property.write(rep.data(), 1);
+ QTRY_COMPARE(property.read(rep.data()).toInt(), 1);
+ }
+
+ void testMethodSignalParamDetails()
+ {
+ QScopedPointer<QRemoteObjectDynamicReplica> rep(m_repNode.acquireDynamic("MyInterface"));
+ QVERIFY(rep->waitForSource());
+
+ auto mo = rep->metaObject();
+ int signalIdx = mo->indexOfSignal("testEnumParamsInSignals(MyInterfaceReplica::Enum1,bool,QString)");
+ QVERIFY(signalIdx != -1);
+ auto simm = mo->method(signalIdx);
+ {
+ QCOMPARE(simm.parameterCount(), 3);
+ auto paramNames = simm.parameterNames();
+ QCOMPARE(paramNames.size(), 3);
+ QCOMPARE(paramNames.at(0), QByteArrayLiteral("enumSignalParam"));
+ QCOMPARE(paramNames.at(1), QByteArrayLiteral("signalParam2"));
+ QCOMPARE(paramNames.at(2), QByteArrayLiteral("__repc_variable_1"));
+ QCOMPARE(simm.parameterMetaType(0), QMetaType::fromType<MyInterfaceReplica::Enum1>());
+ QCOMPARE(simm.parameterMetaType(1), QMetaType::fromType<bool>());
+ QCOMPARE(simm.parameterMetaType(2), QMetaType::fromType<QString>());
+ }
+
+ int slotIdx = mo->indexOfSlot("testEnumParamsInSlots(MyInterfaceReplica::Enum1,bool,int)");
+ QVERIFY(slotIdx != -1);
+ auto slmm = mo->method(slotIdx);
+ {
+ QCOMPARE(slmm .parameterCount(), 3);
+ auto paramNames = slmm .parameterNames();
+ QCOMPARE(paramNames.size(), 3);
+ QCOMPARE(paramNames.at(0), QByteArrayLiteral("enumSlotParam"));
+ QCOMPARE(paramNames.at(1), QByteArrayLiteral("slotParam2"));
+ QCOMPARE(paramNames.at(2), QByteArrayLiteral("__repc_variable_1"));
+ }
+
+ int enumVal = 0;
+ mo->invokeMethod(rep.data(), "testEnumParamsInSlots",
+ QGenericArgument("MyInterfaceReplica::Enum1", &enumVal),
+ Q_ARG(bool, true), Q_ARG(int, 1234));
+
+ int enumIdx = mo->indexOfProperty("enum1");
+ QVERIFY(enumIdx != -1);
+ QTRY_COMPARE(mo->property(enumIdx).read(rep.data()).toInt(), 0);
+
+ int startedIdx = mo->indexOfProperty("started");
+ QVERIFY(startedIdx != -1);
+ QTRY_COMPARE(mo->property(startedIdx).read(rep.data()).toBool(), true);
+ }
+
+ void testMethodSignal()
+ {
+ QScopedPointer<MyInterfaceReplica> rep(new MyInterfaceReplica());
+ rep->setNode(&m_repNode);
+ QVERIFY(rep->waitForSource());
+
+ rep->testEnumParamsInSlots(MyInterfaceReplica::Second, false, 74);
+
+ connect(rep.data(), &MyInterfaceReplica::testEnumParamsInSignals,
+ [](MyInterfaceReplica::Enum1 enumSignalParam) { QCOMPARE(enumSignalParam, MyInterfaceReplica::Second); });
+
+ QTRY_COMPARE(rep->enum1(), MyInterfaceReplica::Second);
+ QTRY_COMPARE(rep->started(), false);
+ }
+
+ void testDisconnect()
+ {
+ auto reply = m_rep->next();
+ QSignalSpy stateSpy(m_rep.data(), &MyInterfaceReplica::stateChanged);
+ QVERIFY(reply.waitForFinished());
+
+ QTRY_COMPARE(stateSpy.count(), 1);
+ QCOMPARE(m_rep->state(), QRemoteObjectReplica::Suspect);
+
+ QTRY_COMPARE(stateSpy.count(), 2);
+ QCOMPARE(m_rep->state(), QRemoteObjectReplica::Valid);
+ // Make sure we updated to the correct enum1 value
+ QCOMPARE(m_rep->enum1(), MyInterfaceReplica::First);
+ }
+
+ void cleanupTestCase()
+ {
+ auto reply = m_rep->quit();
+ QVERIFY(reply.waitForFinished());
+ }
+
+private:
+ QRemoteObjectNode m_repNode;
+ QScopedPointer<MyInterfaceReplica> m_rep;
+};
+
+QTEST_MAIN(tst_Client_Process)
+
+#include "main.moc"
--- /dev/null
+
+#####################################################################
+## tst_integration_external Test:
+#####################################################################
+
+qt_internal_add_test(tst_integration_external
+ OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
+ SOURCES
+ tst_integration_external.cpp
+ PUBLIC_LIBRARIES
+ Qt::RemoteObjects
+)
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2018 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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 with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtTest/QtTest>
+#include <QMetaType>
+#include <QProcess>
+
+#include "../../../shared/testutils.h"
+
+class tst_Integration_External: public QObject
+{
+ Q_OBJECT
+
+private slots:
+ void initTestCase()
+ {
+ QVERIFY(TestUtils::init("external"));
+ QLoggingCategory::setFilterRules("qt.remoteobjects.warning=false");
+ }
+
+ void cleanup()
+ {
+ // wait for delivery of RemoveObject events to the source
+ QTest::qWait(200);
+ }
+
+ void testRun_data()
+ {
+ QTest::addColumn<bool>("templated");
+ QTest::newRow("non-templated enableRemoting") << false;
+ QTest::newRow("templated enableRemoting") << true;
+ }
+
+ void testRun()
+ {
+ QFETCH(bool, templated);
+
+ qDebug() << "Starting server process";
+ QProcess serverProc;
+ serverProc.setProcessChannelMode(QProcess::ForwardedChannels);
+ if (templated) {
+ QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
+ env.insert("TEMPLATED_REMOTING", "true");
+ serverProc.setProcessEnvironment(env);
+ }
+ serverProc.start(TestUtils::findExecutable("integration_external_server", "/server"),
+ QStringList());
+ QVERIFY(serverProc.waitForStarted());
+
+ // wait for server start
+ QTest::qWait(200);
+
+ qDebug() << "Starting client process";
+ QProcess clientProc;
+ clientProc.setProcessChannelMode(QProcess::ForwardedChannels);
+ clientProc.start(TestUtils::findExecutable("integration_external_client", "/client"),
+ QStringList());
+ QVERIFY(clientProc.waitForStarted());
+
+ QVERIFY(clientProc.waitForFinished());
+ QVERIFY(serverProc.waitForFinished());
+
+ QCOMPARE(serverProc.exitCode(), 0);
+ QCOMPARE(clientProc.exitCode(), 0);
+ }
+};
+
+QTEST_MAIN(tst_Integration_External)
+
+#include "tst_integration_external.moc"
--- /dev/null
+
+#####################################################################
+## integration_external_server Binary:
+#####################################################################
+
+qt_internal_add_executable(integration_external_server
+ OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
+ SOURCES
+ main.cpp
+ mytestserver.cpp mytestserver.h
+ INCLUDE_DIRECTORIES
+ ${CMAKE_CURRENT_SOURCE_DIR}
+ PUBLIC_LIBRARIES
+ Qt::RemoteObjects
+ Qt::Test
+)
+qt6_add_repc_sources(integration_external_server
+ ../MyInterface.rep
+)
+
+#### Keys ignored in scope 1:.:.:server.pro:<TRUE>:
+# TEMPLATE = "app"
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2018 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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 with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "mytestserver.h"
+
+#include <QCoreApplication>
+#include <QTcpServer>
+#include <QtTest/QtTest>
+#include <QTcpSocket>
+
+const QUrl registryUrl = QUrl(QStringLiteral("tcp://127.0.0.1:65212"));
+const QUrl extUrl = QUrl(QStringLiteral("exttcp://127.0.0.1:65213"));
+const QUrl extUrl2 = QUrl(QStringLiteral("exttcp://127.0.0.1:65214"));
+
+class tst_Server_Process : public QObject
+{
+ Q_OBJECT
+
+ struct Device
+ {
+ Device(QUrl url) : srcNode(url, registryUrl, QRemoteObjectHost::AllowExternalRegistration)
+ {
+ tcpServer.listen(QHostAddress(url.host()), quint16(url.port()));
+ QVERIFY(srcNode.waitForRegistry(3000));
+ QObject::connect(&tcpServer, &QTcpServer::newConnection, [this]() {
+ auto conn = this->tcpServer.nextPendingConnection();
+ this->srcNode.addHostSideConnection(conn);
+ });
+ }
+ QTcpServer tcpServer;
+ QRemoteObjectHost srcNode;
+ };
+
+private Q_SLOTS:
+ void testRun()
+ {
+ QRemoteObjectRegistryHost registry(registryUrl);
+
+ Device dev1(extUrl);
+ MyTestServer myTestServer;
+ bool templated = qEnvironmentVariableIsSet("TEMPLATED_REMOTING");
+ if (templated)
+ QVERIFY(dev1.srcNode.enableRemoting<MyInterfaceSourceAPI>(&myTestServer));
+ else
+ QVERIFY(dev1.srcNode.enableRemoting(&myTestServer));
+
+ qDebug() << "Waiting for incoming connections";
+
+ QSignalSpy waitForStartedSpy(&myTestServer, &MyTestServer::startedChanged);
+ QVERIFY(waitForStartedSpy.isValid());
+ QVERIFY(waitForStartedSpy.wait());
+ QCOMPARE(waitForStartedSpy.value(0).value(0).toBool(), true);
+
+ // wait for delivery of events
+ QTest::qWait(200);
+
+ qDebug() << "Client connected";
+
+ // BEGIN: Testing
+
+ // make sure continuous changes to enums don't mess up the protocol
+ myTestServer.setEnum1(MyTestServer::Second);
+ myTestServer.setEnum1(MyTestServer::Third);
+
+ emit myTestServer.advance();
+
+ waitForStartedSpy.clear();
+ QVERIFY(waitForStartedSpy.wait());
+ QCOMPARE(waitForStartedSpy.value(0).value(0).toBool(), false);
+
+ bool next = false;
+ connect(&myTestServer, &MyTestServer::nextStep, [&next]{ next = true; });
+ QTRY_VERIFY_WITH_TIMEOUT(next, 5000);
+
+ qDebug() << "Disable remoting";
+ QVERIFY(dev1.srcNode.disableRemoting(&myTestServer));
+
+ // Wait before changing the state
+ QTest::qWait(200);
+
+ // Change a value while replica is suspect
+ myTestServer.setEnum1(MyTestServer::First);
+
+ // Share the object on a different "device", make sure registry updates and connects
+ qDebug() << "Enable remoting";
+ Device dev2(extUrl2);
+ QVERIFY(dev2.srcNode.enableRemoting(&myTestServer));
+
+ // wait for quit
+ bool quit = false;
+ connect(&myTestServer, &MyTestServer::quitApp, [&quit]{quit = true;});
+ QTRY_VERIFY_WITH_TIMEOUT(quit, 5000);
+
+ // wait for delivery of events
+ QTest::qWait(200);
+
+ qDebug() << "Done. Shutting down.";
+ }
+};
+
+QTEST_MAIN(tst_Server_Process)
+
+#include "main.moc"
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2018 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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 with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <qdebug.h>
+
+#include "mytestserver.h"
+#include "rep_MyInterface_source.h"
+
+MyTestServer::MyTestServer(QObject *parent)
+ : MyInterfaceSimpleSource(parent)
+{
+ qDebug() << "Server started";
+}
+
+MyTestServer::~MyTestServer()
+{
+ qDebug() << "Server stopped";
+}
+
+bool MyTestServer::start()
+{
+ setStarted(true);
+ return true;
+}
+
+bool MyTestServer::stop()
+{
+ setStarted(false);
+ return true;
+}
+
+bool MyTestServer::quit()
+{
+ emit quitApp();
+ return true;
+}
+
+bool MyTestServer::next()
+{
+ emit nextStep();
+ return true;
+}
+
+void MyTestServer::testEnumParamsInSlots(Enum1 enumSlotParam, bool slotParam2, int number)
+{
+ setEnum1(enumSlotParam);
+ setStarted(slotParam2);
+ emit testEnumParamsInSignals(enum1(), started(), QString::number(number));
+}
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2018 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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 with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef MYTESTSERVER_H
+#define MYTESTSERVER_H
+
+#include <QTimer>
+
+#include <QtRemoteObjects/qremoteobjectnode.h>
+#include <QtRemoteObjects/qremoteobjectsource.h>
+
+#include "rep_MyInterface_source.h"
+
+class MyTestServer : public MyInterfaceSimpleSource
+{
+ Q_OBJECT
+
+public:
+ MyTestServer(QObject *parent = nullptr);
+ ~MyTestServer() override;
+
+public Q_SLOTS:
+ bool start() override;
+ bool stop() override;
+ bool quit() override;
+ bool next() override;
+ void testEnumParamsInSlots(Enum1 enumSlotParam, bool slotParam2, int __repc_variable_1) override;
+
+Q_SIGNALS:
+ void quitApp();
+ void nextStep();
+};
+
+#endif // MYTESTSERVER_H
--- /dev/null
+
+add_subdirectory(client)
+add_subdirectory(server)
+add_subdirectory(tst)
--- /dev/null
+POD ExtPOD(int i, float f, QString s)
--- /dev/null
+#include <QtCore>
+#include "rep_ExtPodInterface_merged.h"
+
+class MyInterface
+{
+ ENUM Enum1 { First, Second, Third }
+ PROP(Enum1 enum1 = First READWRITE)
+
+ PROP(bool started = false)
+ PROP(int initialValue)
+
+ SLOT(bool start())
+ SLOT(bool stop())
+ SLOT(bool quit())
+ SLOT(void testEnumParamsInSlots(Enum1 enumSlotParam, bool slotParam2, int))
+
+ SIGNAL(advance())
+ SIGNAL(testEnumParamsInSignals(Enum1 enumSignalParam, bool signalParam2, QString))
+
+ SLOT(void testExtPODListSlot(const QList<ExtPOD> &))
+ SIGNAL(testExtPODListSignal(const QList<ExtPOD> &))
+};
--- /dev/null
+#include <QtCore>
+
+POD MyPOD(int i, float f, QString s)
+
+class PodInterface
+{
+ PROP(MyPOD myPod)
+};
--- /dev/null
+
+#####################################################################
+## integration_multiprocess_client Binary:
+#####################################################################
+
+qt_internal_add_executable(integration_multiprocess_client
+ OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
+ SOURCES
+ main.cpp
+ INCLUDE_DIRECTORIES
+ ${CMAKE_CURRENT_SOURCE_DIR}
+ PUBLIC_LIBRARIES
+ Qt::RemoteObjects
+ Qt::Test
+)
+
+qt6_add_repc_merged(integration_multiprocess_client
+ ../ExtPodInterface.rep
+)
+
+qt6_add_repc_replicas(integration_multiprocess_client
+ ../MyInterface.rep
+)
+
+#### Keys ignored in scope 1:.:.:client.pro:<TRUE>:
+# TEMPLATE = "app"
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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 with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "rep_MyInterface_replica.h"
+#include "rep_ExtPodInterface_merged.h"
+
+#include <QCoreApplication>
+#include <QtRemoteObjects/qremoteobjectnode.h>
+#include <QtTest/QtTest>
+
+class tst_Client_Process : public QObject
+{
+ Q_OBJECT
+
+private Q_SLOTS:
+ void initTestCase()
+ {
+ m_repNode.reset(new QRemoteObjectNode);
+ m_repNode->connectToNode(QUrl(QStringLiteral("tcp://127.0.0.1:65213")));
+ m_rep.reset(m_repNode->acquire<MyInterfaceReplica>());
+ connect(m_rep.data(), &MyInterfaceReplica::notified, [&]() { m_notified = true; });
+ connect(m_rep.data(), &MyInterfaceReplica::initialValueChanged, [&]() {
+ // this value is only set when the replica first connects to the source
+ QCOMPARE(m_notified, false);
+ QCOMPARE(m_rep->initialValue(), 18);
+ });
+ QVERIFY(m_rep->waitForSource());
+ }
+
+ void testRun()
+ {
+ auto reply = m_rep->start();
+ QVERIFY(reply.waitForFinished());
+
+ // BEGIN: Testing
+ QSignalSpy advanceSpy(m_rep.data(), &MyInterfaceReplica::advance);
+
+ QSignalSpy spy(m_rep.data(), &MyInterfaceReplica::enum1Changed);
+ QVERIFY(advanceSpy.wait());
+
+ QCOMPARE(spy.count(), 2);
+ // END: Testing
+
+ reply = m_rep->stop();
+ QVERIFY(reply.waitForFinished());
+ }
+
+ void testEnumDetails()
+ {
+ QHash<QByteArray, int> kvs = {{"First", 0}, {"Second", 1}, {"Third", 2}};
+ QScopedPointer<QRemoteObjectDynamicReplica> rep(m_repNode->acquireDynamic("MyInterface"));
+ QVERIFY(rep->waitForSource());
+
+ auto mo = rep->metaObject();
+ int enumIdx = mo->indexOfEnumerator("Enum1");
+ QVERIFY(enumIdx != -1);
+ auto enumerator = mo->enumerator(enumIdx);
+ QCOMPARE(enumerator.name(), "Enum1");
+ QCOMPARE(enumerator.keyCount(), 3);
+ for (int i = 0; i < 3; ++i) {
+ auto key = enumerator.key(i);
+ auto val = enumerator.value(i);
+ auto it = kvs.find(key);
+ QVERIFY(it != kvs.end());
+ QCOMPARE(*it, val);
+ kvs.erase(it);
+ }
+
+ int propIdx = mo->indexOfProperty("enum1");
+ QVERIFY(propIdx != -1);
+ auto property = mo->property(propIdx);
+ property.write(rep.data(), 1);
+ QTRY_COMPARE(property.read(rep.data()).toInt(), 1);
+ }
+
+ void testMethodSignalParamDetails()
+ {
+ QScopedPointer<QRemoteObjectDynamicReplica> rep(m_repNode->acquireDynamic("MyInterface"));
+ QVERIFY(rep->waitForSource());
+
+ auto mo = rep->metaObject();
+ int signalIdx = mo->indexOfSignal("testEnumParamsInSignals(MyInterfaceReplica::Enum1,bool,QString)");
+ QVERIFY(signalIdx != -1);
+ auto simm = mo->method(signalIdx);
+ {
+ QCOMPARE(simm.parameterCount(), 3);
+ auto paramNames = simm.parameterNames();
+ QCOMPARE(paramNames.size(), 3);
+ QCOMPARE(paramNames.at(0), QByteArrayLiteral("enumSignalParam"));
+ QCOMPARE(paramNames.at(1), QByteArrayLiteral("signalParam2"));
+ QCOMPARE(paramNames.at(2), QByteArrayLiteral("__repc_variable_1"));
+ QCOMPARE(simm.parameterMetaType(0), QMetaType::fromType<MyInterfaceReplica::Enum1>());
+ QCOMPARE(simm.parameterMetaType(1), QMetaType::fromType<bool>());
+ QCOMPARE(simm.parameterMetaType(2), QMetaType::fromType<QString>());
+ }
+
+ int slotIdx = mo->indexOfSlot("testEnumParamsInSlots(MyInterfaceReplica::Enum1,bool,int)");
+ QVERIFY(slotIdx != -1);
+ auto slmm = mo->method(slotIdx);
+ {
+ QCOMPARE(slmm .parameterCount(), 3);
+ auto paramNames = slmm .parameterNames();
+ QCOMPARE(paramNames.size(), 3);
+ QCOMPARE(paramNames.at(0), QByteArrayLiteral("enumSlotParam"));
+ QCOMPARE(paramNames.at(1), QByteArrayLiteral("slotParam2"));
+ QCOMPARE(paramNames.at(2), QByteArrayLiteral("__repc_variable_1"));
+ }
+
+ int enumVal = 0;
+ mo->invokeMethod(rep.data(), "testEnumParamsInSlots",
+ QGenericArgument("MyInterfaceReplica::Enum1", &enumVal),
+ Q_ARG(bool, true), Q_ARG(int, 1234));
+
+ int enumIdx = mo->indexOfProperty("enum1");
+ QVERIFY(enumIdx != -1);
+ QTRY_COMPARE(mo->property(enumIdx).read(rep.data()).toInt(), 0);
+
+ int startedIdx = mo->indexOfProperty("started");
+ QVERIFY(startedIdx != -1);
+ QTRY_COMPARE(mo->property(startedIdx).read(rep.data()).toBool(), true);
+ }
+
+ void testMethodSignal()
+ {
+ QScopedPointer<MyInterfaceReplica> rep(new MyInterfaceReplica());
+ rep->setNode(m_repNode.get());
+ QVERIFY(rep->waitForSource());
+
+ rep->testEnumParamsInSlots(MyInterfaceReplica::Second, false, 74);
+
+ connect(rep.data(), &MyInterfaceReplica::testEnumParamsInSignals,
+ [](MyInterfaceReplica::Enum1 enumSignalParam) { QCOMPARE(enumSignalParam, MyInterfaceReplica::Second); });
+
+ QTRY_COMPARE(rep->enum1(), MyInterfaceReplica::Second);
+ QTRY_COMPARE(rep->started(), false);
+ }
+
+ void testExtPodListSignals()
+ {
+ QScopedPointer<MyInterfaceReplica> rep(new MyInterfaceReplica());
+ rep->setNode(m_repNode.get());
+ QVERIFY(rep->waitForSource());
+
+ auto list = QList { ExtPOD(1, 1.1f, QStringLiteral("v1")),
+ ExtPOD(2, 2.2f, QStringLiteral("v2")) };
+ rep->testExtPODListSlot(list);
+ QSignalSpy spy(rep.data(), &MyInterfaceReplica::testExtPODListSignal);
+ connect(rep.data(), &MyInterfaceReplica::testExtPODListSignal,
+ [list](const QList<ExtPOD> &l) { QCOMPARE(l, list); });
+ QTRY_COMPARE(spy.count(), 1);
+ }
+
+ void testPod()
+ {
+ QScopedPointer<QRemoteObjectDynamicReplica> podRep(m_repNode->acquireDynamic("PodInterface"));
+ QVERIFY(podRep->waitForSource());
+ QVariant value = podRep->property("myPod");
+ const QMetaObject *mo = value.metaType().metaObject();
+ const void *gadget = value.constData();
+
+ QMetaProperty iProp = mo->property(mo->indexOfProperty("i"));
+ QVariant iValue = iProp.readOnGadget(gadget);
+ QCOMPARE(iValue.toInt(), 1);
+
+ QMetaProperty fProp = mo->property(mo->indexOfProperty("f"));
+ QVariant fValue = fProp.readOnGadget(gadget);
+ QCOMPARE(fValue.toFloat(), 5.0f);
+
+ QMetaProperty sProp = mo->property(mo->indexOfProperty("s"));
+ QVariant sValue = sProp.readOnGadget(gadget);
+ QCOMPARE(sValue.toString(), QString(QLatin1String("test")));
+ }
+
+ void cleanupTestCase()
+ {
+ auto reply = m_rep->quit();
+ QVERIFY(reply.waitForFinished());
+ m_rep.reset();
+ QVERIFY(QMetaType::fromName("MyPOD").isValid());
+ m_repNode.reset();
+ QVERIFY(!QMetaType::fromName("MyPOD").isValid());
+ }
+
+private:
+ QScopedPointer<QRemoteObjectNode> m_repNode;
+ QScopedPointer<MyInterfaceReplica> m_rep;
+ bool m_notified = false;
+};
+
+QTEST_MAIN(tst_Client_Process)
+
+#include "main.moc"
--- /dev/null
+
+#####################################################################
+## integration_multiprocess_server Binary:
+#####################################################################
+
+qt_internal_add_executable(integration_multiprocess_server
+ OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
+ SOURCES
+ main.cpp
+ mytestserver.cpp mytestserver.h
+ INCLUDE_DIRECTORIES
+ ${CMAKE_CURRENT_SOURCE_DIR}
+ PUBLIC_LIBRARIES
+ Qt::RemoteObjects
+ Qt::Test
+)
+qt6_add_repc_merged(integration_multiprocess_server
+ ../ExtPodInterface.rep
+)
+
+qt6_add_repc_sources(integration_multiprocess_server
+ ../MyInterface.rep
+ ../PodInterface.rep
+)
+
+#### Keys ignored in scope 1:.:.:server.pro:<TRUE>:
+# TEMPLATE = "app"
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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 with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "mytestserver.h"
+#include "rep_PodInterface_source.h"
+
+#include <QCoreApplication>
+#include <QtTest/QtTest>
+
+class tst_Server_Process : public QObject
+{
+ Q_OBJECT
+
+private Q_SLOTS:
+ void testRun()
+ {
+ QRemoteObjectHost srcNode(QUrl(QStringLiteral("tcp://127.0.0.1:65213")));
+ MyTestServer myTestServer;
+ bool templated = qEnvironmentVariableIsSet("TEMPLATED_REMOTING");
+ if (templated)
+ srcNode.enableRemoting<MyInterfaceSourceAPI>(&myTestServer);
+ else
+ srcNode.enableRemoting(&myTestServer);
+
+ PodInterfaceSimpleSource myPodSource;
+ myPodSource.setMyPod(MyPOD(1, 5.0, "test"));
+ if (templated)
+ srcNode.enableRemoting<PodInterfaceSourceAPI>(&myPodSource);
+ else
+ srcNode.enableRemoting(&myPodSource);
+
+ qDebug() << "Waiting for incoming connections";
+
+ QSignalSpy waitForStartedSpy(&myTestServer, &MyTestServer::startedChanged);
+ QVERIFY(waitForStartedSpy.isValid());
+ QVERIFY(waitForStartedSpy.wait());
+ QCOMPARE(waitForStartedSpy.value(0).value(0).toBool(), true);
+
+ // wait for delivery of events
+ QTest::qWait(200);
+
+ qDebug() << "Client connected";
+
+ // BEGIN: Testing
+
+ // make sure continuous changes to enums don't mess up the protocol
+ myTestServer.setEnum1(MyTestServer::Second);
+ myTestServer.setEnum1(MyTestServer::Third);
+
+ emit myTestServer.advance();
+
+ // END: Testing
+
+ waitForStartedSpy.clear();
+ QVERIFY(waitForStartedSpy.wait());
+ QCOMPARE(waitForStartedSpy.value(0).value(0).toBool(), false);
+
+ // wait for quit
+ bool quit = false;
+ connect(&myTestServer, &MyTestServer::quitApp, [&quit]{quit = true;});
+ QTRY_VERIFY_WITH_TIMEOUT(quit, 5000);
+
+ // wait for delivery of events
+ QTest::qWait(200);
+
+ qDebug() << "Done. Shutting down.";
+ }
+};
+
+QTEST_MAIN(tst_Server_Process)
+
+#include "main.moc"
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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 with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <qdebug.h>
+
+#include "mytestserver.h"
+#include "rep_MyInterface_source.h"
+
+MyTestServer::MyTestServer(QObject *parent)
+ : MyInterfaceSimpleSource(parent)
+{
+ qDebug() << "Server started";
+ setInitialValue(18);
+}
+
+MyTestServer::~MyTestServer()
+{
+ qDebug() << "Server stopped";
+}
+
+bool MyTestServer::start()
+{
+ setStarted(true);
+ return true;
+}
+
+bool MyTestServer::stop()
+{
+ setStarted(false);
+ return true;
+}
+
+bool MyTestServer::quit()
+{
+ emit quitApp();
+ return true;
+}
+
+void MyTestServer::testEnumParamsInSlots(Enum1 enumSlotParam, bool slotParam2, int number)
+{
+ setEnum1(enumSlotParam);
+ setStarted(slotParam2);
+ emit testEnumParamsInSignals(enum1(), started(), QString::number(number));
+}
+
+void MyTestServer::testExtPODListSlot(const QList<ExtPOD> &l)
+{
+ emit testExtPODListSignal(l);
+}
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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 with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef MYTESTSERVER_H
+#define MYTESTSERVER_H
+
+#include <QTimer>
+
+#include <QtRemoteObjects/qremoteobjectnode.h>
+#include <QtRemoteObjects/qremoteobjectsource.h>
+
+#include "rep_MyInterface_source.h"
+
+class MyTestServer : public MyInterfaceSimpleSource
+{
+ Q_OBJECT
+
+public:
+ MyTestServer(QObject *parent = nullptr);
+ ~MyTestServer() override;
+
+public Q_SLOTS:
+ bool start() override;
+ bool stop() override;
+ bool quit() override;
+ void testEnumParamsInSlots(Enum1 enumSlotParam, bool slotParam2, int __repc_variable_1) override;
+ void testExtPODListSlot(const QList<ExtPOD> &l) override;
+
+Q_SIGNALS:
+ void quitApp();
+};
+
+#endif // MYTESTSERVER_H
--- /dev/null
+
+#####################################################################
+## tst_integration_multiprocess Test:
+#####################################################################
+
+qt_internal_add_test(tst_integration_multiprocess
+ OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
+ SOURCES
+ tst_integration_multiprocess.cpp
+ PUBLIC_LIBRARIES
+ Qt::RemoteObjects
+)
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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 with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtTest/QtTest>
+#include <QMetaType>
+#include <QProcess>
+
+#include "../../../shared/testutils.h"
+
+class tst_Integration_MultiProcess: public QObject
+{
+ Q_OBJECT
+
+private slots:
+ void initTestCase()
+ {
+ QVERIFY(TestUtils::init("tst"));
+ QLoggingCategory::setFilterRules("qt.remoteobjects.warning=false");
+ }
+
+ void cleanup()
+ {
+ // wait for delivery of RemoveObject events to the source
+ QTest::qWait(200);
+ }
+
+ void testRun_data()
+ {
+ QTest::addColumn<bool>("templated");
+ QTest::newRow("non-templated enableRemoting") << false;
+ QTest::newRow("templated enableRemoting") << true;
+ }
+
+ void testRun()
+ {
+ QFETCH(bool, templated);
+
+ qDebug() << "Starting server process";
+ QProcess serverProc;
+ serverProc.setProcessChannelMode(QProcess::ForwardedChannels);
+ if (templated) {
+ QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
+ env.insert("TEMPLATED_REMOTING", "true");
+ serverProc.setProcessEnvironment(env);
+ }
+ serverProc.start(TestUtils::findExecutable("integration_multiprocess_server", "/server"),
+ QStringList());
+ QVERIFY(serverProc.waitForStarted());
+
+ // wait for server start
+ QTest::qWait(200);
+
+ qDebug() << "Starting client process";
+ QProcess clientProc;
+ clientProc.setProcessChannelMode(QProcess::ForwardedChannels);
+ clientProc.start(TestUtils::findExecutable("integration_multiprocess_client", "/client"),
+ QStringList());
+ QVERIFY(clientProc.waitForStarted());
+
+ QVERIFY(clientProc.waitForFinished());
+ QVERIFY(serverProc.waitForFinished());
+
+ QCOMPARE(serverProc.exitCode(), 0);
+ QCOMPARE(clientProc.exitCode(), 0);
+ }
+};
+
+QTEST_MAIN(tst_Integration_MultiProcess)
+
+#include "tst_integration_multiprocess.moc"
--- /dev/null
+
+#####################################################################
+## localsockettestserver Binary:
+#####################################################################
+
+qt_internal_add_executable(localsockettestserver
+ SOURCES
+ main.cpp
+ PUBLIC_LIBRARIES
+ Qt::RemoteObjects
+ OUTPUT_DIRECTORY
+ ${CMAKE_CURRENT_BINARY_DIR}
+)
+
+#### Keys ignored in scope 1:.:.:localsockettestserver.pro:<TRUE>:
+# TEMPLATE = "app"
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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 with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QCoreApplication>
+#include <QRemoteObjectNode>
+
+int main(int argc, char *argv[])
+{
+ QCoreApplication a(argc, argv);
+ QObject remotedObject;
+ remotedObject.setObjectName(QStringLiteral("connectme"));
+ QRemoteObjectHost node(QUrl(QStringLiteral("local:crashMe")));
+ node.enableRemoting(&remotedObject);
+
+ return a.exec();
+}
--- /dev/null
+
+#####################################################################
+## tst_modelreplicatest Test:
+#####################################################################
+
+qt_internal_add_test(tst_modelreplicatest
+ SOURCES
+ tst_modelreplicatest.cpp
+ DEFINES
+ SRCDIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/\\\"
+ PUBLIC_LIBRARIES
+ Qt::RemoteObjects
+)
+qt6_add_repc_merged(tst_modelreplicatest
+ model.rep
+)
+
+#### Keys ignored in scope 1:.:.:modelreplica.pro:<TRUE>:
+# TEMPLATE = "app"
--- /dev/null
+class Media
+{
+ ENUM state{Stopped, Paused, Playing}
+ PROP(QString currentTrack)
+ PROP(state playState)
+ MODEL tracks(display)
+}
+
+class OtherMedia
+{
+ MODEL tracks(display,decoration)
+}
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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 with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QString>
+#include <QtTest>
+#include "rep_model_merged.h"
+
+class ModelreplicaTest : public QObject
+{
+ Q_OBJECT
+
+public:
+ ModelreplicaTest() = default;
+
+private Q_SLOTS:
+ void basicFunctions();
+ void basicFunctions_data();
+ void nullModel();
+ void nestedSortFilterProxyModel_data() { basicFunctions_data(); }
+ void nestedSortFilterProxyModel();
+ void sortFilterProxyModel_data();
+ void sortFilterProxyModel();
+};
+
+void ModelreplicaTest::basicFunctions_data()
+{
+ QTest::addColumn<bool>("templated");
+ QTest::newRow("non-templated enableRemoting") << false;
+ QTest::newRow("templated enableRemoting") << true;
+}
+
+void ModelreplicaTest::basicFunctions()
+{
+ QFETCH(bool, templated);
+
+ QRemoteObjectRegistryHost host(QUrl("tcp://localhost:5555"));
+ auto model = new QStringListModel();
+ model->setStringList(QStringList() << "Track1" << "Track2" << "Track3");
+ MediaSimpleSource source;
+ source.setTracks(model);
+ if (templated)
+ host.enableRemoting<MediaSourceAPI>(&source);
+ else
+ host.enableRemoting(&source);
+
+ auto model2 = new QStringListModel();
+ model2->setStringList(QStringList() << "Track4" << "Track5");
+ OtherMediaSimpleSource source2;
+ source2.setTracks(model2);
+ host.enableRemoting(&source2);
+
+ QRemoteObjectNode client(QUrl("tcp://localhost:5555"));
+ const QScopedPointer<MediaReplica> replica(client.acquire<MediaReplica>());
+ QSignalSpy tracksSpy(replica->tracks(), &QAbstractItemModelReplica::initialized);
+ QVERIFY(replica->waitForSource(300));
+ QVERIFY(tracksSpy.wait());
+ // Rep file only uses display role
+ QCOMPARE(QList<int>{Qt::DisplayRole}, replica->tracks()->availableRoles());
+
+ QCOMPARE(model->rowCount(), replica->tracks()->rowCount());
+ for (int i = 0; i < replica->tracks()->rowCount(); i++)
+ {
+ // We haven't received any data yet
+ QCOMPARE(QVariant(), replica->tracks()->data(replica->tracks()->index(i, 0)));
+ }
+
+ // Wait for data to be fetch and confirm
+ QTest::qWait(100);
+ QCOMPARE(model->rowCount(), replica->tracks()->rowCount());
+ for (int i = 0; i < replica->tracks()->rowCount(); i++)
+ {
+ QTRY_COMPARE(model->data(model->index(i), Qt::DisplayRole), replica->tracks()->data(replica->tracks()->index(i, 0)));
+ }
+
+ // ensure the tracks objects are distinct
+ const QScopedPointer<OtherMediaReplica> otherReplica(client.acquire<OtherMediaReplica>());
+ QSignalSpy otherTracksSpy(otherReplica->tracks(), &QAbstractItemModelReplica::initialized);
+ QVERIFY(otherReplica->waitForSource(300));
+ QVERIFY(otherTracksSpy.wait());
+ QCOMPARE(otherReplica->tracks()->availableRoles().count(), 2);
+
+}
+
+void ModelreplicaTest::nullModel()
+{
+ QRemoteObjectRegistryHost host(QUrl("tcp://localhost:5555"));
+ MediaSimpleSource source;
+ host.enableRemoting(&source);
+
+ QRemoteObjectNode client(QUrl("tcp://localhost:5555"));
+ const QScopedPointer<MediaReplica> replica(client.acquire<MediaReplica>());
+ QVERIFY(replica->waitForSource(300));
+
+ auto model = new QStringListModel(this);
+ model->setStringList(QStringList() << "Track1" << "Track2" << "Track3");
+ source.setTracks(model);
+
+ QTRY_VERIFY(replica->tracks());
+ QTRY_COMPARE(replica->tracks()->rowCount(), 3);
+ QTRY_COMPARE(replica->tracks()->data(replica->tracks()->index(0, 0)), "Track1");
+
+ model = new QStringListModel(this);
+ model->setStringList(QStringList() << "New Track1" << "New Track2" << "New Track3" << "New Track4");
+ source.setTracks(model);
+ QTRY_COMPARE(replica->tracks()->rowCount(), 4);
+ QTRY_COMPARE(replica->tracks()->data(replica->tracks()->index(3, 0)), "New Track4");
+}
+
+void ModelreplicaTest::nestedSortFilterProxyModel()
+{
+ QFETCH(bool, templated);
+
+ QRemoteObjectRegistryHost host(QUrl("tcp://localhost:5555"));
+ auto model = new QStringListModel(this);
+ model->setStringList(QStringList() << "CCC" << "AAA" << "BBB");
+ auto proxyModel = new QSortFilterProxyModel(this);
+ proxyModel->setSourceModel(model);
+
+ MediaSimpleSource source;
+ source.setTracks(proxyModel);
+ if (templated)
+ host.enableRemoting<MediaSourceAPI>(&source);
+ else
+ host.enableRemoting(&source);
+
+ QRemoteObjectNode client(QUrl("tcp://localhost:5555"));
+ const QScopedPointer<MediaReplica> replica(client.acquire<MediaReplica>());
+ QSignalSpy tracksSpy(replica->tracks(), &QAbstractItemModelReplica::initialized);
+ QVERIFY(replica->waitForSource(300));
+ QVERIFY(tracksSpy.wait());
+ // Rep file only uses display role
+ QCOMPARE(QVector<int>{Qt::DisplayRole}, replica->tracks()->availableRoles());
+
+ QCOMPARE(proxyModel->rowCount(), replica->tracks()->rowCount());
+ for (int i = 0; i < replica->tracks()->rowCount(); i++) {
+ // We haven't received any data yet
+ QCOMPARE(QVariant(), replica->tracks()->data(replica->tracks()->index(i, 0)));
+ }
+
+ // Wait for data to be fetch and confirm
+ QCOMPARE(proxyModel->rowCount(), replica->tracks()->rowCount());
+ for (int i = 0; i < replica->tracks()->rowCount(); i++)
+ QTRY_COMPARE(proxyModel->data(proxyModel->index(i, 0), Qt::DisplayRole), replica->tracks()->data(replica->tracks()->index(i, 0)));
+
+ proxyModel->sort(0, Qt::AscendingOrder);
+ QCOMPARE(proxyModel->rowCount(), replica->tracks()->rowCount());
+ for (int i = 0; i < replica->tracks()->rowCount(); i++)
+ QTRY_COMPARE(proxyModel->data(proxyModel->index(i, 0), Qt::DisplayRole), replica->tracks()->data(replica->tracks()->index(i, 0)));
+}
+
+void ModelreplicaTest::sortFilterProxyModel_data()
+{
+ QTest::addColumn<bool>("prefetch");
+
+ QTest::newRow("size only") << false;
+ QTest::newRow("prefetch") << true;
+}
+
+void ModelreplicaTest::sortFilterProxyModel()
+{
+ QFETCH(bool, prefetch);
+
+ QRemoteObjectRegistryHost host(QUrl("tcp://localhost:5555"));
+ auto model = new QStringListModel(this);
+ model->setStringList(QStringList() << "CCC" << "AAA" << "BBB");
+ auto proxyModel = new QSortFilterProxyModel(this);
+ proxyModel->setSourceModel(model);
+
+ QList<int> roles = { Qt::DisplayRole };
+ host.enableRemoting(proxyModel, "test", roles);
+
+ auto fetchMode = prefetch ? QtRemoteObjects::PrefetchData : QtRemoteObjects::FetchRootSize;
+ QRemoteObjectNode client(QUrl("tcp://localhost:5555"));
+ QScopedPointer<QAbstractItemModelReplica> replica(client.acquireModel("test", fetchMode));
+ QSignalSpy initSpy(replica.get(), &QAbstractItemModelReplica::initialized);
+ QVERIFY(initSpy.wait());
+
+ QCOMPARE(roles, replica->availableRoles());
+
+ // Wait for data to be fetch and confirm
+ QCOMPARE(proxyModel->rowCount(), replica->rowCount());
+ for (int i = 0; i < replica->rowCount(); i++)
+ QTRY_COMPARE(proxyModel->data(proxyModel->index(i, 0), Qt::DisplayRole),
+ replica->data(replica->index(i, 0)));
+
+ proxyModel->sort(0, Qt::AscendingOrder);
+ QCOMPARE(proxyModel->rowCount(), replica->rowCount());
+
+ for (int i = 0; i < replica->rowCount(); i++)
+ QTRY_COMPARE(proxyModel->data(proxyModel->index(i, 0), Qt::DisplayRole),
+ replica->data(replica->index(i, 0)));
+}
+
+QTEST_MAIN(ModelreplicaTest)
+
+#include "tst_modelreplicatest.moc"
--- /dev/null
+
+#####################################################################
+## tst_modelview Test:
+#####################################################################
+
+qt_internal_add_test(tst_modelview
+ SOURCES
+ tst_modelview.cpp
+ ../shared/model_utilities.h
+ PUBLIC_LIBRARIES
+ Qt::Gui
+ Qt::RemoteObjects
+)
+
+## Scopes:
+#####################################################################
+
+qt_internal_extend_target(tst_modelview CONDITION boot2qt
+ DEFINES
+ SLOW_MODELTEST
+)
+
+qt_internal_extend_target(tst_modelview CONDITION MINGW
+ DEFINES
+ SLOW_MODELTEST
+)
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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 with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "../shared/model_utilities.h"
+
+#include <QtTest/QtTest>
+#include <QAbstractItemModelTester>
+#include <QMetaType>
+#include <QRemoteObjectReplica>
+#include <QRemoteObjectNode>
+#include <QAbstractItemModelReplica>
+#include <QStandardItemModel>
+#include <QSortFilterProxyModel>
+#include <QEventLoop>
+#include <QRandomGenerator>
+
+namespace {
+
+QList<QStandardItem*> createInsertionChildren(int num, const QString& name, const QColor &background)
+{
+ QList<QStandardItem*> children;
+ for (int i = 0; i < num; ++i) {
+ QStandardItem *item = new QStandardItem(QStringLiteral("%1 %2").arg(name).arg(i+1));
+ item->setBackground(background);
+ children.append(item);
+ }
+ return children;
+}
+
+class RowsWatcher : public WaitHelper
+{
+public:
+ RowsWatcher(const QAbstractItemModel *model, int expectedRowsCount)
+ : WaitHelper(), m_model(model), m_expectedRowsCount(expectedRowsCount)
+ {
+ connect(m_model, &QAbstractItemModel::rowsInserted, this,
+ [this](const QModelIndex &parent, int first, int last) {
+ const auto columnCount = m_model->columnCount(parent);
+ for (int row = first; row <= last; ++row) {
+ for (int column = 0; column < columnCount; ++column)
+ m_changedData.append(m_model->index(row, column, parent));
+ }
+ onNumRowsChanged(parent, first, last);
+ });
+
+ connect(m_model, &QAbstractItemModel::rowsRemoved, this, &RowsWatcher::onNumRowsChanged);
+ }
+
+ void onNumRowsChanged(const QModelIndex &parent, int first, int last)
+ {
+ const auto compare = [=](const RowData &row) {
+ return (row.m_start == first && row.m_end == last
+ && compareIndices(row.m_index, parent));
+ };
+ QVERIFY(std::find_if(m_pendingRows.begin(), m_pendingRows.end(), compare)
+ != m_pendingRows.end());
+
+ m_currentRowsCount += last - first + 1;
+ if (m_currentRowsCount == m_expectedRowsCount)
+ finish();
+ }
+
+ void scheduleRowsToWatch(const QModelIndex &index, int start, int end)
+ {
+ m_pendingRows.push_back(RowData { index, start, end });
+ }
+
+ QList<QModelIndex> changedData() const { return m_changedData; }
+
+private:
+ struct RowData
+ {
+ QModelIndex m_index;
+ int m_start = -1;
+ int m_end = -1;
+ };
+
+ const QAbstractItemModel *m_model;
+ QList<RowData> m_pendingRows;
+ QList<QModelIndex> m_changedData;
+ int m_currentRowsCount = 0;
+ const int m_expectedRowsCount;
+};
+
+QTextStream cout(stdout, QIODevice::WriteOnly);
+
+//Keep in case we need detailed debugging in the future...
+#if 0
+inline QDebug operator <<(QDebug dbg, const InsertedRow &row)
+{
+ return dbg.nospace() << "Index(" << row.m_index << ", " << row.m_start << ", " << row.m_end << ")";
+}
+
+inline void dumpModel(const QAbstractItemModel *model, const QModelIndex &parent = QModelIndex())
+{
+ int level = 0;
+ for (QModelIndex idx = parent; idx.isValid(); idx = model->parent(idx), ++level);
+ const QHash<int,QByteArray> roles = model->roleNames();
+ for (int i = 0; i < model->rowCount(parent); ++i) {
+ for (int j = 0; j < model->columnCount(parent); ++j) {
+ const QModelIndex index = model->index(i, j);
+ Q_ASSERT(index.isValid());
+ QString s;
+ s.fill(QChar(' '), level*2);
+ cout << qPrintable(s);
+ cout << QString(QLatin1String("%1:%2")).arg(i).arg(j);
+ for (auto it = roles.cbegin(), end = roles.cend(); it != end; ++it) {
+ const QVariant v = model->data(index, it.key());
+ if (!v.isValid()) continue;
+ QString t;
+ QDebug(&t) << v;
+ cout << " " << QString::fromUtf8(it.value()) << "=" << t.trimmed();
+ }
+
+ {
+ QString t;
+ QDebug(&t) << model->flags(index);
+ cout << " flags=" << t;
+ }
+
+ cout << "\n";
+ cout.flush();
+ dumpModel(model, index); // recursive
+ }
+ }
+}
+#endif
+
+void compareData(const QAbstractItemModel *sourceModel, const QAbstractItemModelReplica *replica)
+{
+ QVERIFY(sourceModel);
+ QVERIFY(replica);
+
+ QCOMPARE(replica->rowCount(), sourceModel->rowCount());
+ QCOMPARE(replica->columnCount(), sourceModel->columnCount());
+ QCOMPARE(replica->roleNames(), sourceModel->roleNames());
+
+ for (int i = 0; i < sourceModel->rowCount(); ++i) {
+ for (int j = 0; j < sourceModel->columnCount(); ++j) {
+ const auto roles = replica->availableRoles();
+ for (int role : roles) {
+ QCOMPARE(replica->index(i, j).data(role), sourceModel->index(i, j).data(role));
+ }
+ }
+ }
+}
+
+void compareIndex(const QModelIndex &sourceIndex, const QModelIndex &replicaIndex,
+ const QList<int> &roles)
+{
+ QVERIFY(sourceIndex.isValid());
+ QVERIFY(replicaIndex.isValid());
+ for (int role : roles) {
+ QCOMPARE(replicaIndex.data(role), sourceIndex.data(role));
+ }
+ const QAbstractItemModel *sourceModel = sourceIndex.model();
+ const QAbstractItemModel *replicaModel = replicaIndex.model();
+ const int sourceRowCount = sourceModel->rowCount(sourceIndex);
+ const int replicaRowCount = replicaModel->rowCount(replicaIndex);
+ QCOMPARE(replicaRowCount, sourceRowCount);
+ const int sourceColumnCount = sourceModel->columnCount(sourceIndex);
+ const int replicaColumnCount = replicaModel->columnCount(replicaIndex);
+ // only test the column count if the row count is larger than zero, because we
+ // assume the column count is constant over a tree model and it doesn't make a
+ // difference in the view.
+ if (sourceRowCount)
+ QCOMPARE(replicaColumnCount, sourceColumnCount);
+ for (int i = 0; i < sourceRowCount; ++i) {
+ for (int j = 0; j < sourceColumnCount; ++j) {
+ auto sourceChild = sourceModel->index(i, j, sourceIndex);
+ auto replicaChild = replicaModel->index(i, j, replicaIndex);
+ compareIndex(sourceChild, replicaChild, roles);
+
+ }
+ }
+}
+
+void compareTreeData(const QAbstractItemModel *sourceModel, const QAbstractItemModelReplica *replica)
+{
+ QVERIFY(sourceModel);
+ QVERIFY(replica);
+
+ QCOMPARE(replica->rowCount(), sourceModel->rowCount());
+ QCOMPARE(replica->columnCount(), sourceModel->columnCount());
+
+ for (int i = 0; i < sourceModel->rowCount(); ++i) {
+ for (int j = 0; j < sourceModel->columnCount(); ++j) {
+ const QModelIndex replicaIndex = replica->index(i, j);
+ const QModelIndex sourceIndex = sourceModel->index(i, j);
+ compareIndex(sourceIndex, replicaIndex, replica->availableRoles());
+ }
+ }
+}
+
+void compareTreeData(const QAbstractItemModel *sourceModel, const QAbstractItemModel *replica, const QList<int> &roles)
+{
+ QVERIFY(sourceModel);
+ QVERIFY(replica);
+
+ QCOMPARE(replica->rowCount(), sourceModel->rowCount());
+ QCOMPARE(replica->columnCount(), sourceModel->columnCount());
+
+ for (int i = 0; i < sourceModel->rowCount(); ++i) {
+ for (int j = 0; j < sourceModel->columnCount(); ++j) {
+ const QModelIndex replicaIndex = replica->index(i, j);
+ const QModelIndex sourceIndex = sourceModel->index(i, j);
+ compareIndex(sourceIndex, replicaIndex, roles);
+ }
+ }
+}
+
+void compareFlags(const QAbstractItemModel *sourceModel, const QAbstractItemModelReplica *replica)
+{
+ QVERIFY(sourceModel);
+ QVERIFY(replica);
+
+ QCOMPARE(replica->rowCount(), sourceModel->rowCount());
+ QCOMPARE(replica->columnCount(), sourceModel->columnCount());
+
+ for (int i = 0; i < sourceModel->rowCount(); ++i) {
+ for (int j = 0; j < sourceModel->columnCount(); ++j) {
+ if (replica->index(i, j).flags() != sourceModel->index(i, j).flags())
+ qWarning() << sourceModel->index(i, j).flags() << replica->index(i, j).flags() << i << j;
+ QCOMPARE(replica->index(i, j).flags(), sourceModel->index(i, j).flags());
+ }
+ }
+}
+
+// class to test cutom role names
+class RolenamesListModel : public QAbstractListModel
+{
+public:
+ explicit RolenamesListModel(QObject *parent = nullptr) : QAbstractListModel(parent) { }
+ int rowCount(const QModelIndex &) const override { return int(m_list.length()); }
+ QVariant data(const QModelIndex &index, int role) const override
+ {
+ if (role == Qt::UserRole)
+ return m_list.at(index.row()).second;
+ else if (role == Qt::UserRole+1)
+ return m_list.at(index.row()).first;
+ else
+ return QVariant();
+ }
+ QHash<int, QByteArray> roleNames() const override
+ {
+ QHash<int, QByteArray> roles;
+ roles[Qt::UserRole] = "name";
+ roles[Qt::UserRole+1] = "pid";
+ return roles;
+ }
+ void addPair(const QVariant pid,const QVariant name) {
+ m_list.append(qMakePair(pid, name));
+ }
+ void clearList() {
+ m_list.clear();
+ }
+private:
+ QList<QPair<QVariant, QVariant>> m_list;
+};
+
+QList<QStandardItem*> addChild(int numChilds, int nestingLevel)
+{
+ QList<QStandardItem*> result;
+ if (nestingLevel == 0)
+ return result;
+ for (int i = 0; i < numChilds; ++i) {
+ QStandardItem *child = new QStandardItem(QStringLiteral("Child num %1, nesting Level %2").arg(i+1).arg(nestingLevel));
+ if (i == 0) {
+ QList<QStandardItem*> res = addChild(numChilds, nestingLevel -1);
+ if (res.size() > 0)
+ child->appendRow(res);
+ }
+ result.push_back(child);
+ }
+ return result;
+}
+
+int getRandomNumber(int min, int max)
+{
+ int res = QRandomGenerator::global()->generate() & INT_MAX;
+ const int diff = (max - min);
+ res = res % diff;
+ res += min;
+ return res;
+}
+
+class FetchData : public WaitHelper
+{
+public:
+ FetchData(const QAbstractItemModelReplica *replica) : WaitHelper(), m_replica(replica)
+ {
+ if (!m_replica->isInitialized()) {
+ QEventLoop l;
+ connect(m_replica, &QAbstractItemModelReplica::initialized, &l, &QEventLoop::quit);
+ l.exec();
+ }
+
+ connect(m_replica, &QAbstractItemModelReplica::dataChanged, this, &FetchData::dataChanged);
+ connect(m_replica, &QAbstractItemModelReplica::rowsInserted, this, &FetchData::rowsInserted);
+ }
+
+ bool fetchAndWait(int timeout = 15000)
+ {
+ addAll();
+ fetch();
+ return wait(timeout);
+ }
+
+private:
+ const QAbstractItemModelReplica *m_replica;
+ QHash<QPersistentModelIndex, QList<int>> m_pending;
+ QSet<QPersistentModelIndex> m_waitForInsertion;
+
+ void addData(const QModelIndex &index, const QList<int> &roles)
+ {
+ for (int role : roles) {
+ const bool cached = m_replica->hasData(index, role);
+ if (cached)
+ continue;
+ if (!m_pending.contains(index))
+ m_pending[index] = QList<int>() << role;
+ else {
+ if (!m_pending[index].contains(role))
+ m_pending[index].append(role);
+ }
+ }
+ }
+
+ void addIndex(const QModelIndex &parent, const QList<int> &roles)
+ {
+ if (parent.isValid())
+ addData(parent, roles);
+ for (int i = 0; i < m_replica->rowCount(parent); ++i) {
+ for (int j = 0; j < m_replica->columnCount(parent); ++j) {
+ const QModelIndex index = m_replica->index(i, j, parent);
+ Q_ASSERT(index.isValid());
+ addIndex(index, roles);
+ }
+ }
+ }
+
+ void addAll()
+ {
+ addIndex(QModelIndex(), m_replica->availableRoles());
+ }
+
+ void fetch()
+ {
+ if (m_pending.isEmpty() && m_waitForInsertion.isEmpty()) {
+ finish();
+ return;
+ }
+ QHash<QPersistentModelIndex, QList<int>> pending(m_pending);
+ pending.detach();
+ auto it(pending.constBegin()), end(pending.constEnd());
+ for (; it != end; ++it) {
+ for (int role : it.value()) {
+ QVariant v = m_replica->data(it.key(), role);
+ Q_UNUSED(v)
+ }
+ }
+ }
+
+ void rowsInserted(const QModelIndex &parent, int first, int last)
+ {
+ static QList<int> rolesV;
+ if (rolesV.isEmpty())
+ rolesV << Qt::DisplayRole << Qt::BackgroundRole;
+ m_waitForInsertion.remove(parent);
+ const int columnCount = m_replica->columnCount(parent);
+ if (!(m_replica->hasChildren(parent) && columnCount > 0 && m_replica->rowCount(parent) > 0))
+ qWarning() << m_replica->hasChildren(parent) << columnCount << m_replica->rowCount(parent) << parent.data();
+ QVERIFY(m_replica->hasChildren(parent) && columnCount > 0 && m_replica->rowCount(parent) > 0);
+ for (int i = first; i <= last; ++i) {
+ for (int j = 0; j < columnCount; ++j) {
+ const QModelIndex index = m_replica->index(i, j, parent);
+ const int childRowCount = m_replica->rowCount(index);
+
+ QVERIFY(index.isValid());
+ if (m_replica->hasChildren(index) && childRowCount == 0) {
+ if (index.column() == 0)
+ m_waitForInsertion.insert(index);
+ }
+ addIndex(index, rolesV);
+ }
+ }
+ if (m_replica->hasChildren(parent))
+ fetch();
+ }
+
+ void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QList<int> &roles = {})
+ {
+ Q_ASSERT(topLeft.isValid());
+ Q_ASSERT(bottomRight.isValid());
+ Q_ASSERT(topLeft.parent() == bottomRight.parent());
+
+ const QModelIndex parent = topLeft.parent();
+ for (int i = topLeft.row(); i <= bottomRight.row(); ++i) {
+ for (int j = topLeft.column(); j <= bottomRight.column(); ++j) {
+ const QModelIndex index = m_replica->index(i, j, parent);
+ Q_ASSERT(index.isValid());
+ auto it = m_pending.find(index);
+ if (it == m_pending.end())
+ continue;
+
+#if 0
+ QList<int> itroles = it.value();
+ itroles.detach();
+ if (roles.isEmpty()) {
+ itroles.clear();
+ } else {
+ for (int r : roles) {
+ itroles.removeAll(r);
+ }
+ }
+ if (itroles.isEmpty()) {
+ m_pending.erase(it);
+ } else {
+ m_pending[index] = itroles;
+ }
+#else
+ Q_UNUSED(roles)
+ m_pending.erase(it);
+ if (m_replica->hasChildren(index)) {
+ // ask for the row count to get an update
+ const int rowCount = m_replica->rowCount(index);
+ for (int i = 0; i < rowCount; ++i) {
+ const QModelIndex cIndex = m_replica->index(i, 0, index);
+ Q_ASSERT(cIndex.isValid());
+ addIndex(cIndex, m_replica->availableRoles());
+ }
+ if (rowCount)
+ fetch();
+ else if (index.column() == 0)
+ m_waitForInsertion.insert(index);
+ }
+#endif
+ }
+ }
+
+ if (m_pending.isEmpty() && m_waitForInsertion.isEmpty())
+ finish();
+ }
+};
+
+} // namespace
+
+#define _SETUP_TEST_ \
+ QRemoteObjectHost basicServer; \
+ QRemoteObjectNode client; \
+ QRemoteObjectRegistryHost registryServer; \
+ setup_models(basicServer, client, registryServer);
+
+class TestModelView: public QObject
+{
+ Q_OBJECT
+
+ QStandardItemModel m_sourceModel;
+ RolenamesListModel m_listModel;
+
+public:
+ void setup_models(QRemoteObjectHost &basicServer,
+ QRemoteObjectNode &client,
+ QRemoteObjectRegistryHost ®istryServer);
+
+private slots:
+ // NB: The tests have side effects on the models used, and need to be run
+ // in order (they may depend on previous side effects).
+ void initTestCase();
+
+ void testEmptyModel();
+ void testInitialData();
+ void testInitialDataTree();
+ void testHeaderData();
+ void testHeaderDataChange();
+ void testFlags();
+ void testDataChanged();
+ void testDataChangedTree();
+ void testDataInsertion();
+ void testDataInsertionTree();
+ void testSetData();
+ void testSetDataTree();
+ void testDataRemoval();
+ void testDataRemovalTree();
+ void testServerInsertDataTree();
+
+ void testRoleNames();
+
+ void testModelTest_data();
+ void testModelTest();
+ void testSortFilterModel();
+
+ void testSelectionFromReplica();
+ void testSelectionFromSource();
+ void testChildSelection();
+
+ void testCacheData_data();
+ void testCacheData();
+
+ void cleanup();
+};
+
+void TestModelView::initTestCase()
+{
+ QLoggingCategory::setFilterRules("qt.remoteobjects.warning=false");
+
+ static const int modelSize = 20;
+
+ QHash<int,QByteArray> roleNames;
+ roleNames[Qt::DisplayRole] = "text";
+ roleNames[Qt::BackgroundRole] = "background";
+ m_sourceModel.setItemRoleNames(roleNames);
+
+ QStringList list;
+ list.reserve(modelSize);
+
+ QStringList hHeaderList;
+ hHeaderList << QStringLiteral("First Column with spacing") << QStringLiteral("Second Column with spacing");
+ m_sourceModel.setHorizontalHeaderLabels(hHeaderList);
+
+ for (int i = 0; i < modelSize; ++i) {
+ QStandardItem *firstItem = new QStandardItem(QStringLiteral("FancyTextNumber %1").arg(i));
+ QStandardItem *secondItem = new QStandardItem(QStringLiteral("FancyRow2TextNumber %1").arg(i));
+ if (i % 2 == 0)
+ firstItem->setBackground(Qt::red);
+ firstItem->appendRow(addChild(2,getRandomNumber(1, 4)));
+ QList<QStandardItem*> row;
+ row << firstItem << secondItem;
+ m_sourceModel.appendRow(row);
+ list << QStringLiteral("FancyTextNumber %1").arg(i);
+ }
+
+ const int numElements = 1000;
+ for (int i = 0; i < numElements; ++i) {
+ QString name = QString("Data %1").arg(i);
+ QString pid = QString("%1").arg(i);
+ m_listModel.addPair(name, pid);
+ }
+}
+
+void TestModelView::setup_models(QRemoteObjectHost &basicServer, QRemoteObjectNode &client, QRemoteObjectRegistryHost ®istryServer)
+{
+ static int port = 65211;
+ static const QString url = QStringLiteral("tcp://127.0.0.1:%1");
+
+ // QStandardItem::flags are stored as data with Qt::UserRole - 1
+ static const QList<int> sourceModelRoles( {Qt::DisplayRole, Qt::BackgroundRole, (Qt::UserRole - 1)} );
+
+ static const QList<int> listModelRoles( {Qt::UserRole, Qt::UserRole+1} );
+
+ //Setup registry
+ //Registry needs to be created first until we get the retry mechanism implemented
+ basicServer.setHostUrl(QUrl(url.arg(port)));
+ registryServer.setRegistryUrl(QUrl(url.arg(port+1)));
+ basicServer.setRegistryUrl(QUrl(url.arg(port+1)));
+ basicServer.enableRemoting(&m_sourceModel, "test", sourceModelRoles);
+ basicServer.enableRemoting(&m_listModel, "testRoleNames", listModelRoles);
+ client.setRegistryUrl(QUrl(url.arg(port+1)));
+ port += 2;
+}
+
+#ifdef SLOW_MODELTEST
+#define MODELTEST_WAIT_TIME 25000
+#else
+#define MODELTEST_WAIT_TIME
+#endif
+
+void TestModelView::testEmptyModel()
+{
+ _SETUP_TEST_
+ QList<int> roles = QList<int>() << Qt::DisplayRole << Qt::BackgroundRole;
+ QStandardItemModel emptyModel;
+ basicServer.enableRemoting(&emptyModel, "emptyModel", roles);
+
+ QScopedPointer<QAbstractItemModelReplica> model(client.acquireModel("emptyModel"));
+ model->setRootCacheSize(1000);
+
+ FetchData f(model.data());
+ QVERIFY(f.fetchAndWait(MODELTEST_WAIT_TIME));
+
+ compareData(&emptyModel, model.data());
+}
+
+void TestModelView::testInitialData()
+{
+ _SETUP_TEST_
+ QScopedPointer<QAbstractItemModelReplica> model(client.acquireModel("test"));
+
+ FetchData f(model.data());
+ QVERIFY(f.fetchAndWait(MODELTEST_WAIT_TIME));
+
+ compareData(&m_sourceModel, model.data());
+}
+
+void TestModelView::testInitialDataTree()
+{
+ _SETUP_TEST_
+ QScopedPointer<QAbstractItemModelReplica> model(client.acquireModel("test"));
+
+ FetchData f(model.data());
+ QVERIFY(f.fetchAndWait(MODELTEST_WAIT_TIME));
+
+ compareTreeData(&m_sourceModel, model.data());
+}
+
+void TestModelView::testHeaderData()
+{
+ _SETUP_TEST_
+ QScopedPointer<QAbstractItemModelReplica> model(client.acquireModel("test"));
+
+ FetchData f(model.data());
+ QVERIFY(f.fetchAndWait(MODELTEST_WAIT_TIME));
+
+ // ask for all Data members first, so we don't have to wait for update signals
+ QSignalSpy spyHeader(model.data(), &QAbstractItemModelReplica::headerDataChanged);
+ for (int i = 0; i < m_sourceModel.rowCount(); ++i)
+ model->headerData(i, Qt::Vertical, Qt::DisplayRole);
+ for (int i = 0; i < m_sourceModel.columnCount(); ++i)
+ model->headerData(i, Qt::Horizontal, Qt::DisplayRole);
+ spyHeader.wait();
+
+ for (int i = 0; i < m_sourceModel.rowCount(); ++i)
+ QCOMPARE(model->headerData(i, Qt::Vertical, Qt::DisplayRole), m_sourceModel.headerData(i, Qt::Vertical, Qt::DisplayRole));
+ for (int i = 0; i < m_sourceModel.columnCount(); ++i)
+ QCOMPARE(model->headerData(i, Qt::Horizontal, Qt::DisplayRole), m_sourceModel.headerData(i, Qt::Horizontal, Qt::DisplayRole));
+}
+
+void TestModelView::testHeaderDataChange()
+{
+ _SETUP_TEST_
+ QString newHeader = QStringLiteral("New header name");
+ QScopedPointer<QAbstractItemModelReplica> model(client.acquireModel("test"));
+
+ FetchData f(model.data());
+ QVERIFY(f.fetchAndWait(MODELTEST_WAIT_TIME));
+ QVERIFY(model->headerData(0, Qt::Horizontal, Qt::DisplayRole).toString() != newHeader);
+
+ QSignalSpy spyHeader(model.data(), &QAbstractItemModelReplica::headerDataChanged);
+ m_sourceModel.setHeaderData(0, Qt::Horizontal, newHeader, Qt::DisplayRole);
+ spyHeader.wait();
+ QTRY_COMPARE(model->headerData(0, Qt::Horizontal, Qt::DisplayRole).toString(), newHeader);
+
+ spyHeader.clear();
+ m_sourceModel.setHeaderData(1, Qt::Horizontal, newHeader, Qt::DisplayRole);
+ spyHeader.wait();
+ QTRY_COMPARE(model->headerData(1, Qt::Horizontal, Qt::DisplayRole).toString(), newHeader);
+
+ QString anotherHeader = QStringLiteral("Modified header name");
+ m_sourceModel.setHeaderData(0, Qt::Horizontal, anotherHeader, Qt::DisplayRole);
+ spyHeader.wait();
+
+ QTRY_COMPARE(model->headerData(0, Qt::Horizontal, Qt::DisplayRole).toString(), anotherHeader);
+ QCOMPARE(model->headerData(1, Qt::Horizontal, Qt::DisplayRole).toString(), newHeader);
+}
+
+void TestModelView::testDataChangedTree()
+{
+ _SETUP_TEST_
+ QScopedPointer<QAbstractItemModelReplica> model(client.acquireModel("test"));
+
+ FetchData f(model.data());
+ QVERIFY(f.fetchAndWait(MODELTEST_WAIT_TIME));
+
+ compareTreeData(&m_sourceModel, model.data());
+ QSignalSpy dataChangedSpy(model.data(), &QAbstractItemModelReplica::dataChanged);
+ QSet<int> expected;
+ for (int i = 10; i < 20; ++i) {
+ const QModelIndex parent = m_sourceModel.index(i,0);
+ const int rowCount = m_sourceModel.rowCount(parent);
+ const int colCount = m_sourceModel.columnCount(parent);
+ for (int row = 0; row < rowCount; ++row) {
+ for (int col = 0; col < colCount; ++col) {
+ if (col % 2 == 0)
+ m_sourceModel.setData(m_sourceModel.index(row, col, parent), QColor(Qt::gray), Qt::BackgroundRole);
+ else
+ m_sourceModel.setData(m_sourceModel.index(row, col, parent), QColor(Qt::cyan), Qt::BackgroundRole);
+ }
+ }
+ m_sourceModel.setData(m_sourceModel.index(i, 1), QColor(Qt::magenta), Qt::BackgroundRole);
+ expected << i;
+ }
+
+ bool signalsReceived = false;
+ int runs = 0;
+ const int maxRuns = 10;
+ while (runs < maxRuns) {
+ if (dataChangedSpy.wait() &&!dataChangedSpy.isEmpty()) {
+ signalsReceived = true;
+ for (auto args : dataChangedSpy) {
+ int row = args.at(1).value<QModelIndex>().row();
+ if (row && expected.contains(row))
+ expected.remove(row);
+ }
+ if (expected.size() == 0)
+ break;
+ }
+ ++runs;
+ }
+ QVERIFY(signalsReceived);
+ compareTreeData(&m_sourceModel, model.data());
+}
+
+void TestModelView::testFlags()
+{
+ _SETUP_TEST_
+ QScopedPointer<QAbstractItemModelReplica> model(client.acquireModel("test"));
+
+ FetchData f(model.data());
+ QVERIFY(f.fetchAndWait(MODELTEST_WAIT_TIME));
+
+ QSignalSpy dataChangedSpy(model.data(), &QAbstractItemModelReplica::dataChanged);
+ for (int i = 10; i < 20; ++i) {
+ QStandardItem* firstItem = m_sourceModel.item(i, 0);
+ QStandardItem* secondItem = m_sourceModel.item(i, 1);
+ firstItem->setFlags(firstItem->flags() | Qt::ItemIsEnabled | Qt::ItemIsAutoTristate);
+ secondItem->setFlags(firstItem->flags() | Qt::ItemIsEnabled);
+ }
+ bool signalsReceived = false;
+ while (dataChangedSpy.wait()) {
+ signalsReceived = true;
+ if (dataChangedSpy.takeLast().at(1).value<QModelIndex>().row() == 19)
+ break;
+ }
+ QVERIFY(signalsReceived);
+ compareFlags(&m_sourceModel, model.data());
+}
+
+void TestModelView::testDataChanged()
+{
+ _SETUP_TEST_
+ QScopedPointer<QAbstractItemModelReplica> model(client.acquireModel("test"));
+
+ FetchData f(model.data());
+ QVERIFY(f.fetchAndWait(MODELTEST_WAIT_TIME));
+
+ QSignalSpy dataChangedSpy(model.data(), &QAbstractItemModelReplica::dataChanged);
+ for (int i = 10; i < 20; ++i)
+ m_sourceModel.setData(m_sourceModel.index(i, 1), QColor(Qt::blue), Qt::BackgroundRole);
+
+ bool signalsReceived = false;
+ while (dataChangedSpy.wait()) {
+ signalsReceived = true;
+ if (dataChangedSpy.takeLast().at(1).value<QModelIndex>().row() == 19)
+ break;
+ }
+ QVERIFY(signalsReceived);
+ compareData(&m_sourceModel, model.data());
+}
+
+void TestModelView::testDataInsertion()
+{
+ _SETUP_TEST_
+ QScopedPointer<QAbstractItemModelReplica> model(client.acquireModel("test"));
+
+ FetchData f(model.data());
+ QVERIFY(f.fetchAndWait(MODELTEST_WAIT_TIME));
+
+ const int insertedRowsCount = 9;
+ RowsWatcher watcher(model.data(), insertedRowsCount);
+ QList<QModelIndex> pending;
+
+ m_sourceModel.insertRows(2, insertedRowsCount);
+
+ watcher.scheduleRowsToWatch(QModelIndex(), 2, 2 + insertedRowsCount - 1);
+ QVERIFY(watcher.wait());
+ QCOMPARE(m_sourceModel.rowCount(), model->rowCount());
+
+ pending.append(watcher.changedData());
+
+ // change one row to check for inconsistencies
+ m_sourceModel.setData(m_sourceModel.index(0, 1), QColor(Qt::green), Qt::BackgroundRole);
+ m_sourceModel.setData(m_sourceModel.index(0, 1), QLatin1String("foo"), Qt::DisplayRole);
+ pending.append(model->index(0, 1));
+ WaitForDataChanged w(model.data(), pending);
+
+ QVERIFY(w.wait());
+ compareData(&m_sourceModel, model.data());
+}
+
+void TestModelView::testDataInsertionTree()
+{
+ _SETUP_TEST_
+ QScopedPointer<QAbstractItemModelReplica> model(client.acquireModel("test"));
+
+ FetchData f(model.data());
+ QVERIFY(f.fetchAndWait(MODELTEST_WAIT_TIME));
+
+ const int insertedRowsCount = 9;
+ const int insertedChildRowsCount = 4;
+ RowsWatcher watcher(model.data(), insertedRowsCount + insertedChildRowsCount);
+
+ QList<QModelIndex> pending;
+
+ for (int i = 0; i < insertedRowsCount; ++i) {
+ watcher.scheduleRowsToWatch(QModelIndex(), 2 + i, 2 + i);
+ m_sourceModel.insertRow(2 + i, createInsertionChildren(2, QStringLiteral("insertedintree"), Qt::darkRed));
+ const QModelIndex childIndex = m_sourceModel.index(2 + i, 0);
+ const QModelIndex childIndex2 = m_sourceModel.index(2 + i, 1);
+ pending.append(childIndex);
+ pending.append(childIndex2);
+ }
+ const QModelIndex parent = m_sourceModel.index(10, 0);
+ QStandardItem* parentItem = m_sourceModel.item(10, 0);
+ for (int i = 0; i < insertedChildRowsCount; ++i) {
+ watcher.scheduleRowsToWatch(parent, i, i);
+ parentItem->insertRow(i, createInsertionChildren(2, QStringLiteral("insertedintreedeep"), Qt::darkCyan));
+ const QModelIndex childIndex = m_sourceModel.index(0, 0, parent);
+ const QModelIndex childIndex2 = m_sourceModel.index(0, 1, parent);
+ Q_ASSERT(childIndex.isValid());
+ Q_ASSERT(childIndex2.isValid());
+ pending.append(childIndex);
+ pending.append(childIndex2);
+ }
+
+ QVERIFY(watcher.wait());
+ QCOMPARE(m_sourceModel.rowCount(), model->rowCount());
+
+ pending.append(watcher.changedData());
+
+ // change one row to check for inconsistencies
+
+ pending << m_sourceModel.index(0, 0, parent);
+ WaitForDataChanged w(model.data(), pending);
+ m_sourceModel.setData(m_sourceModel.index(0, 0, parent), QColor(Qt::green), Qt::BackgroundRole);
+ m_sourceModel.setData(m_sourceModel.index(0, 0, parent), QLatin1String("foo"), Qt::DisplayRole);
+
+ QVERIFY(w.wait());
+
+ compareTreeData(&m_sourceModel, model.data());
+}
+
+void TestModelView::testDataRemoval()
+{
+ _SETUP_TEST_
+ QScopedPointer<QAbstractItemModelReplica> model(client.acquireModel("test"));
+ qputenv("QTRO_NODES_CACHE_SIZE", "1000");
+ model->setRootCacheSize(1000);
+ FetchData f(model.data());
+ QVERIFY(f.fetchAndWait(MODELTEST_WAIT_TIME));
+
+ const QPersistentModelIndex parent = m_sourceModel.index(10, 0);
+ {
+ const int removedRowsCount = 3;
+ RowsWatcher watcher(model.data(), removedRowsCount);
+ m_sourceModel.removeRows(0, removedRowsCount, parent);
+ watcher.scheduleRowsToWatch(parent, 0, removedRowsCount - 1);
+ QVERIFY(watcher.wait());
+ QCOMPARE(m_sourceModel.rowCount(parent), model->rowCount(model->index(10, 0)));
+ }
+ {
+ const int removedRowsCount = 8;
+ RowsWatcher watcher(model.data(), removedRowsCount);
+ m_sourceModel.removeRows(2, removedRowsCount);
+ watcher.scheduleRowsToWatch(QModelIndex(), 2, 2 + removedRowsCount - 1);
+ QVERIFY(watcher.wait());
+ QCOMPARE(m_sourceModel.rowCount(), model->rowCount());
+ }
+
+ // change one row to check for inconsistencies
+
+ QList<QModelIndex> pending;
+ pending << m_sourceModel.index(0, 0, parent);
+ WaitForDataChanged w(model.data(), pending);
+ m_sourceModel.setData(m_sourceModel.index(0, 0, parent), QColor(Qt::green), Qt::BackgroundRole);
+ m_sourceModel.setData(m_sourceModel.index(0, 0, parent), QLatin1String("foo"), Qt::DisplayRole);
+
+ QVERIFY(w.wait());
+
+ compareTreeData(&m_sourceModel, model.data());
+}
+
+void TestModelView::testRoleNames()
+{
+ _SETUP_TEST_
+ QScopedPointer<QAbstractItemModelReplica> repModel( client.acquireModel(QStringLiteral("testRoleNames")));
+ // Set a bigger cache enough to keep all the data otherwise the last test will fail
+ repModel->setRootCacheSize(1500);
+ FetchData f(repModel.data());
+ QVERIFY(f.fetchAndWait(MODELTEST_WAIT_TIME));
+
+ // test custom role names
+ QCOMPARE(repModel.data()->roleNames(), m_listModel.roleNames());
+
+ // test data associated with custom roles
+ compareData(&m_listModel,repModel.data());
+}
+
+void TestModelView::testDataRemovalTree()
+{
+ _SETUP_TEST_
+ m_sourceModel.removeRows(2, 4);
+ //Maybe some checks here?
+}
+
+void TestModelView::testServerInsertDataTree()
+{
+ _SETUP_TEST_
+ QList<int> roles = QList<int> { Qt::DisplayRole, Qt::BackgroundRole };
+ QStandardItemModel testTreeModel;
+ basicServer.enableRemoting(&testTreeModel, "testTreeModel", roles);
+
+ QScopedPointer<QAbstractItemModelReplica> model(client.acquireModel("testTreeModel"));
+
+ QTRY_COMPARE(testTreeModel.rowCount(), model->rowCount());
+
+ QVERIFY(testTreeModel.insertRow(0));
+ QVERIFY(testTreeModel.insertColumn(0));
+ auto root = testTreeModel.index(0, 0);
+ QVERIFY(testTreeModel.setData(root, QLatin1String("Root"), Qt::DisplayRole));
+ QVERIFY(testTreeModel.setData(root, QColor(Qt::green), Qt::BackgroundRole));
+ QVERIFY(testTreeModel.insertRow(0, root));
+ QVERIFY(testTreeModel.insertColumn(0, root));
+ auto child1 = testTreeModel.index(0, 0, root);
+ QVERIFY(testTreeModel.setData(child1, QLatin1String("Child1"), Qt::DisplayRole));
+ QVERIFY(testTreeModel.setData(child1, QColor(Qt::red), Qt::BackgroundRole));
+
+ QTRY_COMPARE(testTreeModel.rowCount(), model->rowCount());
+
+ FetchData f(model.data());
+ QVERIFY(f.fetchAndWait(MODELTEST_WAIT_TIME));
+
+ compareData(&testTreeModel, model.data());
+}
+
+void TestModelView::testModelTest_data()
+{
+ // QtRemoteObjects::InitialAction is a namespace enum. QTest/QFETCH fail to compile with it as
+ // the column type, so use bool instead.
+ QTest::addColumn<bool>("prefetch");
+
+ QTest::newRow("size only") << false;
+ QTest::newRow("prefetch") << true;
+}
+
+void TestModelView::testModelTest()
+{
+ QFETCH(bool, prefetch);
+ _SETUP_TEST_
+ QtRemoteObjects::InitialAction action = QtRemoteObjects::InitialAction::FetchRootSize;
+ if (prefetch)
+ action = QtRemoteObjects::InitialAction::PrefetchData;
+ QScopedPointer<QAbstractItemModelReplica> repModel( client.acquireModel(QStringLiteral("test"), action));
+ QAbstractItemModelTester test(repModel.data(), QAbstractItemModelTester::FailureReportingMode::Fatal);
+
+ FetchData f(repModel.data());
+ QVERIFY(f.fetchAndWait(MODELTEST_WAIT_TIME));
+ Q_UNUSED(test)
+}
+
+void TestModelView::testSortFilterModel()
+{
+ _SETUP_TEST_
+ QScopedPointer<QAbstractItemModelReplica> repModel( client.acquireModel(QStringLiteral("test")));
+
+ FetchData f(repModel.data());
+ QVERIFY(f.fetchAndWait(MODELTEST_WAIT_TIME));
+
+ QSortFilterProxyModel clientSort;
+ clientSort.setSourceModel(repModel.data());
+ clientSort.setSortRole(Qt::DisplayRole);
+ QSortFilterProxyModel sourceSort;
+ sourceSort.setSourceModel(&m_sourceModel);
+ sourceSort.setSortRole(Qt::DisplayRole);
+
+ compareTreeData(&sourceSort, &clientSort, repModel->availableRoles());
+}
+
+void TestModelView::testSetData()
+{
+ _SETUP_TEST_
+ QScopedPointer<QAbstractItemModelReplica> model(client.acquireModel("test"));
+
+ FetchData f(model.data());
+ QVERIFY(f.fetchAndWait(MODELTEST_WAIT_TIME));
+ compareTreeData(&m_sourceModel, model.data(), model->availableRoles());
+
+ //fetched and verified initial state, now setData on the client
+ QList<QModelIndex> pending;
+ QList<QModelIndex> pendingReplica;
+ for (int row = 0, numRows = model->rowCount(); row < numRows; ++row) {
+ for (int column = 0, numColumns = model->columnCount(); column != numColumns; ++column) {
+ const QModelIndex index = model->index(row, column);
+ const QString newData = QStringLiteral("This entry was changed with setData");
+ QVERIFY(model->setData(index, newData, Qt::DisplayRole));
+ pending.append(m_sourceModel.index(row, column));
+ pendingReplica.append(model->index(row, column));
+ }
+ }
+ WaitForDataChanged waiter(&m_sourceModel, pending);
+ QVERIFY(waiter.wait());
+ WaitForDataChanged waiterReplica(model.data(), pendingReplica);
+ QVERIFY(waiterReplica.wait());
+ compareData(&m_sourceModel, model.data());
+}
+
+void TestModelView::testSetDataTree()
+{
+ _SETUP_TEST_
+ QScopedPointer<QAbstractItemModelReplica> model(client.acquireModel("test"));
+
+ FetchData f(model.data());
+ QVERIFY(f.fetchAndWait(MODELTEST_WAIT_TIME));
+ compareTreeData(&m_sourceModel, model.data(), model->availableRoles());
+
+ //fetched and verified initial state, now setData on the client
+ QList<QModelIndex> pending;
+ QList<QModelIndex> pendingReplica;
+
+ QList<QModelIndex> stack;
+ stack.push_back(QModelIndex());
+ QList<QModelIndex> sourceStack;
+ sourceStack.push_back(QModelIndex());
+
+
+ const QString newData = QStringLiteral("This entry was changed with setData in a tree %1 %2 %3");
+ while (!stack.isEmpty()) {
+ const QModelIndex parent = stack.takeLast();
+ const QModelIndex parentSource = sourceStack.takeLast();
+ for (int row = 0; row < model->rowCount(parent); ++row) {
+ for (int column = 0; column < model->columnCount(parent); ++column) {
+ const QModelIndex index = model->index(row, column, parent);
+ const QModelIndex indexSource = m_sourceModel.index(row, column, parentSource);
+ QVERIFY(model->setData(index, newData.arg(parent.isValid()).arg(row).arg(column), Qt::DisplayRole));
+ pending.append(indexSource);
+ pendingReplica.append(index);
+ if (column == 0) {
+ stack.push_back(index);
+ sourceStack.push_back(indexSource);
+ }
+ }
+ }
+ }
+ WaitForDataChanged waiter(&m_sourceModel, pending);
+ QVERIFY(waiter.wait());
+ WaitForDataChanged waiterReplica(model.data(), pendingReplica);
+ QVERIFY(waiterReplica.wait());
+ compareData(&m_sourceModel, model.data());
+}
+
+void TestModelView::testSelectionFromReplica()
+{
+ _SETUP_TEST_
+ QList<int> roles = QList<int> { Qt::DisplayRole, Qt::BackgroundRole };
+ QStandardItemModel simpleModel;
+ for (int i = 0; i < 4; ++i)
+ simpleModel.appendRow(new QStandardItem(QString("item %0").arg(i)));
+ QItemSelectionModel selectionModel(&simpleModel);
+ basicServer.enableRemoting(&simpleModel, "simpleModelFromReplica", roles, &selectionModel);
+
+ QScopedPointer<QAbstractItemModelReplica> model(client.acquireModel("simpleModelFromReplica"));
+ QItemSelectionModel *replicaSelectionModel = model->selectionModel();
+
+ FetchData f(model.data());
+ QVERIFY(f.fetchAndWait(MODELTEST_WAIT_TIME));
+
+ replicaSelectionModel->setCurrentIndex(model->index(1,0), QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Current);
+ QTRY_COMPARE(selectionModel.currentIndex().row(), 1);
+}
+
+void TestModelView::testSelectionFromSource()
+{
+ _SETUP_TEST_
+ QList<int> roles = QList<int> { Qt::DisplayRole, Qt::BackgroundRole };
+ QStandardItemModel simpleModel;
+ for (int i = 0; i < 4; ++i)
+ simpleModel.appendRow(new QStandardItem(QString("item %0").arg(i)));
+ QItemSelectionModel selectionModel(&simpleModel);
+ basicServer.enableRemoting(&simpleModel, "simpleModelFromSource", roles, &selectionModel);
+
+ QScopedPointer<QAbstractItemModelReplica> model(client.acquireModel("simpleModelFromSource"));
+ QItemSelectionModel *replicaSelectionModel = model->selectionModel();
+
+ FetchData f(model.data());
+ QVERIFY(f.fetchAndWait(MODELTEST_WAIT_TIME));
+
+ selectionModel.setCurrentIndex(simpleModel.index(1,0), QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Current);
+ QTRY_COMPARE(replicaSelectionModel->currentIndex().row(), 1);
+}
+
+void TestModelView::testCacheData_data()
+{
+ QTest::addColumn<QList<int>>("roles");
+
+ QTest::newRow("empty") << QList<int> {};
+ QTest::newRow("all") << QList<int> { Qt::UserRole, Qt::UserRole + 1 };
+}
+
+void TestModelView::testCacheData()
+{
+ QFETCH(QList<int>, roles);
+
+ _SETUP_TEST_
+ QScopedPointer<QAbstractItemModelReplica> model(client.acquireModel("testRoleNames", QtRemoteObjects::PrefetchData, roles));
+ model->setRootCacheSize(1000);
+
+ QEventLoop l;
+ connect(model.data(), &QAbstractItemModelReplica::initialized, &l, &QEventLoop::quit);
+ l.exec();
+
+ compareData(&m_listModel, model.data());
+}
+
+void TestModelView::testChildSelection()
+{
+ _SETUP_TEST_
+ QList<int> roles = { Qt::DisplayRole, Qt::BackgroundRole };
+ QStandardItemModel simpleModel;
+ QStandardItem *parentItem = simpleModel.invisibleRootItem();
+ for (int i = 0; i < 4; ++i) {
+ QStandardItem *item = new QStandardItem(QString("item %0").arg(i));
+ parentItem->appendRow(item);
+ parentItem = item;
+ }
+ QItemSelectionModel selectionModel(&simpleModel);
+ basicServer.enableRemoting(&simpleModel, "treeModelFromSource", roles, &selectionModel);
+
+ QScopedPointer<QAbstractItemModelReplica> model(client.acquireModel("treeModelFromSource", QtRemoteObjects::PrefetchData, roles));
+ QItemSelectionModel *replicaSelectionModel = model->selectionModel();
+
+ QTRY_COMPARE(simpleModel.rowCount(), model->rowCount());
+ QTRY_COMPARE(model->data(model->index(0, 0)), QVariant(QString("item 0")));
+
+ // select an item not yet "seen" by the replica
+ selectionModel.setCurrentIndex(simpleModel.index(0, 0, simpleModel.index(0,0)), QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Current);
+ QTRY_COMPARE(replicaSelectionModel->currentIndex().row(), 0);
+ QVERIFY(replicaSelectionModel->currentIndex().parent().isValid());
+}
+
+void TestModelView::cleanup()
+{
+ // wait for delivery of RemoveObject events to the source
+ QTest::qWait(20);
+}
+
+QTEST_MAIN(TestModelView)
+
+#include "tst_modelview.moc"
--- /dev/null
+
+#####################################################################
+## tst_pods Test:
+#####################################################################
+
+qt_internal_add_test(tst_pods
+ SOURCES
+ tst_pods.cpp
+ PUBLIC_LIBRARIES
+ Qt::RemoteObjects
+)
+qt6_add_repc_replicas(tst_pods
+ pods.h
+)
+
+## Scopes:
+#####################################################################
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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 with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#pragma once
+// This is an autogenerated file.
+// Do not edit this file, any changes made will be lost the next time it is generated.
+
+#include <QObject>
+
+
+#include <QString>
+class PodI
+{
+ Q_GADGET
+ Q_PROPERTY(int i READ i WRITE setI)
+public:
+ explicit PodI() : _i() {}
+ explicit PodI(int i) : _i(i) {}
+ PodI(const PodI& other)
+ {
+ QtRemoteObjects::copyStoredProperties(&other, this);
+ }
+
+ PodI &operator=(const PodI &other)
+ {
+ if (this != &other)
+ QtRemoteObjects::copyStoredProperties(&other, this);
+ return *this;
+ }
+
+ int i() const { return _i; }
+ void setI(int i) { if (i != _i) { _i = i; } }
+private:
+ int _i;
+};
+
+inline QDataStream &operator<<(QDataStream &ds, const PodI &obj) {
+ QtRemoteObjects::copyStoredProperties(&obj, ds);
+ return ds;
+}
+
+inline QDataStream &operator>>(QDataStream &ds, PodI &obj) {
+ QtRemoteObjects::copyStoredProperties(ds, &obj);
+ return ds;
+}
+
+class PodF
+{
+ Q_GADGET
+ Q_PROPERTY(float f READ f WRITE setF)
+public:
+ explicit PodF() : _f() {}
+ explicit PodF(float f) : _f(f) {}
+ PodF(const PodF& other)
+ {
+ QtRemoteObjects::copyStoredProperties(&other, this);
+ }
+
+ PodF &operator=(const PodF &other)
+ {
+ if (this != &other)
+ QtRemoteObjects::copyStoredProperties(&other, this);
+ return *this;
+ }
+
+ float f() const { return _f; }
+ void setF(float f) { if (f != _f) { _f = f; } }
+private:
+ float _f;
+};
+
+inline QDataStream &operator<<(QDataStream &ds, const PodF &obj) {
+ QtRemoteObjects::copyStoredProperties(&obj, ds);
+ return ds;
+}
+
+inline QDataStream &operator>>(QDataStream &ds, PodF &obj) {
+ QtRemoteObjects::copyStoredProperties(ds, &obj);
+ return ds;
+}
+
+class PodS
+{
+ Q_GADGET
+ Q_PROPERTY(QString s READ s WRITE setS)
+public:
+ explicit PodS() : _s() {}
+ explicit PodS(QString s) : _s(s) {}
+ PodS(const PodS& other)
+ {
+ QtRemoteObjects::copyStoredProperties(&other, this);
+ }
+
+ PodS &operator=(const PodS &other)
+ {
+ if (this != &other)
+ QtRemoteObjects::copyStoredProperties(&other, this);
+ return *this;
+ }
+
+ QString s() const { return _s; }
+ void setS(QString s) { if (s != _s) { _s = s; } }
+private:
+ QString _s;
+};
+
+inline QDataStream &operator<<(QDataStream &ds, const PodS &obj) {
+ QtRemoteObjects::copyStoredProperties(&obj, ds);
+ return ds;
+}
+
+inline QDataStream &operator>>(QDataStream &ds, PodS &obj) {
+ QtRemoteObjects::copyStoredProperties(ds, &obj);
+ return ds;
+}
+
+class PodIFS
+{
+ Q_GADGET
+ Q_PROPERTY(int i READ i WRITE setI)
+ Q_PROPERTY(float f READ f WRITE setF)
+ Q_PROPERTY(QString s READ s WRITE setS)
+public:
+ explicit PodIFS() : _i(), _f(), _s() {}
+ explicit PodIFS(int i, float f, QString s) : _i(i), _f(f), _s(s) {}
+ PodIFS(const PodIFS& other)
+ {
+ QtRemoteObjects::copyStoredProperties(&other, this);
+ }
+
+ PodIFS &operator=(const PodIFS &other)
+ {
+ if (this != &other)
+ QtRemoteObjects::copyStoredProperties(&other, this);
+ return *this;
+ }
+
+ int i() const { return _i; }
+ void setI(int i) { if (i != _i) { _i = i; } }
+ float f() const { return _f; }
+ void setF(float f) { if (f != _f) { _f = f; } }
+ QString s() const { return _s; }
+ void setS(QString s) { if (s != _s) { _s = s; } }
+private:
+ int _i;
+ float _f;
+ QString _s;
+};
+
+inline QDataStream &operator<<(QDataStream &ds, const PodIFS &obj) {
+ QtRemoteObjects::copyStoredProperties(&obj, ds);
+ return ds;
+}
+
+inline QDataStream &operator>>(QDataStream &ds, PodIFS &obj) {
+ QtRemoteObjects::copyStoredProperties(ds, &obj);
+ return ds;
+}
+
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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 with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "rep_pods_replica.h"
+
+#include <QTest>
+
+#include <QByteArray>
+#include <QDataStream>
+
+class tst_pods : public QObject {
+ Q_OBJECT
+
+private Q_SLOTS:
+ void testConstructors();
+ void testMarshalling();
+};
+
+
+void tst_pods::testConstructors()
+{
+ PodI pi1;
+ QCOMPARE(pi1.i(), 0);
+
+ PodI pi2(1);
+ QCOMPARE(pi2.i(), 1);
+
+ PodI pi3(pi2);
+ QCOMPARE(pi3.i(), pi2.i());
+}
+
+void tst_pods::testMarshalling()
+{
+ QByteArray ba;
+ QDataStream ds(&ba, QIODevice::ReadWrite);
+
+ {
+ PodI i1(1), i2(2), i3(3), iDeadBeef(0xdeadbeef);
+ ds << i1 << i2 << i3 << iDeadBeef;
+ }
+
+ ds.device()->seek(0);
+
+ {
+ PodI i1, i2, i3, iDeadBeef;
+ ds >> i1 >> i2 >> i3 >> iDeadBeef;
+
+ QCOMPARE(i1.i(), 1);
+ QCOMPARE(i2.i(), 2);
+ QCOMPARE(i3.i(), 3);
+ QCOMPARE(iDeadBeef.i(), int(0xdeadbeef));
+ }
+}
+
+QTEST_APPLESS_MAIN(tst_pods)
+
+#include "tst_pods.moc"
+
--- /dev/null
+
+#####################################################################
+## tst_proxy Test:
+#####################################################################
+
+qt_internal_add_test(tst_proxy
+ SOURCES
+ tst_proxy.cpp
+ ../shared/model_utilities.h
+ PUBLIC_LIBRARIES
+ Qt::RemoteObjects
+)
+qt6_add_repc_merged(tst_proxy
+ engine.rep
+ subclass.rep
+)
+
+## Scopes:
+#####################################################################
--- /dev/null
+class Engine
+{
+ ENUM EngineType {Null, Gas, Electric, Hybrid};
+ PROP(int cylinders = 4)
+ PROP(bool started)
+ PROP(int rpm)
+ PROP(EngineType type)
+}
--- /dev/null
+POD MyPOD(int i, float f, QString s)
+
+class SubClass
+{
+ PROP(MyPOD myPOD)
+}
+
+class ParentClass
+{
+ CLASS subClass(SubClass)
+ MODEL tracks(display)
+}
+
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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 with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "rep_engine_merged.h"
+#include "rep_subclass_merged.h"
+#include "../shared/model_utilities.h"
+
+#include <QtTest/QtTest>
+#include <QRemoteObjectReplica>
+#include <QRemoteObjectNode>
+
+const QUrl localHostUrl = QUrl(QLatin1String("local:testHost"));
+const QUrl tcpHostUrl = QUrl(QLatin1String("tcp://127.0.0.1:9989"));
+const QUrl proxyNodeUrl = QUrl(QLatin1String("tcp://127.0.0.1:12123"));
+const QUrl remoteNodeUrl = QUrl(QLatin1String("tcp://127.0.0.1:23234"));
+const QUrl registryUrl = QUrl(QLatin1String("local:testRegistry"));
+const QUrl proxyHostUrl = QUrl(QLatin1String("local:fromProxy"));
+
+#define SET_NODE_NAME(obj) (obj).setName(QLatin1String(#obj))
+
+class ProxyTest : public QObject
+{
+ Q_OBJECT
+private Q_SLOTS:
+ void cleanup()
+ {
+ // wait for delivery of RemoveObject events to the source
+ QTest::qWait(200);
+ }
+
+ void testProxy_data();
+ void testProxy();
+ void testForwardProxy();
+ void testReverseProxy();
+ // The following should fail to compile, verifying the SourceAPI templates work
+ // for subclasses
+ /*
+ void testSubclass()
+ {
+ QRemoteObjectHost host(localHostUrl);
+
+ struct invalidchild {
+ MyPOD myPOD() { return MyPOD(12, 13.f, QStringLiteral("Yay!")); }
+ };
+ struct badparent {
+ invalidchild *subClass() { return new invalidchild; }
+ } parent;
+ host.enableRemoting<ParentClassSourceAPI>(&parent);
+ }
+ */
+
+ void testTopLevelModel();
+};
+
+void ProxyTest::testProxy_data()
+{
+ QTest::addColumn<bool>("sourceApi");
+ QTest::addColumn<bool>("useProxy");
+ QTest::addColumn<bool>("dynamic");
+
+ QTest::newRow("dynamicApi, no proxy") << false << false << false;
+ QTest::newRow("sourceApi, no proxy") << true << false << false;
+ QTest::newRow("dynamicApi, with proxy") << false << true << false;
+ QTest::newRow("sourceApi, with proxy") << true << true << false;
+ QTest::newRow("dynamicApi, no proxy, dynamicRep") << false << false << true;
+ QTest::newRow("sourceApi, no proxy, dynamicRep") << true << false << true;
+ QTest::newRow("dynamicApi, with proxy, dynamicRep") << false << true << true;
+ QTest::newRow("sourceApi, with proxy, dynamicRep") << true << true << true;
+}
+
+void ProxyTest::testProxy()
+{
+ QFETCH(bool, sourceApi);
+ QFETCH(bool, useProxy);
+ QFETCH(bool, dynamic);
+
+ //Setup Local Registry
+ QRemoteObjectRegistryHost registry(registryUrl);
+ SET_NODE_NAME(registry);
+ //Setup Local Host
+ QRemoteObjectHost host(localHostUrl);
+ SET_NODE_NAME(host);
+ host.setRegistryUrl(registryUrl);
+ EngineSimpleSource engine;
+ engine.setRpm(1234);
+ engine.setType(EngineSimpleSource::Gas);
+ if (sourceApi)
+ host.enableRemoting<EngineSourceAPI>(&engine);
+ else
+ host.enableRemoting(&engine);
+
+ QRemoteObjectHost proxyNode;
+ SET_NODE_NAME(proxyNode);
+ if (useProxy) {
+ proxyNode.setHostUrl(tcpHostUrl);
+ proxyNode.proxy(registryUrl);
+ }
+
+ //Setup Local Replica
+ QRemoteObjectNode client;
+ SET_NODE_NAME(client);
+ if (useProxy)
+ client.connectToNode(tcpHostUrl);
+ else
+ client.setRegistryUrl(registryUrl);
+
+ QScopedPointer<QRemoteObjectReplica> replica;
+ if (!dynamic) {
+ //QLoggingCategory::setFilterRules("qt.remoteobjects*=true");
+ replica.reset(client.acquire<EngineReplica>());
+ QVERIFY(replica->waitForSource(1000));
+
+ EngineReplica *rep = qobject_cast<EngineReplica *>(replica.data());
+
+ //Compare Replica to Source
+ QCOMPARE(rep->rpm(), engine.rpm());
+ QCOMPARE(EngineReplica::EngineType(rep->type()), EngineReplica::Gas);
+
+ //Change Replica and make sure change propagates to source
+ QSignalSpy sourceSpy(&engine, &EngineSimpleSource::rpmChanged);
+ QSignalSpy replicaSpy(rep, &EngineReplica::rpmChanged);
+ rep->pushRpm(42);
+ sourceSpy.wait();
+ QCOMPARE(sourceSpy.count(), 1);
+ QCOMPARE(engine.rpm(), 42);
+
+ // ... and the change makes it back to the replica
+ replicaSpy.wait();
+ QCOMPARE(replicaSpy.count(), 1);
+ QCOMPARE(rep->rpm(), 42);
+ } else {
+ replica.reset(client.acquireDynamic(QStringLiteral("Engine")));
+ QVERIFY(replica->waitForSource(1000));
+
+ //Compare Replica to Source
+ const QMetaObject *metaObject = replica->metaObject();
+ const int rpmIndex = metaObject->indexOfProperty("rpm");
+ Q_ASSERT(rpmIndex != -1);
+ const QMetaProperty rpmMeta = metaObject->property(rpmIndex);
+ QCOMPARE(rpmMeta.read(replica.data()).value<int>(), engine.rpm());
+ const int typeIndex = metaObject->indexOfProperty("type");
+ Q_ASSERT(typeIndex != -1);
+ const QMetaProperty typeMeta = metaObject->property(typeIndex);
+ QCOMPARE(typeMeta.read(replica.data()).value<EngineReplica::EngineType>(), EngineReplica::Gas);
+
+ //Change Replica and make sure change propagates to source
+ QSignalSpy sourceSpy(&engine, &EngineSimpleSource::rpmChanged);
+ QSignalSpy replicaSpy(replica.data(), QByteArray(QByteArrayLiteral("2")+rpmMeta.notifySignal().methodSignature().constData()));
+
+ const int rpmPushIndex = metaObject->indexOfMethod("pushRpm(int)");
+ Q_ASSERT(rpmPushIndex != -1);
+ QMetaMethod pushMethod = metaObject->method(rpmPushIndex);
+ Q_ASSERT(pushMethod.isValid());
+ QVERIFY(pushMethod.invoke(replica.data(), Q_ARG(int, 42)));
+
+ sourceSpy.wait();
+ QCOMPARE(sourceSpy.count(), 1);
+ QCOMPARE(engine.rpm(), 42);
+
+ // ... and the change makes it back to the replica
+ replicaSpy.wait();
+ QCOMPARE(replicaSpy.count(), 1);
+ QCOMPARE(rpmMeta.read(replica.data()).value<int>(), engine.rpm());
+ }
+
+ // Make sure disabling the Source cascades the state change
+ bool res = host.disableRemoting(&engine);
+ Q_ASSERT(res);
+ QSignalSpy stateSpy(replica.data(), &QRemoteObjectReplica::stateChanged);
+ stateSpy.wait();
+ QCOMPARE(stateSpy.count(), 1);
+ QCOMPARE(replica->state(), QRemoteObjectReplica::Suspect);
+
+ // Now test subclass Source
+ ParentClassSimpleSource parent;
+ SubClassSimpleSource subclass;
+ const MyPOD initialValue(42, 3.14f, QStringLiteral("SubClass"));
+ subclass.setMyPOD(initialValue);
+ QStringListModel model;
+ model.setStringList(QStringList() << "Track1" << "Track2" << "Track3");
+ parent.setSubClass(&subclass);
+ parent.setTracks(&model);
+ QCOMPARE(subclass.myPOD(), initialValue);
+ if (sourceApi)
+ host.enableRemoting<ParentClassSourceAPI>(&parent);
+ else
+ host.enableRemoting(&parent);
+ if (!dynamic) {
+ replica.reset(client.acquire<ParentClassReplica>());
+ ParentClassReplica *rep = qobject_cast<ParentClassReplica *>(replica.data());
+ QSignalSpy tracksSpy(rep->tracks(), &QAbstractItemModelReplica::initialized);
+ QVERIFY(replica->waitForSource(1000));
+ //QLoggingCategory::setFilterRules("qt.remoteobjects*=false");
+
+ //Compare Replica to Source
+ QVERIFY(rep->subClass() != nullptr);
+ QCOMPARE(rep->subClass()->myPOD(), parent.subClass()->myPOD());
+ QVERIFY(rep->tracks() != nullptr);
+ QVERIFY(tracksSpy.count() || tracksSpy.wait());
+ // Rep file only uses display role, but proxy doesn't forward that yet
+ if (!useProxy)
+ QCOMPARE(rep->tracks()->availableRoles(), QList<int> { Qt::DisplayRole });
+ else {
+ const auto &availableRolesVec = rep->tracks()->availableRoles();
+ QSet<int> availableRoles;
+ for (int r : availableRolesVec)
+ availableRoles.insert(r);
+ const auto &rolesHash = model.roleNames();
+ QSet<int> roles;
+ for (auto it = rolesHash.cbegin(), end = rolesHash.cend(); it != end; ++it)
+ roles.insert(it.key());
+ QCOMPARE(availableRoles, roles);
+ }
+ QList<QModelIndex> pending;
+ QTRY_COMPARE(rep->tracks()->rowCount(), model.rowCount());
+ for (int i = 0; i < rep->tracks()->rowCount(); i++)
+ {
+ // We haven't received any data yet
+ const auto index = rep->tracks()->index(i, 0);
+ QCOMPARE(rep->tracks()->data(index), QVariant());
+ pending.append(index);
+ }
+ if (useProxy) { // A first batch of updates will be the empty proxy values
+ WaitForDataChanged w(rep->tracks(), pending);
+ QVERIFY(w.wait());
+ }
+ WaitForDataChanged w(rep->tracks(), pending);
+ QVERIFY(w.wait());
+ for (int i = 0; i < rep->tracks()->rowCount(); i++)
+ {
+ QTRY_COMPARE(rep->tracks()->data(rep->tracks()->index(i, 0)), model.data(model.index(i), Qt::DisplayRole));
+ }
+
+ //Change SubClass and make sure change propagates
+ SubClassSimpleSource updatedSubclass;
+ const MyPOD updatedValue(-1, 123.456f, QStringLiteral("Updated"));
+ updatedSubclass.setMyPOD(updatedValue);
+ QSignalSpy replicaSpy(rep, &ParentClassReplica::subClassChanged);
+ parent.setSubClass(&updatedSubclass);
+ replicaSpy.wait();
+ QCOMPARE(replicaSpy.count(), 1);
+ QCOMPARE(rep->subClass()->myPOD(), parent.subClass()->myPOD());
+ QCOMPARE(rep->subClass()->myPOD(), updatedValue);
+ } else {
+ replica.reset(client.acquireDynamic(QStringLiteral("ParentClass")));
+ QVERIFY(replica->waitForSource(1000));
+
+ const QMetaObject *metaObject = replica->metaObject();
+ // Verify subClass pointer
+ const int subclassIndex = metaObject->indexOfProperty("subClass");
+ QVERIFY(subclassIndex != -1);
+ const QMetaProperty subclassMeta = metaObject->property(subclassIndex);
+ QObject *subclassQObjectPtr = subclassMeta.read(replica.data()).value<QObject *>();
+ QVERIFY(subclassQObjectPtr != nullptr);
+ QRemoteObjectDynamicReplica *subclassReplica = qobject_cast<QRemoteObjectDynamicReplica *>(subclassQObjectPtr);
+ QVERIFY(subclassReplica != nullptr);
+ // Verify tracks pointer
+ const int tracksIndex = metaObject->indexOfProperty("tracks");
+ QVERIFY(tracksIndex != -1);
+ const QMetaProperty tracksMeta = metaObject->property(tracksIndex);
+ QObject *tracksQObjectPtr = tracksMeta.read(replica.data()).value<QObject *>();
+ QVERIFY(tracksQObjectPtr != nullptr);
+ QAbstractItemModelReplica *tracksReplica = qobject_cast<QAbstractItemModelReplica *>(tracksQObjectPtr);
+ QVERIFY(tracksReplica != nullptr);
+
+ // Verify subClass data
+ const int podIndex = subclassReplica->metaObject()->indexOfProperty("myPOD");
+ QVERIFY(podIndex != -1);
+ const QMetaProperty podMeta = subclassReplica->metaObject()->property(podIndex);
+ MyPOD pod = podMeta.read(subclassReplica).value<MyPOD>();
+ QCOMPARE(pod, parent.subClass()->myPOD());
+
+ // Verify tracks data
+ // Rep file only uses display role, but proxy doesn't forward that yet
+ if (!useProxy)
+ QCOMPARE(tracksReplica->availableRoles(), QList<int> { Qt::DisplayRole });
+ else {
+ const auto &availableRolesVec = tracksReplica->availableRoles();
+ QSet<int> availableRoles;
+ for (int r : availableRolesVec)
+ availableRoles.insert(r);
+ const auto &rolesHash = model.roleNames();
+ QSet<int> roles;
+ for (auto it = rolesHash.cbegin(), end = rolesHash.cend(); it != end; ++it)
+ roles.insert(it.key());
+ QCOMPARE(availableRoles, roles);
+ }
+ QTRY_COMPARE(tracksReplica->isInitialized(), true);
+ QSignalSpy dataSpy(tracksReplica, &QAbstractItemModelReplica::dataChanged);
+ QList<QModelIndex> pending;
+ QTRY_COMPARE(tracksReplica->rowCount(), model.rowCount());
+ for (int i = 0; i < tracksReplica->rowCount(); i++)
+ {
+ // We haven't received any data yet
+ const auto index = tracksReplica->index(i, 0);
+ QCOMPARE(tracksReplica->data(index), QVariant());
+ pending.append(index);
+ }
+ if (useProxy) { // A first batch of updates will be the empty proxy values
+ WaitForDataChanged w(tracksReplica, pending);
+ QVERIFY(w.wait());
+ }
+ WaitForDataChanged w(tracksReplica, pending);
+ QVERIFY(w.wait());
+ for (int i = 0; i < tracksReplica->rowCount(); i++)
+ {
+ QCOMPARE(tracksReplica->data(tracksReplica->index(i, 0)), model.data(model.index(i), Qt::DisplayRole));
+ }
+
+ //Change SubClass and make sure change propagates
+ SubClassSimpleSource updatedSubclass;
+ const MyPOD updatedValue(-1, 123.456f, QStringLiteral("Updated"));
+ updatedSubclass.setMyPOD(updatedValue);
+ QSignalSpy replicaSpy(replica.data(), QByteArray(QByteArrayLiteral("2")+subclassMeta.notifySignal().methodSignature().constData()));
+ parent.setSubClass(&updatedSubclass);
+ replicaSpy.wait();
+ QCOMPARE(replicaSpy.count(), 1);
+ subclassQObjectPtr = subclassMeta.read(replica.data()).value<QObject *>();
+ QVERIFY(subclassQObjectPtr != nullptr);
+ subclassReplica = qobject_cast<QRemoteObjectDynamicReplica *>(subclassQObjectPtr);
+ QVERIFY(subclassReplica != nullptr);
+
+ pod = podMeta.read(subclassReplica).value<MyPOD>();
+ QCOMPARE(pod, parent.subClass()->myPOD());
+ }
+ replica.reset();
+}
+
+void ProxyTest::testForwardProxy()
+{
+ // Setup Local Registry
+ QRemoteObjectRegistryHost registry(registryUrl);
+ SET_NODE_NAME(registry);
+
+ // Setup Local Host
+ QRemoteObjectHost host(localHostUrl, registryUrl);
+ SET_NODE_NAME(host);
+
+ // Setup Proxy
+ QRemoteObjectRegistryHost proxyNode(proxyNodeUrl);
+ SET_NODE_NAME(proxyNode);
+ proxyNode.proxy(registryUrl, proxyHostUrl);
+ // Include the reverseProxy to make sure we don't try to send back
+ // proxied objects.
+ proxyNode.reverseProxy();
+
+ // Setup Source
+ EngineSimpleSource engine;
+ engine.setRpm(1234);
+
+ // Setup Remote Node
+ QRemoteObjectHost remoteNode(remoteNodeUrl);
+ SET_NODE_NAME(remoteNode);
+ remoteNode.connectToNode(proxyNodeUrl);
+
+ // Add source
+ host.enableRemoting(&engine);
+
+ // Setup Replica
+ const QScopedPointer<EngineReplica> replica(remoteNode.acquire<EngineReplica>());
+ QTRY_VERIFY(replica->waitForSource(300));
+
+ // Compare Replica to Source
+ QCOMPARE(replica->rpm(), engine.rpm());
+}
+
+void ProxyTest::testReverseProxy()
+{
+ // Setup Local Registry
+ QRemoteObjectRegistryHost registry(registryUrl);
+ SET_NODE_NAME(registry);
+
+ // Setup Local Host
+ QRemoteObjectHost host(localHostUrl, registryUrl);
+ SET_NODE_NAME(host);
+
+ // Setup Proxy
+ QRemoteObjectRegistryHost proxyNode(proxyNodeUrl);
+ SET_NODE_NAME(proxyNode);
+ proxyNode.proxy(registryUrl, proxyHostUrl);
+ proxyNode.reverseProxy();
+
+ // Setup Source
+ EngineSimpleSource engine;
+ engine.setRpm(1234);
+
+ // Setup Remote Node
+ QRemoteObjectHost remoteNode(remoteNodeUrl, proxyNodeUrl);
+ SET_NODE_NAME(remoteNode);
+
+ // Add source
+ remoteNode.enableRemoting(&engine);
+
+ // Setup Replica
+ const QScopedPointer<EngineReplica> replica(host.acquire<EngineReplica>());
+ QTRY_VERIFY(replica->waitForSource(300));
+
+ //Compare Replica to Source
+ QCOMPARE(replica->rpm(), engine.rpm());
+}
+
+void ProxyTest::testTopLevelModel()
+{
+ QRemoteObjectRegistryHost registry(registryUrl);
+
+ //Setup Local Host
+ QRemoteObjectHost host(localHostUrl);
+ SET_NODE_NAME(host);
+ host.setRegistryUrl(registryUrl);
+
+ QStringListModel model;
+ model.setStringList(QStringList() << "Track1" << "Track2" << "Track3");
+ host.enableRemoting(&model, "trackList", QList<int> { Qt::DisplayRole });
+
+ QRemoteObjectHost proxyNode;
+ SET_NODE_NAME(proxyNode);
+ proxyNode.setHostUrl(tcpHostUrl);
+ proxyNode.proxy(registryUrl);
+
+ //Setup Local Replica
+ QRemoteObjectNode client;
+ SET_NODE_NAME(client);
+ client.connectToNode(tcpHostUrl);
+ QAbstractItemModelReplica *replica = client.acquireModel("trackList");
+ QSignalSpy tracksSpy(replica, &QAbstractItemModelReplica::initialized);
+ QVERIFY(tracksSpy.wait());
+ QTRY_COMPARE(replica->rowCount(), model.rowCount());
+}
+
+QTEST_MAIN(ProxyTest)
+
+#include "tst_proxy.moc"
--- /dev/null
+
+add_subdirectory(client)
+add_subdirectory(server)
+add_subdirectory(proxy)
+add_subdirectory(tst)
--- /dev/null
+
+#####################################################################
+## proxy_multiprocess_client Binary:
+#####################################################################
+
+qt_internal_add_executable(proxy_multiprocess_client
+ OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
+ SOURCES
+ ../namespace.h
+ ../shared.h
+ main.cpp
+ INCLUDE_DIRECTORIES
+ ${CMAKE_CURRENT_SOURCE_DIR}
+ PUBLIC_LIBRARIES
+ Qt::RemoteObjects
+ Qt::Test
+)
+qt6_add_repc_replicas(proxy_multiprocess_client
+ ../subclass.rep
+)
+
+#### Keys ignored in scope 1:.:.:client.pro:<TRUE>:
+# TEMPLATE = "app"
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2019 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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 with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "rep_subclass_replica.h"
+#include "../shared.h"
+
+#include <QCoreApplication>
+#include <QtRemoteObjects/qremoteobjectnode.h>
+#include <QtTest/QtTest>
+
+static QMap<int, MyPOD> int_map{{1, initialValue},
+ {16, initialValue}};
+static ParentClassReplica::ActivePositions flags1 = ParentClassReplica::Position::position1;
+static ParentClassReplica::ActivePositions flags2 = ParentClassReplica::Position::position2
+ | ParentClassReplica::Position::position3;
+static QMap<ParentClassReplica::ActivePositions, MyPOD> my_map{{flags1, initialValue},
+ {flags2, initialValue}};
+static QHash<NS2::NamespaceEnum, MyPOD> my_hash{{NS2::NamespaceEnum::Alpha, initialValue},
+ {NS2::NamespaceEnum::Charlie, initialValue}};
+
+class tst_Client_Process : public QObject
+{
+ Q_OBJECT
+
+private Q_SLOTS:
+ void initTestCase()
+ {
+ m_repNode.reset(new QRemoteObjectNode);
+ m_repNode->connectToNode(QUrl(QStringLiteral("tcp://127.0.0.1:65213")));
+ m_rep.reset(m_repNode->acquire<ParentClassReplica>());
+ const auto objectMode = qEnvironmentVariable("ObjectMode");
+ qDebug() << "Waiting to connect, mode =" << objectMode;
+ QVERIFY(m_rep->waitForSource());
+ }
+
+ void testSubClass()
+ {
+ const auto objectMode = qEnvironmentVariable("ObjectMode");
+
+ qDebug() << "Starting test" << objectMode;
+ if (objectMode == QLatin1String("ObjectPointer")) {
+ QSignalSpy tracksSpy(m_rep->tracks(), &QAbstractItemModelReplica::initialized);
+ QVERIFY(m_rep->subClass() != nullptr);
+ QCOMPARE(m_rep->subClass()->myPOD(), initialValue);
+ QCOMPARE(m_rep->subClass()->i(), initialI);
+ QVERIFY(m_rep->tracks() != nullptr);
+ QVERIFY(tracksSpy.count() || tracksSpy.wait());
+ QCOMPARE(m_rep->myEnum(), ParentClassReplica::bar);
+ QCOMPARE(m_rep->date(), Qt::RFC2822Date);
+ QCOMPARE(m_rep->nsEnum(), NS::Bravo);
+ QCOMPARE(m_rep->ns2Enum(), NS2::NamespaceEnum::Bravo);
+ QCOMPARE(m_rep->variant(), QVariant::fromValue(42.0f));
+ QCOMPARE(m_rep->simpleList(), QList<QString>() << "one" << "two");
+ QCOMPARE(m_rep->podList(), QList<MyPOD>() << initialValue << initialValue);
+ QCOMPARE(m_rep->intMap(), int_map);
+ QCOMPARE(m_rep->enumMap(), my_map);
+ QCOMPARE(m_rep->podHash(), my_hash);
+ } else {
+ QVERIFY(m_rep->subClass() == nullptr);
+ QVERIFY(m_rep->tracks() == nullptr);
+ QCOMPARE(m_rep->myEnum(), ParentClassReplica::foo);
+ QCOMPARE(m_rep->date(), Qt::ISODate);
+ QCOMPARE(m_rep->nsEnum(), NS::Alpha);
+ QCOMPARE(m_rep->ns2Enum(), NS2::NamespaceEnum::Alpha);
+ QCOMPARE(m_rep->variant(), QVariant());
+ }
+
+ QPoint p(1, 2);
+ auto enumReply = m_rep->enumSlot(p, ParentClassReplica::bar);
+ QVERIFY(enumReply.waitForFinished());
+ QCOMPARE(enumReply.error(), QRemoteObjectPendingCall::NoError);
+ QCOMPARE(enumReply.returnValue(), ParentClassReplica::foobar);
+
+ qDebug() << "Verified expected initial states, sending start.";
+ QSignalSpy enumSpy(m_rep.data(), &ParentClassReplica::enum2);
+ QSignalSpy advanceSpy(m_rep.data(), &ParentClassReplica::advance);
+ auto reply = m_rep->start();
+ QVERIFY(reply.waitForFinished());
+ QVERIFY(reply.error() == QRemoteObjectPendingCall::NoError);
+ QCOMPARE(reply.returnValue(), QVariant::fromValue(true));
+ QVERIFY(enumSpy.wait());
+ QCOMPARE(enumSpy.count(), 1);
+ const auto arguments = enumSpy.takeFirst();
+ QCOMPARE(arguments.at(0), QVariant::fromValue(ParentClassReplica::foo));
+ QCOMPARE(arguments.at(1), QVariant::fromValue(ParentClassReplica::bar));
+
+ QVERIFY(advanceSpy.count() || advanceSpy.wait());
+ QVERIFY(m_rep->subClass() != nullptr);
+ QCOMPARE(m_rep->subClass()->myPOD(), updatedValue);
+ QCOMPARE(m_rep->subClass()->i(), updatedI);
+ QVERIFY(m_rep->tracks() != nullptr);
+ QCOMPARE(m_rep->myEnum(), ParentClassReplica::foobar);
+ QCOMPARE(m_rep->date(), Qt::ISODateWithMs);
+ QCOMPARE(m_rep->nsEnum(), NS::Charlie);
+ QCOMPARE(m_rep->ns2Enum(), NS2::NamespaceEnum::Charlie);
+ QCOMPARE(m_rep->variant(), QVariant::fromValue(podValue));
+ qDebug() << "Verified expected final states, cleaning up.";
+ }
+
+ void cleanupTestCase()
+ {
+ auto reply = m_rep->quit();
+ // Don't verify the wait result, depending on the timing of the server and proxy
+ // closing it may return false. We just need this process to stay alive long
+ // enough for the packets to be sent.
+ reply.waitForFinished(5000);
+ }
+
+private:
+ QScopedPointer<QRemoteObjectNode> m_repNode;
+ QScopedPointer<ParentClassReplica> m_rep;
+};
+
+QTEST_MAIN(tst_Client_Process)
+
+#include "main.moc"
--- /dev/null
+#ifndef __PROXY_MULTIPROCESS_NAMESPACE_H__
+#define __PROXY_MULTIPROCESS_NAMESPACE_H__
+
+#include <QMetaType>
+
+namespace NS
+{
+ Q_NAMESPACE
+ enum NamespaceEnum { Alpha=1, Bravo, Charlie };
+ Q_ENUM_NS(NamespaceEnum)
+}
+
+namespace NS2
+{
+ Q_NAMESPACE
+ enum class NamespaceEnum : quint8 { Alpha=1, Bravo, Charlie };
+ Q_ENUM_NS(NamespaceEnum)
+}
+
+#endif // include guard
--- /dev/null
+
+#####################################################################
+## proxy Binary:
+#####################################################################
+
+qt_internal_add_executable(proxy
+ OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
+ SOURCES
+ main.cpp
+ INCLUDE_DIRECTORIES
+ ${CMAKE_CURRENT_SOURCE_DIR}
+ PUBLIC_LIBRARIES
+ Qt::RemoteObjects
+ Qt::Test
+)
+
+#### Keys ignored in scope 1:.:.:proxy.pro:<TRUE>:
+# TEMPLATE = "app"
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2019 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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 with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QCoreApplication>
+#include <QtRemoteObjects/qremoteobjectnode.h>
+#include <QtTest/QtTest>
+
+class tst_Proxy_Process : public QObject
+{
+ Q_OBJECT
+
+private Q_SLOTS:
+ void testRun()
+ {
+ m_hostNode.reset(new QRemoteObjectHost);
+ m_hostNode->setHostUrl(QUrl(QStringLiteral("tcp://127.0.0.1:65213")));
+ m_hostNode->proxy(QUrl("local:testRegistry"));
+
+ // our proxied object should be added, and then later removed when the server shuts down
+ QSignalSpy addSpy(m_hostNode.data(), &QRemoteObjectNode::remoteObjectAdded);
+ QSignalSpy removeSpy(m_hostNode.data(), &QRemoteObjectNode::remoteObjectRemoved);
+ QVERIFY(addSpy.wait());
+ QVERIFY(removeSpy.wait());
+ }
+
+private:
+ QScopedPointer<QRemoteObjectHost> m_hostNode;
+};
+
+QTEST_MAIN(tst_Proxy_Process)
+
+#include "main.moc"
--- /dev/null
+
+#####################################################################
+## proxy_multiprocess_server Binary:
+#####################################################################
+
+qt_internal_add_executable(proxy_multiprocess_server
+ OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
+ SOURCES
+ ${CMAKE_CURRENT_BINARY_DIR}/rep_subclass_source.h
+ ../namespace.h
+ ../shared.h
+ main.cpp
+ mytestserver.cpp mytestserver.h
+ INCLUDE_DIRECTORIES
+ ${CMAKE_CURRENT_SOURCE_DIR}
+ PUBLIC_LIBRARIES
+ Qt::RemoteObjects
+ Qt::Test
+)
+qt6_add_repc_sources(proxy_multiprocess_server
+ ../subclass.rep
+)
+
+#### Keys ignored in scope 1:.:.:server.pro:<TRUE>:
+# TEMPLATE = "app"
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2019 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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 with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "mytestserver.h"
+#include "rep_subclass_source.h"
+#include "../shared.h"
+
+#include <QCoreApplication>
+#include <QtTest/QtTest>
+
+static QMap<int, MyPOD> int_map{{1, initialValue},
+ {16, initialValue}};
+static MyTestServer::ActivePositions flags1 = MyTestServer::Position::position1;
+static MyTestServer::ActivePositions flags2 = MyTestServer::Position::position2
+ | MyTestServer::Position::position3;
+static QMap<MyTestServer::ActivePositions, MyPOD> my_map{{flags1, initialValue},
+ {flags2, initialValue}};
+static QHash<NS2::NamespaceEnum, MyPOD> my_hash{{NS2::NamespaceEnum::Alpha, initialValue},
+ {NS2::NamespaceEnum::Charlie, initialValue}};
+
+class tst_Server_Process : public QObject
+{
+ Q_OBJECT
+
+private Q_SLOTS:
+ void testRun()
+ {
+ const auto objectMode = qEnvironmentVariable("ObjectMode");
+ bool templated = qEnvironmentVariableIsSet("TEMPLATED_REMOTING");
+
+ qDebug() << "Starting tests:" << objectMode << "templated =" << templated;
+ QRemoteObjectRegistryHost srcNode(QUrl(QStringLiteral("local:testRegistry")));
+
+ MyTestServer parent;
+ SubClassSimpleSource subclass;
+ subclass.setMyPOD(initialValue);
+ subclass.setI(initialI);
+ QStringListModel model;
+ model.setStringList(QStringList() << "Track1" << "Track2" << "Track3");
+ if (objectMode == QLatin1String("ObjectPointer")) {
+ parent.setSubClass(&subclass);
+ parent.setTracks(&model);
+ parent.setMyEnum(ParentClassSource::bar);
+ parent.setDate(Qt::RFC2822Date);
+ parent.setNsEnum(NS::Bravo);
+ parent.setNs2Enum(NS2::NamespaceEnum::Bravo);
+ parent.setVariant(QVariant::fromValue(42.0f));
+ parent.setSimpleList(QList<QString>() << "one" << "two");
+ parent.setPodList(QList<MyPOD>() << initialValue << initialValue);
+ parent.setIntMap(int_map);
+ parent.setEnumMap(my_map);
+ parent.setPodHash(my_hash);
+ }
+
+ if (templated)
+ srcNode.enableRemoting<ParentClassSourceAPI>(&parent);
+ else
+ srcNode.enableRemoting(&parent);
+
+ qDebug() << "Waiting for incoming connections";
+
+ QSignalSpy waitForStartedSpy(&parent, &MyTestServer::startedChanged);
+ QVERIFY(waitForStartedSpy.isValid());
+ QVERIFY(waitForStartedSpy.wait());
+ QCOMPARE(waitForStartedSpy.value(0).value(0).toBool(), true);
+
+ // wait for delivery of events
+ QTest::qWait(200);
+
+ //Change SubClass and make sure change propagates
+ SubClassSimpleSource updatedSubclass;
+ updatedSubclass.setMyPOD(updatedValue);
+ updatedSubclass.setI(updatedI);
+ parent.setSubClass(&updatedSubclass);
+ if (objectMode == QLatin1String("NullPointer"))
+ parent.setTracks(&model);
+ parent.setMyEnum(ParentClassSource::foobar);
+ parent.setDate(Qt::ISODateWithMs);
+ parent.setNsEnum(NS::Charlie);
+ parent.setNs2Enum(NS2::NamespaceEnum::Charlie);
+ parent.setVariant(QVariant::fromValue(podValue));
+ emit parent.enum2(ParentClassSource::foo, ParentClassSource::bar);
+
+ emit parent.advance();
+
+ // wait for quit
+ bool quit = false;
+ connect(&parent, &MyTestServer::quitApp, [&quit]{quit = true;});
+ QTRY_VERIFY_WITH_TIMEOUT(quit, 5000);
+
+ // wait for delivery of events
+ QTest::qWait(200);
+
+ qDebug() << "Done. Shutting down.";
+ }
+};
+
+QTEST_MAIN(tst_Server_Process)
+
+#include "main.moc"
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2019 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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 with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <qdebug.h>
+
+#include "mytestserver.h"
+
+MyTestServer::MyTestServer(QObject *parent)
+ : ParentClassSimpleSource(parent)
+{
+ qDebug() << "Server started";
+}
+
+MyTestServer::~MyTestServer()
+{
+ qDebug() << "Server stopped";
+}
+
+bool MyTestServer::start()
+{
+ setStarted(true);
+ return true;
+}
+
+bool MyTestServer::quit()
+{
+ emit quitApp();
+ return true;
+}
+
+ParentClassSource::MyEnum MyTestServer::enumSlot(QPoint p, MyEnum myEnum)
+{
+ Q_UNUSED(p)
+ Q_UNUSED(myEnum)
+ return ParentClassSource::foobar;
+}
+
+Qt::DateFormat MyTestServer::dateSlot(Qt::DateFormat date)
+{
+ Q_UNUSED(date)
+ return Qt::RFC2822Date;
+}
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2019 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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 with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef MYTESTSERVER_H
+#define MYTESTSERVER_H
+
+#include <QTimer>
+
+#include <QtRemoteObjects/qremoteobjectnode.h>
+#include <QtRemoteObjects/qremoteobjectsource.h>
+
+#include "rep_subclass_source.h"
+
+class MyTestServer : public ParentClassSimpleSource
+{
+ Q_OBJECT
+
+public:
+ MyTestServer(QObject *parent = nullptr);
+ ~MyTestServer() override;
+
+public Q_SLOTS:
+ bool start() override;
+ bool quit() override;
+ MyEnum enumSlot(QPoint p, MyEnum myEnum) override;
+ Qt::DateFormat dateSlot(Qt::DateFormat date) override;
+
+Q_SIGNALS:
+ void quitApp();
+};
+
+#endif // MYTESTSERVER_H
--- /dev/null
+const MyPOD initialValue(MyPOD::Position::position1, 3.14, QStringLiteral("SubClass"));
+const MyPOD updatedValue(MyPOD::Position::position2 | MyPOD::Position::position3, 123.456, QStringLiteral("Updated"));
+const VariantPOD podValue(10, 11);
+const int initialI = 100;
+const int updatedI = 200;
+
--- /dev/null
+#include <QPoint>
+#include "../namespace.h"
+
+USE_ENUM(Qt::DateFormat)
+USE_ENUM(NS::NamespaceEnum)
+USE_ENUM(NS2::NamespaceEnum)
+
+POD MyPOD{
+ ENUM class Position : unsigned short {position1=1, position2=2, position3=4}
+ FLAG (ActivePositions Position)
+ ActivePositions positions, float f, QString s
+}
+POD VariantPOD(int i, int j)
+
+class SubClass
+{
+ PROP(MyPOD myPOD)
+ PROP(int i)
+}
+
+class ParentClass
+{
+ ENUM MyEnum {foo=1, bar=3, foobar=6}
+ ENUM class Position : unsigned short {position1=1, position2=2, position3=4}
+ FLAG (ActivePositions Position)
+ PROP(bool started = false)
+ PROP(MyEnum myEnum=foo)
+ PROP(QVariant variant)
+ PROP(Qt::DateFormat date = Qt::ISODate)
+ PROP(NS::NamespaceEnum nsEnum = NS::Alpha)
+ PROP(NS2::NamespaceEnum ns2Enum = NS2::NamespaceEnum::Alpha)
+ PROP(QList<QString> simpleList)
+ PROP(QList<MyPOD> podList)
+ PROP(QMap<int, MyPOD> intMap)
+ PROP(QMap<ActivePositions, MyPOD> enumMap)
+ PROP(QHash<NS2::NamespaceEnum, MyPOD> podHash)
+
+ SLOT(bool start())
+ SLOT(bool quit())
+ SIGNAL(advance())
+ SIGNAL(enum2(MyEnum myEnum1, MyEnum myEnum2))
+ SLOT(MyEnum enumSlot(QPoint point, MyEnum myEnum))
+
+ SIGNAL(updateDate(Qt::DateFormat date1, Qt::DateFormat date2))
+ SLOT(Qt::DateFormat dateSlot(Qt::DateFormat date))
+
+ CLASS subClass(SubClass)
+ MODEL tracks(display)
+}
+
--- /dev/null
+
+#####################################################################
+## tst_proxy_multiprocess Test:
+#####################################################################
+
+qt_internal_add_test(tst_proxy_multiprocess
+ OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
+ SOURCES
+ tst_proxy_multiprocess.cpp
+ PUBLIC_LIBRARIES
+ Qt::RemoteObjects
+)
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2019 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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 with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtTest/QtTest>
+#include <QMetaType>
+#include <QProcess>
+
+#include "../../../shared/testutils.h"
+
+class tst_Proxy_MultiProcess: public QObject
+{
+ Q_OBJECT
+
+public:
+ enum ObjectMode { NullPointer, ObjectPointer };
+ Q_ENUM(ObjectMode)
+
+private slots:
+ void initTestCase()
+ {
+ QVERIFY(TestUtils::init("tst"));
+ }
+
+ void cleanup()
+ {
+ // wait for delivery of RemoveObject events to the source
+ QTest::qWait(200);
+ }
+
+ void testRun_data()
+ {
+ QTest::addColumn<bool>("templated");
+ QTest::addColumn<ObjectMode>("objectMode");
+ QTest::newRow("non-templated, subobject") << false << ObjectPointer;
+ QTest::newRow("templated, subobject") << true << ObjectPointer;
+ QTest::newRow("non-templated, nullptr") << false << NullPointer;
+ QTest::newRow("templated, nullptr") << true << NullPointer;
+ }
+
+ void testRun()
+ {
+ QFETCH(bool, templated);
+ QFETCH(ObjectMode, objectMode);
+
+ qDebug() << "Starting server process";
+ QProcess serverProc;
+ serverProc.setProcessChannelMode(QProcess::ForwardedChannels);
+ QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
+ env.insert("ObjectMode", QVariant::fromValue(objectMode).toString());
+ if (templated) {
+ env.insert("TEMPLATED_REMOTING", "true");
+ }
+ serverProc.setProcessEnvironment(env);
+ serverProc.start(TestUtils::findExecutable("proxy_multiprocess_server", "/server"),
+ QStringList());
+ QVERIFY(serverProc.waitForStarted());
+
+ // wait for server start
+ QTest::qWait(200);
+
+
+ qDebug() << "Starting client process";
+ QProcess clientProc;
+ clientProc.setProcessChannelMode(QProcess::ForwardedChannels);
+ clientProc.setProcessEnvironment(env);
+ clientProc.start(TestUtils::findExecutable("proxy_multiprocess_client", "/client"),
+ QStringList());
+ QVERIFY(clientProc.waitForStarted());
+
+ // wait for client start
+ QTest::qWait(200);
+
+
+ qDebug() << "Starting proxy process";
+ QProcess proxyProc;
+ proxyProc.setProcessChannelMode(QProcess::ForwardedChannels);
+ proxyProc.start(TestUtils::findExecutable("proxy", "/proxy"),
+ QStringList());
+ QVERIFY(proxyProc.waitForStarted());
+
+ // wait for proxy start
+ QTest::qWait(200);
+
+
+ QVERIFY(clientProc.waitForFinished());
+ QVERIFY(proxyProc.waitForFinished());
+ QVERIFY(serverProc.waitForFinished());
+
+ QCOMPARE(serverProc.exitCode(), 0);
+ QCOMPARE(proxyProc.exitCode(), 0);
+ QCOMPARE(clientProc.exitCode(), 0);
+ }
+};
+
+QTEST_MAIN(tst_Proxy_MultiProcess)
+
+#include "tst_proxy_multiprocess.moc"
--- /dev/null
+
+add_subdirectory(integration)
+add_subdirectory(usertypes)
--- /dev/null
+
+#####################################################################
+## tst_qmlintegration Test:
+#####################################################################
+
+# Collect test data
+file(GLOB_RECURSE test_data_glob
+ RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
+ ${CMAKE_CURRENT_SOURCE_DIR}/data/tst_*)
+list(APPEND test_data ${test_data_glob})
+
+qt_internal_add_test(tst_qmlintegration
+ GUI
+ QMLTEST
+ SOURCES
+ tst_integration.cpp
+ PUBLIC_LIBRARIES
+ Qt::Gui
+ TESTDATA ${test_data}
+)
+
+#### Keys ignored in scope 1:.:.:integration.pro:<TRUE>:
+# OTHER_FILES = "$$PWD/data/*.qml"
+# TEMPLATE = "app"
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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 with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtTest 1.1
+import QtRemoteObjects 5.12
+
+TestCase {
+ id: testCase
+
+ Node {
+ id: defaultNode
+ }
+
+ Node {
+ id: nodeWithPersistedStore
+
+ persistedStore: SettingsStore {}
+ }
+
+ name: "testIntegration"
+ function test_integration()
+ {
+ // test defaultNode
+ compare(defaultNode.registryUrl, "")
+ compare(defaultNode.persistedStore, null)
+
+ // test nodeWithPersistedStore
+ compare(nodeWithPersistedStore.registryUrl, "")
+ verify(nodeWithPersistedStore.persistedStore)
+ }
+}
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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 with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtQuickTest/quicktest.h>
+QUICK_TEST_MAIN(tst_integration)
--- /dev/null
+
+#####################################################################
+## tst_usertypes Test:
+#####################################################################
+
+qt_internal_add_test(tst_usertypes
+ SOURCES
+ tst_usertypes.cpp
+ DEFINES
+ SRCDIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/\\\"
+ PUBLIC_LIBRARIES
+ Qt::Qml
+ Qt::RemoteObjects
+)
+qt6_add_repc_merged(tst_usertypes
+ usertypes.rep
+)
+
+#### Keys ignored in scope 1:.:.:usertypes.pro:<TRUE>:
+# TEMPLATE = "app"
--- /dev/null
+import QtQuick 2.0
+
+QtObject {
+ property int value: 39
+}
--- /dev/null
+import QtQuick 2.0
+import QtRemoteObjects 5.12
+import usertypes 1.0
+
+ComplexTypeReplica {
+ node: Node {
+ registryUrl: "local:testModel"
+ }
+}
--- /dev/null
+import QtQuick 2.0
+
+QtObject {
+ property QtObject myTypeOk: MyType {} // this works
+ property MyType myType: MyType {} // this crashes
+ property MyType myType2 // this crashes (ensure solution works with null object)
+}
--- /dev/null
+import QtQuick 2.0
+import QtRemoteObjects 5.12
+import usertypes 1.0
+
+ComplexTypeReplica {
+ // test that the existence of this property doesn't cause issues
+ property QtObject object: QtObject {}
+
+ node: Node {
+ registryUrl: "local:testExtraComplex"
+ }
+}
+
--- /dev/null
+import QtQuick 2.0
+import QtRemoteObjects 5.12
+import usertypes 1.0
+
+SimpleClockReplica {
+ property string result: hour // test that the existence of this property doesn't cause issues
+
+ node: Node {
+ registryUrl: "local:test"
+ }
+ onStateChanged: if (state == SimpleClockReplica.Valid) pushHour(10)
+}
--- /dev/null
+import QtQuick 2.0
+import QtRemoteObjects 5.12
+import usertypes 1.0
+
+SimpleClockReplica {
+ property string result: hour // test that the existence of this property doesn't cause issues
+
+ node: Node {
+ registryUrl: "local:test2"
+ }
+}
--- /dev/null
+import QtQuick 2.0
+import QtRemoteObjects 5.15
+import usertypes 1.0
+
+Item {
+ SimpleClockSimpleSource {
+ id: clock
+ }
+
+ Host {
+ hostUrl: "local:testHost"
+ Component.onCompleted: enableRemoting(clock)
+ }
+
+ Timer {
+ interval: 500
+ running: true
+ onTriggered: clock.timeUpdated(10, 30)
+ }
+}
--- /dev/null
+import QtQuick 2.0
+import QtRemoteObjects 5.12
+import usertypes 1.0
+
+TypeWithModelReplica {
+ node: Node {
+ registryUrl: "local:testModel"
+ }
+}
--- /dev/null
+import QtQuick 2.0
+import QtRemoteObjects 5.12
+import usertypes 1.0
+
+Item {
+ property int result: replica.clock.hour
+
+ property Node sharedNode: Node {
+ registryUrl: "local:testSubObject"
+ }
+
+ property TypeWithSubObjectReplica replica: TypeWithSubObjectReplica {
+ node: sharedNode
+ onStateChanged: if (state == TypeWithSubObjectReplica.Valid) clock.pushHour(7)
+ }
+}
+
--- /dev/null
+import QtQuick 2.0
+import QtRemoteObjects 5.12
+import usertypes 1.0
+
+Item {
+ property int result: replica.hour
+ property int result2: replica2.hour
+
+ Node {
+ id: sharedNode
+ registryUrl: "local:testTwoReplicas"
+ }
+
+ SimpleClockReplica {
+ id: replica
+ node: sharedNode
+ }
+
+ SimpleClockReplica {
+ id: replica2
+ }
+
+ Timer {
+ running: true
+ interval: 200
+ onTriggered: replica2.node = sharedNode
+ }
+}
+
--- /dev/null
+import QtQuick 2.0
+import QtRemoteObjects 5.14
+import usertypes 1.0
+
+TypeWithReplyReplica {
+ property variant result
+ property bool hasError
+
+ node: Node {
+ registryUrl: "local:testWatcher"
+ }
+ onStateChanged: function(state) {
+ if (state != TypeWithReplyReplica.Valid)
+ return;
+ QtRemoteObjects.watch(uppercase("hello"), 1000)
+ .then(function(value) { hasError = false; result = value },
+ function(error) { hasError = true })
+ }
+
+ function callSlowFunction() {
+ result = 0
+ hasError = false
+
+ QtRemoteObjects.watch(slowFunction(), 300)
+ .then(function(value) { hasError = false; result = value },
+ function(error) { hasError = true })
+ }
+
+ function callComplexFunction() {
+ result = null
+ hasError = false
+
+ QtRemoteObjects.watch(complexReturnType(), 300)
+ .then(function(value) { hasError = false; result = value },
+ function(error) { hasError = true })
+ }
+}
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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 with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QString>
+#include <QtTest>
+#include <qqmlengine.h>
+#include <qqmlcomponent.h>
+#include "rep_usertypes_merged.h"
+
+class TypeWithReply : public TypeWithReplySimpleSource
+{
+public:
+ QString uppercase(const QString & input) override {
+ return input.toUpper();
+ }
+ QMap<QString, QString> complexReturnType() override {
+ return QMap<QString, QString>{{"one","1"}};
+ }
+ int slowFunction() override {
+ QTest::qWait(1000);
+ return 15;
+ }
+};
+
+class tst_usertypes : public QObject
+{
+ Q_OBJECT
+
+public:
+ tst_usertypes();
+
+private Q_SLOTS:
+ void extraPropertyInQml();
+ void extraPropertyInQml2();
+ void extraPropertyInQmlComplex();
+ void modelInQml();
+ void subObjectInQml();
+ void complexInQml_data();
+ void complexInQml();
+ void watcherInQml();
+ void hostInQml();
+ void twoReplicas();
+ void remoteCompositeType();
+};
+
+tst_usertypes::tst_usertypes()
+{
+ qmlRegisterType<ComplexTypeReplica>("usertypes", 1, 0, "ComplexTypeReplica");
+}
+
+void tst_usertypes::extraPropertyInQml()
+{
+ qmlRegisterType<SimpleClockReplica>("usertypes", 1, 0, "SimpleClockReplica");
+
+ QRemoteObjectRegistryHost host(QUrl("local:test"));
+ SimpleClockSimpleSource clock;
+ host.enableRemoting(&clock);
+
+ QQmlEngine e;
+ QQmlComponent c(&e, SRCDIR "data/extraprop.qml");
+ QObject *obj = c.create();
+ QVERIFY(obj);
+
+ QTRY_COMPARE_WITH_TIMEOUT(obj->property("result").value<int>(), 10, 1000);
+}
+
+void tst_usertypes::extraPropertyInQml2()
+{
+ qmlRegisterType<SimpleClockReplica>("usertypes", 1, 0, "SimpleClockReplica");
+
+ QRemoteObjectRegistryHost host(QUrl("local:test2"));
+ SimpleClockSimpleSource clock;
+ clock.setHour(10);
+ host.enableRemoting(&clock);
+
+ QQmlEngine e;
+ QQmlComponent c(&e, SRCDIR "data/extraprop2.qml");
+ QObject *obj = c.create();
+ QVERIFY(obj);
+
+ QTRY_COMPARE_WITH_TIMEOUT(obj->property("hour").value<int>(), 10, 1000);
+ QCOMPARE(obj->property("result").value<int>(), 10);
+}
+
+void tst_usertypes::extraPropertyInQmlComplex()
+{
+ QRemoteObjectRegistryHost host(QUrl("local:testExtraComplex"));
+
+ SimpleClockSimpleSource clock;
+ QStringListModel *model = new QStringListModel();
+ model->setStringList(QStringList() << "Track1" << "Track2" << "Track3");
+ ComplexTypeSimpleSource source;
+ source.setClock(&clock);
+ source.setTracks(model);
+ host.enableRemoting(&source);
+
+ QQmlEngine e;
+ QQmlComponent c(&e, SRCDIR "data/extraPropComplex.qml");
+ QObject *obj = c.create();
+ QVERIFY(obj);
+
+ ComplexTypeReplica *rep = qobject_cast<ComplexTypeReplica*>(obj);
+ QVERIFY(rep);
+
+ // don't crash
+ QTRY_VERIFY_WITH_TIMEOUT(rep->isInitialized(), 1000);
+}
+
+void tst_usertypes::modelInQml()
+{
+ qmlRegisterType<TypeWithModelReplica>("usertypes", 1, 0, "TypeWithModelReplica");
+
+ QRemoteObjectRegistryHost host(QUrl("local:testModel"));
+
+ QStringListModel *model = new QStringListModel();
+ model->setStringList(QStringList() << "Track1" << "Track2" << "Track3");
+ TypeWithModelSimpleSource source;
+ source.setTracks(model);
+ host.enableRemoting<TypeWithModelSourceAPI>(&source);
+
+ QQmlEngine e;
+ QQmlComponent c(&e, SRCDIR "data/model.qml");
+ QObject *obj = c.create();
+ QVERIFY(obj);
+
+ QTRY_VERIFY_WITH_TIMEOUT(obj->property("tracks").value<QAbstractItemModelReplica*>() != nullptr, 1000);
+ auto tracks = obj->property("tracks").value<QAbstractItemModelReplica*>();
+ QTRY_VERIFY_WITH_TIMEOUT(tracks->isInitialized(), 1000);
+
+ TypeWithModelReplica *rep = qobject_cast<TypeWithModelReplica *>(obj);
+ QVERIFY(rep->isInitialized());
+}
+
+void tst_usertypes::subObjectInQml()
+{
+ qmlRegisterType<TypeWithSubObjectReplica>("usertypes", 1, 0, "TypeWithSubObjectReplica");
+
+ QRemoteObjectRegistryHost host(QUrl("local:testSubObject"));
+
+ SimpleClockSimpleSource clock;
+ TypeWithSubObjectSimpleSource source;
+ source.setClock(&clock);
+ host.enableRemoting(&source);
+
+ QQmlEngine e;
+ QQmlComponent c(&e, SRCDIR "data/subObject.qml");
+ QObject *obj = c.create();
+ QVERIFY(obj);
+
+ TypeWithSubObjectReplica *replica = obj->property("replica").value<TypeWithSubObjectReplica*>();
+ QVERIFY(replica);
+
+ QTRY_VERIFY_WITH_TIMEOUT(replica->property("clock").value<SimpleClockReplica*>() != nullptr, 1000);
+ QTRY_COMPARE_WITH_TIMEOUT(obj->property("result").toInt(), 7, 1000);
+}
+
+void tst_usertypes::complexInQml_data()
+{
+ QTest::addColumn<bool>("templated");
+ QTest::addColumn<bool>("nullobject");
+ QTest::newRow("non-templated pointer") << false << false;
+ QTest::newRow("templated pointer") << true << false;
+ QTest::newRow("non-templated nullptr") << false << true;
+ QTest::newRow("templated nullptr") << true << true;
+}
+
+void tst_usertypes::complexInQml()
+{
+ QFETCH(bool, templated);
+ QFETCH(bool, nullobject);
+
+ QRemoteObjectRegistryHost host(QUrl("local:testModel"));
+
+ QStringListModel *model = new QStringListModel();
+ model->setStringList(QStringList() << "Track1" << "Track2" << "Track3");
+ QScopedPointer<SimpleClockSimpleSource> clock;
+ if (!nullobject)
+ clock.reset(new SimpleClockSimpleSource());
+ ComplexTypeSimpleSource source;
+ source.setTracks(model);
+ source.setClock(clock.data());
+ if (templated)
+ host.enableRemoting<ComplexTypeSourceAPI>(&source);
+ else
+ host.enableRemoting(&source);
+
+ QQmlEngine e;
+ QQmlComponent c(&e, SRCDIR "data/complex.qml");
+ QObject *obj = c.create();
+ QVERIFY(obj);
+
+ QTRY_VERIFY_WITH_TIMEOUT(obj->property("tracks").value<QAbstractItemModelReplica*>() != nullptr, 1000);
+ auto tracks = obj->property("tracks").value<QAbstractItemModelReplica*>();
+ QTRY_VERIFY_WITH_TIMEOUT(tracks->isInitialized(), 1000);
+ ComplexTypeReplica *rep = qobject_cast<ComplexTypeReplica *>(obj);
+ QVERIFY(rep->waitForSource(300));
+ QCOMPARE(rep->property("before").value<int>(), 0);
+ QCOMPARE(rep->property("after").value<int>(), 42);
+ if (nullobject) {
+ QCOMPARE(rep->clock(), nullptr);
+ QCOMPARE(source.clock(), nullptr);
+ } else {
+ QCOMPARE(source.clock()->hour(), 6);
+ QCOMPARE(rep->clock()->hour(), source.clock()->hour());
+ }
+}
+
+void tst_usertypes::watcherInQml()
+{
+ qmlRegisterType<TypeWithReplyReplica>("usertypes", 1, 0, "TypeWithReplyReplica");
+
+ QRemoteObjectRegistryHost host(QUrl("local:testWatcher"));
+ TypeWithReply source;
+ host.enableRemoting(&source);
+
+ QQmlEngine e;
+ QQmlComponent c(&e, SRCDIR "data/watcher.qml");
+ QObject *obj = c.create();
+ QVERIFY(obj);
+
+ QTRY_COMPARE_WITH_TIMEOUT(obj->property("result").value<QString>(), QString::fromLatin1("HELLO"), 1000);
+ QCOMPARE(obj->property("hasError").value<bool>(), false);
+
+ QMetaObject::invokeMethod(obj, "callSlowFunction");
+ QTRY_COMPARE_WITH_TIMEOUT(obj->property("hasError").value<bool>(), true, 1000);
+ QVERIFY(obj->property("result").value<int>() != 10);
+
+ QMetaObject::invokeMethod(obj, "callComplexFunction");
+ QTRY_VERIFY_WITH_TIMEOUT(!obj->property("result").isNull(), 1000);
+ auto map = obj->property("result").value<QMap<QString,QString>>();
+ QCOMPARE(map.value("one"), QString::fromLatin1("1"));
+ QCOMPARE(obj->property("hasError").value<bool>(), false);
+}
+
+void tst_usertypes::hostInQml()
+{
+ qmlRegisterType<SimpleClockSimpleSource>("usertypes", 1, 0, "SimpleClockSimpleSource");
+
+ QQmlEngine e;
+ QQmlComponent c(&e, SRCDIR "data/hosted.qml");
+ QObject *obj = c.create();
+ QVERIFY(obj);
+
+ QRemoteObjectNode node;
+ node.connectToNode(QUrl("local:testHost"));
+ SimpleClockReplica *replica = node.acquire<SimpleClockReplica>();
+ QTRY_COMPARE_WITH_TIMEOUT(replica->state(), QRemoteObjectReplica::Valid, 1000);
+
+ QSignalSpy spy(replica, &SimpleClockReplica::timeUpdated);
+ spy.wait();
+ QCOMPARE(spy.count(), 1);
+}
+
+void tst_usertypes::twoReplicas()
+{
+ qmlRegisterType<SimpleClockReplica>("usertypes", 1, 0, "SimpleClockReplica");
+
+ QRemoteObjectRegistryHost host(QUrl("local:testTwoReplicas"));
+ SimpleClockSimpleSource clock;
+ clock.setHour(7);
+ host.enableRemoting(&clock);
+
+ QQmlEngine e;
+ QQmlComponent c(&e, SRCDIR "data/twoReplicas.qml");
+ QObject *obj = c.create();
+ QVERIFY(obj);
+
+ QTRY_COMPARE_WITH_TIMEOUT(obj->property("result").value<int>(), 7, 1000);
+ QTRY_COMPARE_WITH_TIMEOUT(obj->property("result2").value<int>(), 7, 1000);
+}
+
+void tst_usertypes::remoteCompositeType()
+{
+ QQmlEngine e;
+ QQmlComponent c(&e, SRCDIR "data/composite.qml");
+ QScopedPointer<QObject> obj(c.create());
+ QVERIFY(obj);
+
+ QRemoteObjectRegistryHost host(QUrl("local:remoteCompositeType"));
+ host.enableRemoting(obj.data(), "composite");
+}
+
+QTEST_MAIN(tst_usertypes)
+
+#include "tst_usertypes.moc"
--- /dev/null
+#include <QtCore>
+
+class SimpleClock
+{
+ PROP(int hour=6);
+ PROP(int minute=30);
+ SIGNAL(timeUpdated(int hour, int minute, int second=0, int millisecond=0));
+};
+
+class TypeWithModel
+{
+ MODEL tracks(display);
+};
+
+class TypeWithSubObject
+{
+ CLASS clock(SimpleClock);
+};
+
+class ComplexType
+{
+ PROP(int before = 0)
+ MODEL tracks(display)
+ CLASS clock(SimpleClock)
+ PROP(int after = 42)
+}
+
+class TypeWithReply
+{
+ SLOT(QString uppercase(const QString &input))
+ SLOT(QMap<QString, QString> complexReturnType())
+ SLOT(int slowFunction())
+};
--- /dev/null
+
+add_subdirectory(client)
+add_subdirectory(server)
+add_subdirectory(tst)
--- /dev/null
+qt_internal_add_executable(qtro_reconnect_client
+ OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
+ SOURCES main.cpp
+ INCLUDE_DIRECTORIES ${CMAKE_CURRENT_SOURCE_DIR}
+ PUBLIC_LIBRARIES Qt::RemoteObjects Qt::Test
+)
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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 with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QCoreApplication>
+#include <QtTest/QtTest>
+#include <QtRemoteObjects/qremoteobjectnode.h>
+
+class tst_Client_Process : public QObject
+{
+ Q_OBJECT
+
+private Q_SLOTS:
+ void testRun()
+ {
+ const QString url = qEnvironmentVariable("RO_URL");
+ QRemoteObjectNode node;
+ node.connectToNode(QUrl(url));
+ QRemoteObjectDynamicReplica *ro = node.acquireDynamic("SourceObj");
+
+ QSignalSpy initSpy(ro, &QRemoteObjectDynamicReplica::initialized);
+ QVERIFY(initSpy.wait());
+ QSignalSpy pongSpy(ro, SIGNAL(pong()));
+ QMetaObject::invokeMethod(ro, "ping");
+ QVERIFY(pongSpy.wait());
+ QMetaObject::invokeMethod(ro, "ping");
+
+ QVERIFY(initSpy.wait());
+ QMetaObject::invokeMethod(ro, "ping");
+ QVERIFY(pongSpy.wait());
+ QMetaObject::invokeMethod(ro, "ping");
+ QTest::qWait(100);
+ delete ro;
+ }
+};
+
+QTEST_MAIN(tst_Client_Process)
+
+#include "main.moc"
--- /dev/null
+qt_internal_add_executable(qtro_reconnect_server
+ OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
+ SOURCES main.cpp
+ INCLUDE_DIRECTORIES ${CMAKE_CURRENT_SOURCE_DIR}
+ PUBLIC_LIBRARIES Qt::RemoteObjects Qt::Test
+)
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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 with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QCoreApplication>
+#include <QtTest/QtTest>
+#include <QtRemoteObjects/qremoteobjectnode.h>
+#include <QtRemoteObjects/qremoteobjectsource.h>
+
+
+class SourceObj : public QObject
+{
+ Q_OBJECT
+
+public Q_SLOTS:
+ void ping() { ++m_pingCount; };
+
+Q_SIGNALS:
+ void pong();
+
+public:
+ int m_pingCount = 0;
+};
+
+class tst_Server_Process : public QObject
+{
+ Q_OBJECT
+
+private Q_SLOTS:
+ void testRun()
+ {
+ const QString url = qEnvironmentVariable("RO_URL");
+ QRemoteObjectHost *srcNode = new QRemoteObjectHost(QUrl(url));
+ SourceObj so;
+ so.setObjectName(QStringLiteral("SourceObj"));
+ srcNode->enableRemoting(&so);
+
+ QTRY_VERIFY(so.m_pingCount == 1);
+ emit so.pong();
+ QTRY_VERIFY(so.m_pingCount == 2);
+ delete srcNode;
+
+ srcNode = new QRemoteObjectHost(QUrl(url));
+ srcNode->enableRemoting(&so);
+
+ QTRY_VERIFY(so.m_pingCount == 3);
+ emit so.pong();
+ QTRY_VERIFY(so.m_pingCount == 4);
+ delete srcNode;
+ }
+};
+
+QTEST_MAIN(tst_Server_Process)
+
+#include "main.moc"
--- /dev/null
+qt_internal_add_test(tst_reconnect
+ OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
+ SOURCES tst_reconnect.cpp
+ PUBLIC_LIBRARIES Qt::RemoteObjects
+)
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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 with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtTest/QtTest>
+#include <QStandardPaths>
+#include <QProcess>
+#include "../../../shared/testutils.h"
+
+
+class tst_Reconnect: public QObject
+{
+ Q_OBJECT
+
+private slots:
+ void testRun_data()
+ {
+ QTest::addColumn<QString>("url");
+ QTest::addRow("local") << QStringLiteral("local:replica");
+ QTest::addRow("tcp") << QStringLiteral("tcp://127.0.0.1:65217");
+ }
+
+ void testRun()
+ {
+ QFETCH(QString, url);
+
+ QVERIFY(TestUtils::init("tst"));
+
+ QProcess serverProc;
+ serverProc.setProcessChannelMode(QProcess::ForwardedChannels);
+ QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
+ env.insert("RO_URL", url);
+ serverProc.setProcessEnvironment(env);
+ serverProc.start(TestUtils::findExecutable("qtro_reconnect_server", "/server"),
+ QStringList());
+ QVERIFY(serverProc.waitForStarted());
+
+ QProcess clientProc;
+ clientProc.setProcessChannelMode(QProcess::ForwardedChannels);
+ clientProc.setProcessEnvironment(env);
+ clientProc.start(TestUtils::findExecutable("qtro_reconnect_client", "/client"),
+ QStringList());
+ qDebug() << "Started server and client process on:" << url;
+ QVERIFY(clientProc.waitForStarted());
+
+ QVERIFY(clientProc.waitForFinished());
+ QVERIFY(serverProc.waitForFinished());
+
+ QCOMPARE(serverProc.exitCode(), 0);
+ QCOMPARE(clientProc.exitCode(), 0);
+ }
+};
+
+QTEST_MAIN(tst_Reconnect)
+
+#include "tst_reconnect.moc"
--- /dev/null
+
+#####################################################################
+## tst_rep_from_header Test:
+#####################################################################
+
+qt_internal_add_test(tst_rep_from_header
+ SOURCES
+ tst_rep_from_header.cpp
+ PUBLIC_LIBRARIES
+ Qt::RemoteObjects
+)
+qt6_reps_from_headers(tst_rep_from_header pods.h)
+
+#### Keys ignored in scope 1:.:.:rep_from_header.pro:<TRUE>:
+# QOBJECT_REP = "$$REP_FILES"
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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 with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#pragma once
+// This is an autogenerated file.
+// Do not edit this file, any changes made will be lost the next time it is generated.
+
+#include <QObject>
+
+
+#include <QString>
+class PodI
+{
+ Q_GADGET
+ Q_PROPERTY(int i READ i WRITE setI)
+public:
+ explicit PodI() : _i() {}
+ explicit PodI(int i) : _i(i) {}
+ PodI(const PodI& other)
+ {
+ QtRemoteObjects::copyStoredProperties(&other, this);
+ }
+
+ PodI &operator=(const PodI &other)
+ {
+ if (this != &other)
+ QtRemoteObjects::copyStoredProperties(&other, this);
+ return *this;
+ }
+
+ int i() const { return _i; }
+ void setI(int i) { if (i != _i) { _i = i; } }
+private:
+ int _i;
+};
+
+inline QDataStream &operator<<(QDataStream &ds, const PodI &obj) {
+ QtRemoteObjects::copyStoredProperties(&obj, ds);
+ return ds;
+}
+
+inline QDataStream &operator>>(QDataStream &ds, PodI &obj) {
+ QtRemoteObjects::copyStoredProperties(ds, &obj);
+ return ds;
+}
+
+class PodF
+{
+ Q_GADGET
+ Q_PROPERTY(float f READ f WRITE setF)
+public:
+ explicit PodF() : _f() {}
+ explicit PodF(float f) : _f(f) {}
+ PodF(const PodF& other)
+ {
+ QtRemoteObjects::copyStoredProperties(&other, this);
+ }
+
+ PodF &operator=(const PodF &other)
+ {
+ if (this != &other)
+ QtRemoteObjects::copyStoredProperties(&other, this);
+ return *this;
+ }
+
+ float f() const { return _f; }
+ void setF(float f) { if (f != _f) { _f = f; } }
+private:
+ float _f;
+};
+
+inline QDataStream &operator<<(QDataStream &ds, const PodF &obj) {
+ QtRemoteObjects::copyStoredProperties(&obj, ds);
+ return ds;
+}
+
+inline QDataStream &operator>>(QDataStream &ds, PodF &obj) {
+ QtRemoteObjects::copyStoredProperties(ds, &obj);
+ return ds;
+}
+
+class PodS
+{
+ Q_GADGET
+ Q_PROPERTY(QString s READ s WRITE setS)
+public:
+ explicit PodS() : _s() {}
+ explicit PodS(QString s) : _s(s) {}
+ PodS(const PodS& other)
+ {
+ QtRemoteObjects::copyStoredProperties(&other, this);
+ }
+
+ PodS &operator=(const PodS &other)
+ {
+ if (this != &other)
+ QtRemoteObjects::copyStoredProperties(&other, this);
+ return *this;
+ }
+
+ QString s() const { return _s; }
+ void setS(QString s) { if (s != _s) { _s = s; } }
+private:
+ QString _s;
+};
+
+inline QDataStream &operator<<(QDataStream &ds, const PodS &obj) {
+ QtRemoteObjects::copyStoredProperties(&obj, ds);
+ return ds;
+}
+
+inline QDataStream &operator>>(QDataStream &ds, PodS &obj) {
+ QtRemoteObjects::copyStoredProperties(ds, &obj);
+ return ds;
+}
+
+class PodIFS
+{
+ Q_GADGET
+ Q_PROPERTY(int i READ i WRITE setI)
+ Q_PROPERTY(float f READ f WRITE setF)
+ Q_PROPERTY(QString s READ s WRITE setS)
+public:
+ explicit PodIFS() : _i(), _f(), _s() {}
+ explicit PodIFS(int i, float f, QString s) : _i(i), _f(f), _s(s) {}
+ PodIFS(const PodIFS& other)
+ {
+ QtRemoteObjects::copyStoredProperties(&other, this);
+ }
+
+ PodIFS &operator=(const PodIFS &other)
+ {
+ if (this != &other)
+ QtRemoteObjects::copyStoredProperties(&other, this);
+ return *this;
+ }
+
+ int i() const { return _i; }
+ void setI(int i) { if (i != _i) { _i = i; } }
+ float f() const { return _f; }
+ void setF(float f) { if (f != _f) { _f = f; } }
+ QString s() const { return _s; }
+ void setS(QString s) { if (s != _s) { _s = s; } }
+private:
+ int _i;
+ float _f;
+ QString _s;
+};
+
+inline QDataStream &operator<<(QDataStream &ds, const PodIFS &obj) {
+ QtRemoteObjects::copyStoredProperties(&obj, ds);
+ return ds;
+}
+
+inline QDataStream &operator>>(QDataStream &ds, PodIFS &obj) {
+ QtRemoteObjects::copyStoredProperties(ds, &obj);
+ return ds;
+}
+
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2020 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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 with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//#include "rep_pods_replica.h"
+
+#include <QTest>
+
+#include <QByteArray>
+
+class tst_rep_from_header : public QObject {
+ Q_OBJECT
+
+private Q_SLOTS:
+ void testRep_data();
+ void testRep();
+};
+
+void tst_rep_from_header::testRep_data()
+{
+ QTest::addColumn<QString>("actualFile");
+ QTest::addColumn<QByteArrayList>("expectedLines");
+
+ QTest::newRow("pods") << QStringLiteral("pods.rep")
+ << QByteArrayList{"POD PodI(int i)",
+ "POD PodF(float f)",
+ "POD PodS(QString s)",
+ "POD PodIFS(int i, float f, QString s)",
+ ""};
+}
+
+void tst_rep_from_header::testRep()
+{
+ QFETCH(QString, actualFile);
+ QFETCH(QByteArrayList, expectedLines);
+ const auto readFile = [&](const QString &fileName) {
+ QFile f(fileName);
+ f.open(QIODevice::ReadOnly);
+ QByteArrayList lines;
+ while (!f.atEnd())
+ lines.append(f.readLine().trimmed());
+ return lines;
+ };
+
+ QVERIFY2(QFile::exists(actualFile), qPrintable(actualFile));
+
+ QByteArrayList actualLines = readFile(actualFile);
+
+ QVERIFY(actualLines == expectedLines);
+}
+
+QTEST_APPLESS_MAIN(tst_rep_from_header)
+
+#include "tst_rep_from_header.moc"
+
--- /dev/null
+
+add_subdirectory(enums)
+add_subdirectory(pods)
+if(NOT windows)
+ add_subdirectory(signature)
+endif()
--- /dev/null
+
+#####################################################################
+## tst_enums Test:
+#####################################################################
+
+qt_internal_add_test(tst_enums
+ SOURCES
+ tst_enums.cpp
+ PUBLIC_LIBRARIES
+ Qt::RemoteObjects
+)
+qt6_add_repc_replicas(tst_enums
+ enums.rep
+)
+
+## Scopes:
+#####################################################################
--- /dev/null
+
+USE_ENUM(Qt::DayOfWeek)
+
+class TestInterface
+{
+};
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017-2020 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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 with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "rep_enums_replica.h"
+
+#include <QTest>
+
+#include <QByteArray>
+#include <QDataStream>
+
+class tst_Enums : public QObject {
+ Q_OBJECT
+
+private Q_SLOTS:
+ void testMarshalling();
+};
+
+void tst_Enums::testMarshalling()
+{
+ QByteArray ba;
+ QDataStream ds(&ba, QIODevice::ReadWrite);
+
+ {
+ const Qt::DayOfWeek format1 = Qt::Monday;
+ const Qt::DayOfWeek format2 = Qt::Tuesday;
+ const Qt::DayOfWeek format3 = Qt::Wednesday;
+ const Qt::DayOfWeek format4 = Qt::Thursday;
+ const Qt::DayOfWeek format5 = Qt::Friday;
+ const Qt::DayOfWeek format6 = Qt::Saturday;
+ const Qt::DayOfWeek format7 = Qt::Sunday;
+
+ ds << format1 << format2 << format3 << format4 << format5 << format6 << format7;
+ }
+
+ ds.device()->seek(0);
+
+ {
+ Qt::DayOfWeek format1, format2, format3, format4, format5, format6, format7;
+
+ ds >> format1 >> format2 >> format3 >> format4 >> format5 >> format6 >> format7;
+
+ QCOMPARE(format1, Qt::Monday);
+ QCOMPARE(format2, Qt::Tuesday);
+ QCOMPARE(format3, Qt::Wednesday);
+ QCOMPARE(format4, Qt::Thursday);
+ QCOMPARE(format5, Qt::Friday);
+ QCOMPARE(format6, Qt::Saturday);
+ QCOMPARE(format7, Qt::Sunday);
+ }
+}
+
+QTEST_APPLESS_MAIN(tst_Enums)
+
+#include "tst_enums.moc"
--- /dev/null
+
+#####################################################################
+## tst_repc_pods Test:
+#####################################################################
+
+qt_internal_add_test(tst_repc_pods
+ SOURCES
+ tst_pods.cpp
+ PUBLIC_LIBRARIES
+ Qt::RemoteObjects
+)
+qt6_add_repc_replicas(tst_repc_pods
+ pods.rep
+)
+
+## Scopes:
+#####################################################################
--- /dev/null
+#include <QString>
+
+ENUM Test {TRUE, FALSE}
+
+POD PodI(int i)
+POD PodF(float f)
+POD PodS(QString s)
+POD PodIFS(int i, float f, QString s)
+POD PodT(QList<TestEnum::Test> t)
+
+class Container {
+};
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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 with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "rep_pods_replica.h"
+
+#include <QTest>
+
+#include <QByteArray>
+#include <QDataStream>
+
+class tst_Pods : public QObject {
+ Q_OBJECT
+
+private Q_SLOTS:
+ void testConstructors();
+ void testMarshalling();
+ void testProperty();
+};
+
+
+void tst_Pods::testConstructors()
+{
+ PodI pi1;
+ QCOMPARE(pi1.i(), 0);
+
+ PodI pi2(1);
+ QCOMPARE(pi2.i(), 1);
+
+ PodI pi3(pi2);
+ QCOMPARE(pi3.i(), pi2.i());
+}
+
+void tst_Pods::testMarshalling()
+{
+ QByteArray ba;
+ QDataStream ds(&ba, QIODevice::ReadWrite);
+
+ {
+ PodI i1(1), i2(2), i3(3), iDeadBeef(0xdeadbeef);
+ ds << i1 << i2 << i3 << iDeadBeef;
+ }
+
+ ds.device()->seek(0);
+
+ {
+ PodI i1, i2, i3, iDeadBeef;
+ ds >> i1 >> i2 >> i3 >> iDeadBeef;
+
+ QCOMPARE(i1.i(), 1);
+ QCOMPARE(i2.i(), 2);
+ QCOMPARE(i3.i(), 3);
+ QCOMPARE(iDeadBeef.i(), int(0xdeadbeef));
+ }
+}
+
+void tst_Pods::testProperty()
+{
+ ContainerReplica::registerMetatypes();
+
+ PodT pt;
+ QMetaProperty prop = pt.staticMetaObject.property(0);
+ QVERIFY(prop.userType() != 0);
+}
+
+QTEST_APPLESS_MAIN(tst_Pods)
+
+#include "tst_pods.moc"
--- /dev/null
+
+add_subdirectory(signatureServer)
+add_subdirectory(matchAndQuit)
+add_subdirectory(differentGlobalEnum)
+add_subdirectory(differentClassEnum)
+add_subdirectory(differentPropertyCount)
+add_subdirectory(differentPropertyCountChild)
+add_subdirectory(differentPropertyType)
+add_subdirectory(scrambledProperties)
+add_subdirectory(differentSlotCount)
+add_subdirectory(differentSlotType)
+add_subdirectory(differentSlotParamCount)
+add_subdirectory(differentSlotParamType)
+add_subdirectory(scrambledSlots)
+add_subdirectory(differentSignalCount)
+add_subdirectory(differentSignalParamCount)
+add_subdirectory(differentSignalParamType)
+add_subdirectory(scrambledSignals)
+add_subdirectory(state)
+if(QT_FEATURE_process)
+ add_subdirectory(signatureTests)
+endif()
--- /dev/null
+
+#####################################################################
+## differentClassEnum Binary:
+#####################################################################
+
+qt_internal_add_executable(differentClassEnum
+ OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
+ SOURCES
+ ../mismatch.cpp
+ INCLUDE_DIRECTORIES
+ ..
+ PUBLIC_LIBRARIES
+ Qt::RemoteObjects
+ Qt::Test
+)
+qt6_add_repc_replicas(differentClassEnum
+ mismatch.rep
+)
--- /dev/null
+ENUM Test {TRUE, FALSE}
+
+class TestClass
+{
+ ENUM ClassEnum {Null = 2, One, Two}
+
+ PROP(TestEnum::Test testEnum)
+ PROP(ClassEnum classEnum)
+
+ PROP(int prop1);
+ PROP(double prop2);
+
+ SLOT(bool slot1());
+ SLOT(QString slot2());
+
+ SIGNAL(signal1());
+ SIGNAL(signal2());
+
+ SLOT(void ping(const QString &message));
+ SIGNAL(pong(const QString &message));
+
+ SLOT(bool quit());
+};
--- /dev/null
+
+#####################################################################
+## differentGlobalEnum Binary:
+#####################################################################
+
+qt_internal_add_executable(differentGlobalEnum
+ OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
+ SOURCES
+ ../mismatch.cpp
+ INCLUDE_DIRECTORIES
+ ..
+ PUBLIC_LIBRARIES
+ Qt::RemoteObjects
+ Qt::Test
+)
+qt6_add_repc_replicas(differentGlobalEnum
+ mismatch.rep
+)
--- /dev/null
+ENUM Test {FALSE, TRUE}
+
+class TestChildClass
+{
+ PROP(int prop1);
+ PROP(double prop2);
+};
+
+class TestClass
+{
+ ENUM ClassEnum {Null, One, Two}
+
+ PROP(TestEnum::Test testEnum)
+ PROP(ClassEnum classEnum)
+
+ PROP(int prop1);
+ PROP(double prop2);
+
+ SLOT(bool slot1());
+ SLOT(QString slot2());
+
+ CLASS childProp(TestChildClass);
+
+ SIGNAL(signal1());
+ SIGNAL(signal2());
+
+ SLOT(void ping(const QString &message));
+ SIGNAL(pong(const QString &message));
+
+ SLOT(bool quit());
+};
--- /dev/null
+
+#####################################################################
+## differentPropertyCount Binary:
+#####################################################################
+
+qt_internal_add_executable(differentPropertyCount
+ OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
+ SOURCES
+ ../mismatch.cpp
+ INCLUDE_DIRECTORIES
+ ..
+ PUBLIC_LIBRARIES
+ Qt::RemoteObjects
+ Qt::Test
+)
+qt6_add_repc_replicas(differentPropertyCount
+ mismatch.rep
+)
--- /dev/null
+ENUM Test {TRUE, FALSE}
+
+class TestChildClass
+{
+ PROP(int prop1);
+ PROP(double prop2);
+};
+
+class TestClass
+{
+ ENUM ClassEnum {Null, One, Two}
+
+ PROP(TestEnum::Test testEnum)
+ PROP(ClassEnum classEnum)
+
+ PROP(int prop1);
+ PROP(double prop2);
+ PROP(double prop3);
+
+ CLASS childProp(TestChildClass);
+
+ SLOT(bool slot1());
+ SLOT(QString slot2());
+
+ SIGNAL(signal1());
+ SIGNAL(signal2());
+
+ SLOT(void ping(const QString &message));
+ SIGNAL(pong(const QString &message));
+
+ SLOT(bool quit());
+};
--- /dev/null
+
+#####################################################################
+## differentPropertyCount Binary:
+#####################################################################
+
+qt_internal_add_executable(differentPropertyCountChild
+ OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
+ SOURCES
+ ../mismatch.cpp
+ INCLUDE_DIRECTORIES
+ ..
+ PUBLIC_LIBRARIES
+ Qt::RemoteObjects
+ Qt::Test
+)
+qt6_add_repc_replicas(differentPropertyCountChild
+ mismatch.rep
+)
--- /dev/null
+include(../mismatch.pri)
+
+TARGET = differentPropertyCountChild
+
+REPC_REPLICA = $$PWD/mismatch.rep
--- /dev/null
+ENUM Test {TRUE, FALSE}
+
+class TestChildClass
+{
+ PROP(double prop2);
+};
+
+class TestClass
+{
+ ENUM ClassEnum {Null, One, Two}
+
+ PROP(TestEnum::Test testEnum)
+ PROP(ClassEnum classEnum)
+
+ PROP(int prop1);
+ PROP(double prop2);
+
+ CLASS childProp(TestChildClass);
+
+ SLOT(bool slot1());
+ SLOT(QString slot2());
+
+ SIGNAL(signal1());
+ SIGNAL(signal2());
+
+ SLOT(void ping(const QString &message));
+ SIGNAL(pong(const QString &message));
+
+ SLOT(bool quit());
+};
--- /dev/null
+
+#####################################################################
+## differentPropertyType Binary:
+#####################################################################
+
+qt_internal_add_executable(differentPropertyType
+ OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
+ SOURCES
+ ../mismatch.cpp
+ INCLUDE_DIRECTORIES
+ ..
+ PUBLIC_LIBRARIES
+ Qt::RemoteObjects
+ Qt::Test
+)
+qt6_add_repc_replicas(differentPropertyType
+ mismatch.rep
+)
--- /dev/null
+ENUM Test {TRUE, FALSE}
+
+class TestChildClass
+{
+ PROP(int prop1);
+ PROP(double prop2);
+};
+
+class TestClass
+{
+ ENUM ClassEnum {Null, One, Two}
+
+ PROP(TestEnum::Test testEnum)
+ PROP(ClassEnum classEnum)
+
+ PROP(int prop1);
+ PROP(QString prop2);
+
+ SLOT(bool slot1());
+ SLOT(QString slot2());
+
+ CLASS childProp(TestChildClass);
+
+ SIGNAL(signal1());
+ SIGNAL(signal2());
+
+ SLOT(void ping(const QString &message));
+ SIGNAL(pong(const QString &message));
+
+ SLOT(bool quit());
+};
--- /dev/null
+
+#####################################################################
+## differentSignalCount Binary:
+#####################################################################
+
+qt_internal_add_executable(differentSignalCount
+ OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
+ SOURCES
+ ../mismatch.cpp
+ INCLUDE_DIRECTORIES
+ ..
+ PUBLIC_LIBRARIES
+ Qt::RemoteObjects
+ Qt::Test
+)
+qt6_add_repc_replicas(differentSignalCount
+ mismatch.rep
+)
--- /dev/null
+ENUM Test {TRUE, FALSE}
+
+class TestChildClass
+{
+ PROP(int prop1);
+ PROP(double prop2);
+};
+
+class TestClass
+{
+ ENUM ClassEnum {Null, One, Two}
+
+ PROP(TestEnum::Test testEnum)
+ PROP(ClassEnum classEnum)
+
+ PROP(int prop1);
+ PROP(double prop2);
+
+ CLASS childProp(TestChildClass);
+
+ SLOT(bool slot1());
+ SLOT(QString slot2());
+
+ SIGNAL(signal1());
+ SIGNAL(signal2());
+ SIGNAL(anotherSignal());
+
+ SLOT(void ping(const QString &message));
+ SIGNAL(pong(const QString &message));
+
+ SLOT(bool quit());
+};
--- /dev/null
+
+#####################################################################
+## differentSignalParamCount Binary:
+#####################################################################
+
+qt_internal_add_executable(differentSignalParamCount
+ OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
+ SOURCES
+ ../mismatch.cpp
+ INCLUDE_DIRECTORIES
+ ..
+ PUBLIC_LIBRARIES
+ Qt::RemoteObjects
+ Qt::Test
+)
+qt6_add_repc_replicas(differentSignalParamCount
+ mismatch.rep
+)
--- /dev/null
+ENUM Test {TRUE, FALSE}
+
+class TestChildClass
+{
+ PROP(int prop1);
+ PROP(double prop2);
+};
+
+class TestClass
+{
+ ENUM ClassEnum {Null, One, Two}
+
+ PROP(TestEnum::Test testEnum)
+ PROP(ClassEnum classEnum)
+
+ PROP(int prop1);
+ PROP(double prop2);
+
+ SLOT(bool slot1());
+ SLOT(QString slot2());
+
+ CLASS childProp(TestChildClass);
+
+ SIGNAL(signal1());
+ SIGNAL(signal2());
+
+ SLOT(void ping(const QString &message));
+ SIGNAL(pong(const QString &message, int anotherParam));
+
+ SLOT(bool quit());
+};
--- /dev/null
+
+#####################################################################
+## differentSignalParamType Binary:
+#####################################################################
+
+qt_internal_add_executable(differentSignalParamType
+ OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
+ SOURCES
+ ../mismatch.cpp
+ INCLUDE_DIRECTORIES
+ ..
+ PUBLIC_LIBRARIES
+ Qt::RemoteObjects
+ Qt::Test
+)
+qt6_add_repc_replicas(differentSignalParamType
+ mismatch.rep
+)
--- /dev/null
+ENUM Test {TRUE, FALSE}
+
+class TestChildClass
+{
+ PROP(int prop1);
+ PROP(double prop2);
+};
+
+class TestClass
+{
+ ENUM ClassEnum {Null, One, Two}
+
+ PROP(TestEnum::Test testEnum)
+ PROP(ClassEnum classEnum)
+
+ PROP(int prop1);
+ PROP(double prop2);
+
+ CLASS childProp(TestChildClass);
+
+ SLOT(bool slot1());
+ SLOT(QString slot2());
+
+ SIGNAL(signal1());
+ SIGNAL(signal2());
+
+ SLOT(void ping(const QString &message));
+ SIGNAL(pong(const QByteArray &message));
+
+ SLOT(bool quit());
+};
--- /dev/null
+
+#####################################################################
+## differentSlotCount Binary:
+#####################################################################
+
+qt_internal_add_executable(differentSlotCount
+ OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
+ SOURCES
+ ../mismatch.cpp
+ INCLUDE_DIRECTORIES
+ ..
+ PUBLIC_LIBRARIES
+ Qt::RemoteObjects
+ Qt::Test
+)
+qt6_add_repc_replicas(differentSlotCount
+ mismatch.rep
+)
--- /dev/null
+ENUM Test {TRUE, FALSE}
+
+class TestChildClass
+{
+ PROP(int prop1);
+ PROP(double prop2);
+};
+
+class TestClass
+{
+ ENUM ClassEnum {Null, One, Two}
+
+ PROP(TestEnum::Test testEnum)
+ PROP(ClassEnum classEnum)
+
+ PROP(int prop1);
+ PROP(double prop2);
+
+ CLASS childProp(TestChildClass);
+
+ SLOT(bool slot1());
+ SLOT(QString slot2());
+ SLOT(void anotherSlot());
+
+ SIGNAL(signal1());
+ SIGNAL(signal2());
+
+ SLOT(void ping(const QString &message));
+ SIGNAL(pong(const QString &message));
+
+ SLOT(bool quit());
+};
--- /dev/null
+
+#####################################################################
+## differentSlotParamCount Binary:
+#####################################################################
+
+qt_internal_add_executable(differentSlotParamCount
+ OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
+ SOURCES
+ ../mismatch.cpp
+ INCLUDE_DIRECTORIES
+ ..
+ PUBLIC_LIBRARIES
+ Qt::RemoteObjects
+ Qt::Test
+)
+qt6_add_repc_replicas(differentSlotParamCount
+ mismatch.rep
+)
--- /dev/null
+ENUM Test {TRUE, FALSE}
+
+class TestChildClass
+{
+ PROP(int prop1);
+ PROP(double prop2);
+};
+
+class TestClass
+{
+ ENUM ClassEnum {Null, One, Two}
+
+ PROP(TestEnum::Test testEnum)
+ PROP(ClassEnum classEnum)
+
+ PROP(int prop1);
+ PROP(double prop2);
+
+ CLASS childProp(TestChildClass);
+
+ SLOT(bool slot1());
+ SLOT(QString slot2());
+
+ SIGNAL(signal1());
+ SIGNAL(signal2());
+
+ SLOT(void ping(const QString &message, int anotherParam));
+ SIGNAL(pong(const QString &message));
+
+ SLOT(bool quit());
+};
--- /dev/null
+
+#####################################################################
+## differentSlotParamType Binary:
+#####################################################################
+
+qt_internal_add_executable(differentSlotParamType
+ OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
+ SOURCES
+ ../mismatch.cpp
+ INCLUDE_DIRECTORIES
+ ..
+ PUBLIC_LIBRARIES
+ Qt::RemoteObjects
+ Qt::Test
+)
+qt6_add_repc_replicas(differentSlotParamType
+ mismatch.rep
+)
--- /dev/null
+ENUM Test {TRUE, FALSE}
+
+class TestChildClass
+{
+ PROP(int prop1);
+ PROP(double prop2);
+};
+
+class TestClass
+{
+ ENUM ClassEnum {Null, One, Two}
+
+ PROP(TestEnum::Test testEnum)
+ PROP(ClassEnum classEnum)
+
+ PROP(int prop1);
+ PROP(double prop2);
+
+ CLASS childProp(TestChildClass);
+
+ SLOT(bool slot1());
+ SLOT(QString slot2());
+
+ SIGNAL(signal1());
+ SIGNAL(signal2());
+
+ SLOT(void ping(const QByteArray &message));
+ SIGNAL(pong(const QString &message));
+
+ SLOT(bool quit());
+};
--- /dev/null
+
+#####################################################################
+## differentSlotType Binary:
+#####################################################################
+
+qt_internal_add_executable(differentSlotType
+ OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
+ SOURCES
+ ../mismatch.cpp
+ INCLUDE_DIRECTORIES
+ ..
+ PUBLIC_LIBRARIES
+ Qt::RemoteObjects
+ Qt::Test
+)
+qt6_add_repc_replicas(differentSlotType
+ mismatch.rep
+)
--- /dev/null
+ENUM Test {TRUE, FALSE}
+
+class TestChildClass
+{
+ PROP(int prop1);
+ PROP(double prop2);
+};
+
+class TestClass
+{
+ ENUM ClassEnum {Null, One, Two}
+
+ PROP(TestEnum::Test testEnum)
+ PROP(ClassEnum classEnum)
+
+ PROP(int prop1);
+ PROP(double prop2);
+
+ CLASS childProp(TestChildClass);
+
+ SLOT(bool slot1());
+ SLOT(int slot2());
+
+ SIGNAL(signal1());
+ SIGNAL(signal2());
+
+ SLOT(void ping(const QString &message));
+ SIGNAL(pong(const QString &message));
+
+ SLOT(bool quit());
+};
--- /dev/null
+
+#####################################################################
+## matchAndQuit Binary:
+#####################################################################
+
+qt_internal_add_executable(matchAndQuit
+ OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
+ SOURCES
+ main.cpp
+ INCLUDE_DIRECTORIES
+ ${CMAKE_CURRENT_SOURCE_DIR}
+ PUBLIC_LIBRARIES
+ Qt::RemoteObjects
+ Qt::Test
+)
+qt6_add_repc_replicas(matchAndQuit
+ ../server.rep
+)
+
+#### Keys ignored in scope 1:.:.:matchAndQuit.pro:<TRUE>:
+# TEMPLATE = "app"
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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 with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "rep_server_replica.h"
+
+#include <QCoreApplication>
+#include <QtRemoteObjects/qremoteobjectnode.h>
+#include <QtTest/QtTest>
+
+class tst_Match_Process : public QObject
+{
+ Q_OBJECT
+
+private Q_SLOTS:
+ void testRun()
+ {
+ QRemoteObjectNode repNode;
+ repNode.connectToNode(QUrl(QStringLiteral("tcp://127.0.0.1:65214")));
+ QSharedPointer<TestClassReplica> rep(repNode.acquire<TestClassReplica>());
+ QSignalSpy stateChangedSpy(rep.data(), &QRemoteObjectReplica::stateChanged);
+ QVERIFY(rep->waitForSource());
+ QCOMPARE(rep->state(), QRemoteObjectReplica::Valid);
+
+ QVERIFY(rep->quit().waitForFinished());
+ QTRY_COMPARE(rep->state(), QRemoteObjectReplica::Suspect);
+
+ QCOMPARE(stateChangedSpy.count(), 2);
+
+ // Test Default to Valid transition
+ auto args = stateChangedSpy.takeFirst();
+ QCOMPARE(args.count(), 2);
+ QCOMPARE(args.at(0).toInt(), int(QRemoteObjectReplica::Valid));
+ QCOMPARE(args.at(1).toInt(), int(QRemoteObjectReplica::Default));
+
+ // Test Valid to Suspect transition
+ args = stateChangedSpy.takeFirst();
+ QCOMPARE(args.count(), 2);
+ QCOMPARE(args.at(0).toInt(), int(QRemoteObjectReplica::Suspect));
+ QCOMPARE(args.at(1).toInt(), int(QRemoteObjectReplica::Valid));
+ }
+};
+
+QTEST_MAIN(tst_Match_Process)
+
+#include "main.moc"
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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 with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "rep_mismatch_replica.h"
+
+#include <QCoreApplication>
+#include <QtRemoteObjects/qremoteobjectnode.h>
+#include <QtTest/QtTest>
+
+class tst_Mismatch_Process : public QObject
+{
+ Q_OBJECT
+
+private Q_SLOTS:
+ void testRun()
+ {
+ QRemoteObjectNode repNode;
+ repNode.connectToNode(QUrl(QStringLiteral("tcp://127.0.0.1:65214")));
+ QTest::ignoreMessage(QtWarningMsg, " Signature mismatch for TestClassReplica \"TestClass\"");
+ QSharedPointer<TestClassReplica> rep(repNode.acquire<TestClassReplica>());
+ QTRY_COMPARE(rep->state(), QRemoteObjectReplica::SignatureMismatch);
+ }
+};
+
+QTEST_MAIN(tst_Mismatch_Process)
+
+#include "mismatch.moc"
--- /dev/null
+TEMPLATE = app
+QT += remoteobjects core testlib
+QT -= gui
+
+DESTDIR = ./
+CONFIG += c++11
+CONFIG -= app_bundle
+
+INCLUDEPATH += $$PWD
+SOURCES += $$PWD/mismatch.cpp
--- /dev/null
+
+#####################################################################
+## scrambledProperties Binary:
+#####################################################################
+
+qt_internal_add_executable(scrambledProperties
+ OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
+ SOURCES
+ ../mismatch.cpp
+ INCLUDE_DIRECTORIES
+ ..
+ PUBLIC_LIBRARIES
+ Qt::RemoteObjects
+ Qt::Test
+)
+qt6_add_repc_replicas(scrambledProperties
+ mismatch.rep
+)
--- /dev/null
+ENUM Test {TRUE, FALSE}
+
+class TestChildClass
+{
+ PROP(int prop1);
+ PROP(double prop2);
+};
+
+class TestClass
+{
+ ENUM ClassEnum {Null, One, Two}
+
+ PROP(TestEnum::Test testEnum)
+ PROP(ClassEnum classEnum)
+
+ PROP(double prop2);
+ PROP(int prop1);
+
+ CLASS childProp(TestChildClass);
+
+ SLOT(bool slot1());
+ SLOT(QString slot2());
+
+ SIGNAL(signal1());
+ SIGNAL(signal2());
+
+ SLOT(void ping(const QString &message));
+ SIGNAL(pong(const QString &message));
+
+ SLOT(bool quit());
+};
--- /dev/null
+
+#####################################################################
+## scrambledSignals Binary:
+#####################################################################
+
+qt_internal_add_executable(scrambledSignals
+ OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
+ SOURCES
+ ../mismatch.cpp
+ INCLUDE_DIRECTORIES
+ ..
+ PUBLIC_LIBRARIES
+ Qt::RemoteObjects
+ Qt::Test
+)
+qt6_add_repc_replicas(scrambledSignals
+ mismatch.rep
+)
--- /dev/null
+ENUM Test {TRUE, FALSE}
+
+class TestChildClass
+{
+ PROP(int prop1);
+ PROP(double prop2);
+};
+
+class TestClass
+{
+ ENUM ClassEnum {Null, One, Two}
+
+ PROP(TestEnum::Test testEnum)
+ PROP(ClassEnum classEnum)
+
+ PROP(int prop1);
+ PROP(double prop2);
+
+ CLASS childProp(TestChildClass);
+
+ SLOT(bool slot1());
+ SLOT(QString slot2());
+
+ SIGNAL(signal2());
+ SIGNAL(signal1());
+
+ SLOT(void ping(const QString &message));
+ SIGNAL(pong(const QString &message));
+
+ SLOT(bool quit());
+};
--- /dev/null
+
+#####################################################################
+## scrambledSlots Binary:
+#####################################################################
+
+qt_internal_add_executable(scrambledSlots
+ OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
+ SOURCES
+ ../mismatch.cpp
+ INCLUDE_DIRECTORIES
+ ..
+ PUBLIC_LIBRARIES
+ Qt::RemoteObjects
+ Qt::Test
+)
+qt6_add_repc_replicas(scrambledSlots
+ mismatch.rep
+)
--- /dev/null
+ENUM Test {TRUE, FALSE}
+
+class TestChildClass
+{
+ PROP(int prop1);
+ PROP(double prop2);
+};
+
+class TestClass
+{
+ ENUM ClassEnum {Null, One, Two}
+
+ PROP(TestEnum::Test testEnum)
+ PROP(ClassEnum classEnum)
+
+ PROP(int prop1);
+ PROP(double prop2);
+
+ CLASS childProp(TestChildClass);
+
+ SLOT(QString slot2());
+ SLOT(bool slot1());
+
+ SIGNAL(signal1());
+ SIGNAL(signal2());
+
+ SLOT(void ping(const QString &message));
+ SIGNAL(pong(const QString &message));
+
+ SLOT(bool quit());
+};
--- /dev/null
+ENUM Test {TRUE, FALSE}
+
+class TestChildClass
+{
+ PROP(int prop1);
+ PROP(double prop2);
+};
+
+class TestClass
+{
+ ENUM ClassEnum {Null, One, Two}
+
+ PROP(TestEnum::Test testEnum)
+ PROP(ClassEnum classEnum)
+
+ PROP(int prop1);
+ PROP(double prop2);
+
+ CLASS childProp(TestChildClass);
+
+ SLOT(bool slot1());
+ SLOT(QString slot2());
+
+ SIGNAL(signal1());
+ SIGNAL(signal2());
+
+ SLOT(void ping(const QString &message));
+ SIGNAL(pong(const QString &message));
+
+ SLOT(bool quit());
+};
--- /dev/null
+
+#####################################################################
+## signatureServer Binary:
+#####################################################################
+
+qt_internal_add_executable(signatureServer
+ OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
+ SOURCES
+ ${CMAKE_CURRENT_BINARY_DIR}/rep_server_source.h
+ main.cpp
+ INCLUDE_DIRECTORIES
+ ${CMAKE_CURRENT_SOURCE_DIR}
+ PUBLIC_LIBRARIES
+ Qt::RemoteObjects
+ Qt::Test
+)
+qt6_add_repc_sources(signatureServer
+ ../server.rep
+)
+
+#### Keys ignored in scope 1:.:.:signatureServer.pro:<TRUE>:
+# TEMPLATE = "app"
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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 with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "rep_server_source.h"
+
+#include <QCoreApplication>
+#include <QtTest/QtTest>
+
+class MyTestServer : public TestClassSimpleSource
+{
+ Q_OBJECT
+public:
+ bool shouldQuit = false;
+ // TestClassSimpleSource interface
+public slots:
+ bool slot1() override {return true;}
+ QString slot2() override {return QLatin1String("Hello there");}
+ void ping(const QString &message) override
+ {
+ emit pong(message);
+ }
+
+ bool quit() override
+ {
+ qDebug() << "quit() called";
+
+ return shouldQuit = true;
+ }
+};
+
+class tst_Server_Process : public QObject
+{
+ Q_OBJECT
+
+private Q_SLOTS:
+ void testRun()
+ {
+ QRemoteObjectHost srcNode(QUrl(QStringLiteral("tcp://127.0.0.1:65214")));
+ MyTestServer myTestServer{};
+ TestChildClassSimpleSource child;
+ myTestServer.setChildProp(&child);
+
+ srcNode.enableRemoting(&myTestServer);
+
+ qDebug() << "Waiting for incoming connections";
+
+ QTRY_VERIFY_WITH_TIMEOUT(myTestServer.shouldQuit, 20000); // wait up to 20s
+
+ qDebug() << "Stopping server";
+ QTest::qWait(200); // wait for server to send reply to client invoking quit() function
+ }
+};
+
+QTEST_MAIN(tst_Server_Process)
+
+#include "main.moc"
--- /dev/null
+
+#####################################################################
+## tst_signature Test:
+#####################################################################
+
+qt_internal_add_test(tst_signature
+ OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
+ SOURCES
+ tst_signature.cpp
+ PUBLIC_LIBRARIES
+ Qt::RemoteObjects
+)
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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 with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "../../../../shared/testutils.h"
+
+#include <QtTest/QtTest>
+#include <QMetaType>
+#include <QProcess>
+
+typedef QLatin1String _;
+class tst_Signature: public QObject
+{
+ Q_OBJECT
+
+private slots:
+ void initTestCase()
+ {
+ QVERIFY(TestUtils::init("signatureTests"));
+ QLoggingCategory::setFilterRules("qt.remoteobjects.warning=false");
+ }
+
+ void cleanup()
+ {
+ // wait for delivery of RemoveObject events to the source
+ QTest::qWait(200);
+ }
+
+ void testRun()
+ {
+ qDebug() << "Starting signatureServer process";
+ QProcess serverProc;
+ serverProc.setProcessChannelMode(QProcess::ForwardedChannels);
+ serverProc.start(TestUtils::findExecutable("signatureServer", "/signatureServer"),
+ QStringList());
+ QVERIFY(serverProc.waitForStarted());
+
+ // wait for server start
+ QTest::qWait(200);
+
+ const QLatin1String tests[] = {
+ _("differentGlobalEnum"),
+ _("differentClassEnum"),
+ _("differentPropertyCount"),
+ _("differentPropertyCountChild"),
+ _("differentPropertyType"),
+ _("scrambledProperties"),
+ _("differentSlotCount"),
+ _("differentSlotType"),
+ _("differentSlotParamCount"),
+ _("differentSlotParamType"),
+ _("scrambledSlots"),
+ _("differentSignalCount"),
+ _("differentSignalParamCount"),
+ _("differentSignalParamType"),
+ _("scrambledSignals"),
+ _("state"),
+ _("matchAndQuit"), // matchAndQuit should be the last one
+ };
+
+ for (const auto &test : tests) {
+ qDebug() << "Starting" << test << "process";
+ QProcess testProc;
+ testProc.setProcessChannelMode(QProcess::ForwardedChannels);
+ testProc.start(TestUtils::findExecutable(test, "/" + test ),
+ QStringList());
+ QVERIFY(testProc.waitForStarted());
+ QVERIFY(testProc.waitForFinished());
+ QCOMPARE(testProc.exitCode(), 0);
+ }
+
+ QVERIFY(serverProc.waitForFinished());
+ QCOMPARE(serverProc.exitCode(), 0);
+ }
+};
+
+QTEST_MAIN(tst_Signature)
+
+#include "tst_signature.moc"
--- /dev/null
+
+#####################################################################
+## state Binary:
+#####################################################################
+
+qt_internal_add_executable(state
+ OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
+ SOURCES
+ main.cpp
+ INCLUDE_DIRECTORIES
+ ${CMAKE_CURRENT_SOURCE_DIR}
+ PUBLIC_LIBRARIES
+ Qt::RemoteObjects
+ Qt::Test
+)
+qt6_add_repc_replicas(state
+ mismatch.rep
+)
+
+#### Keys ignored in scope 1:.:.:state.pro:<TRUE>:
+# TEMPLATE = "app"
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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 with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "rep_mismatch_replica.h"
+
+#include <QCoreApplication>
+#include <QtRemoteObjects/qremoteobjectnode.h>
+#include <QtTest/QtTest>
+
+class tst_State_Process : public QObject
+{
+ Q_OBJECT
+
+private Q_SLOTS:
+ void testMismatch()
+ {
+ QRemoteObjectNode repNode;
+ repNode.connectToNode(QUrl{QStringLiteral("tcp://127.0.0.1:65214")});
+ QSharedPointer<TestClassReplica> rep{repNode.acquire<TestClassReplica>()};
+ QSignalSpy stateChangedSpy(rep.data(), &QRemoteObjectReplica::stateChanged);
+ QTRY_COMPARE(rep->state(), QRemoteObjectReplica::SignatureMismatch);
+ QCOMPARE(stateChangedSpy.count(), 1);
+ auto args = stateChangedSpy.takeFirst();
+ QCOMPARE(args.count(), 2);
+ QCOMPARE(args.at(0).toInt(), int(QRemoteObjectReplica::SignatureMismatch));
+ QCOMPARE(args.at(1).toInt(), int(QRemoteObjectReplica::Default));
+ }
+
+ void testDynamic()
+ {
+ QRemoteObjectNode repNode;
+ repNode.connectToNode(QUrl{QStringLiteral("tcp://127.0.0.1:65214")});
+ QSharedPointer<QRemoteObjectDynamicReplica> rep{repNode.acquireDynamic("TestClass")};
+ QSignalSpy stateChangedSpy(rep.data(), &QRemoteObjectReplica::stateChanged);
+ QTRY_COMPARE(rep->state(), QRemoteObjectReplica::Valid);
+ QCOMPARE(stateChangedSpy.count(), 1);
+ auto args = stateChangedSpy.takeFirst();
+ QCOMPARE(args.count(), 2);
+ QCOMPARE(args.at(0).toInt(), int(QRemoteObjectReplica::Valid));
+ QCOMPARE(args.at(1).toInt(), int(QRemoteObjectReplica::Uninitialized));
+ }
+};
+
+QTEST_MAIN(tst_State_Process)
+
+#include "main.moc"
--- /dev/null
+ENUM Test {TRUE, FALSE}
+
+class TestChildClass
+{
+ PROP(int prop1);
+ PROP(double prop2);
+};
+
+class TestClass
+{
+ ENUM ClassEnum {Null, One, Two}
+
+ PROP(TestEnum::Test testEnum)
+ PROP(ClassEnum classEnum)
+
+ PROP(int prop1);
+ PROP(double prop2);
+
+ CLASS childProp(TestChildClass);
+
+ SLOT(QString slot2());
+ SLOT(bool slot1());
+
+ SIGNAL(signal1());
+ SIGNAL(signal2());
+
+ SLOT(void ping(const QString &message));
+ SIGNAL(pong(const QString &message));
+
+ SLOT(bool quit());
+};
--- /dev/null
+
+#####################################################################
+## tst_repcodegenerator Test:
+#####################################################################
+
+qt_internal_add_test(tst_repcodegenerator
+ SOURCES
+ tst_repcodegenerator.cpp
+ PUBLIC_LIBRARIES
+ Qt::RemoteObjects
+)
+qt6_add_repc_merged(tst_repcodegenerator
+ classwithsignalonlytest.rep
+ preprocessortest.rep
+ classwithreadonlypropertytest.rep
+)
+
+## Scopes:
+#####################################################################
--- /dev/null
+class MyReadOnlyPropClass
+{
+ PROP(bool myProp READONLY)
+}
--- /dev/null
+class MyClass
+{
+ SIGNAL(mySignal(int))
+}
--- /dev/null
+#include <QString>
+
+#define PREPROCESSORTEST_MACRO 1
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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 with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "rep_preprocessortest_merged.h"
+
+#include <QTest>
+
+class tst_RepCodeGenerator : public QObject {
+ Q_OBJECT
+
+private Q_SLOTS:
+ void testPreprocessorTestFile();
+};
+
+void tst_RepCodeGenerator::testPreprocessorTestFile()
+{
+ // could be a compile-time test, but let's just do something here
+ QVERIFY(PREPROCESSORTEST_MACRO);
+}
+
+QTEST_APPLESS_MAIN(tst_RepCodeGenerator)
+
+#include "tst_repcodegenerator.moc"
--- /dev/null
+class LocalDataCenter
+{
+ PROP(int data1);
+ PROP(float data2);
+ PROP(QString data3);
+ PROP(QList<int> data4);
+ SIGNAL(callMe(QList<int> fun));
+};
--- /dev/null
+class TcpDataCenter
+{
+ PROP(int data1);
+ PROP(float data2);
+ PROP(QString data3);
+ PROP(QList<int> data4);
+};
--- /dev/null
+#####################################################################
+## tst_parser Test:
+#####################################################################
+
+set(REPPARSER_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../../src/repparser")
+
+qt_internal_add_test(tst_parser
+ SOURCES
+ tst_parser.cpp
+ INCLUDE_DIRECTORIES
+ ${REPPARSER_DIR}
+ PUBLIC_LIBRARIES
+ Qt::CorePrivate
+)
+
+# QLALR Grammars:
+qt_process_qlalr(
+ tst_parser
+ ${REPPARSER_DIR}/parser.g
+ ""
+)
+
+## Scopes:
+#####################################################################
+
+qt_internal_extend_target(tst_parser CONDITION MSVC
+ COMPILE_OPTIONS
+ /wd4129
+)
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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 with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "repparser.h"
+
+#include <QTemporaryFile>
+#include <QTest>
+#include <QTextStream>
+
+Q_DECLARE_METATYPE(ASTProperty::Modifier)
+Q_DECLARE_METATYPE(ASTModelRole)
+
+class tst_Parser : public QObject {
+ Q_OBJECT
+
+private Q_SLOTS:
+ void testBasic_data();
+ void testBasic();
+ void testProperties_data();
+ void testProperties();
+ void testSlots_data();
+ void testSlots();
+ void testSignals_data();
+ void testSignals();
+ void testPods_data();
+ void testPods();
+ void testPods2_data();
+ void testPods2();
+ void testEnums_data();
+ void testEnums();
+ void testTypedEnums_data();
+ void testTypedEnums();
+ void testModels_data();
+ void testModels();
+ void testClasses_data();
+ void testClasses();
+ void testInvalid_data();
+ void testInvalid();
+};
+
+void tst_Parser::testBasic_data()
+{
+ QTest::addColumn<QString>("content");
+
+ //Comment out "empty" tests that fail QLALR parser...
+ //QTest::newRow("empty") << ""; // empty lines are fine...
+ QTest::newRow("preprocessor_line_include") << "#include \"foo\"";
+ QTest::newRow("preprocessor_line_include_spaces") << "# include \"foo\"";
+ QTest::newRow("preprocessor_line_ifgroup") << "#if 1\n#include \"foo\n#endif";
+ //QTest::newRow("comment") << "//This is a comment";
+ QTest::newRow("enum") << "ENUM MyEnum {test}";
+ QTest::newRow("empty class with comment") << "class MyClass {\n//comment\n}";
+ QTest::newRow("comment, class") << "//comment\nclass MyClass {}";
+ QTest::newRow("include, comment, class") << "#include \"foo\"\n//comment\nclass MyClass {}";
+}
+
+void tst_Parser::testBasic()
+{
+ QFETCH(QString, content);
+
+ QTemporaryFile file;
+ file.open();
+ QTextStream stream(&file);
+ stream << content << Qt::endl;
+ file.seek(0);
+
+ RepParser parser(file);
+ QVERIFY(parser.parse());
+}
+
+void tst_Parser::testProperties_data()
+{
+ QTest::addColumn<QString>("propertyDeclaration");
+ QTest::addColumn<QString>("expectedType");
+ QTest::addColumn<QString>("expectedName");
+ QTest::addColumn<QString>("expectedDefaultValue");
+ QTest::addColumn<ASTProperty::Modifier>("expectedModifier");
+ QTest::addColumn<bool>("expectedPersistence");
+
+ QTest::newRow("default") << "PROP(QString foo)" << "QString" << "foo" << QString() << ASTProperty::ReadPush << false;
+ QTest::newRow("default with comment") << "PROP(QString foo) // my property" << "QString" << "foo" << QString() << ASTProperty::ReadPush << false;
+ QTest::newRow("default with comment above") << "// my property\nPROP(QString foo)" << "QString" << "foo" << QString() << ASTProperty::ReadPush << false;
+ QTest::newRow("default with indented comment above") << " // my property\nPROP(QString foo)" << "QString" << "foo" << QString() << ASTProperty::ReadPush << false;
+ QTest::newRow("readonly") << "PROP(QString foo READONLY)" << "QString" << "foo" << QString() << ASTProperty::ReadOnly << false;
+ QTest::newRow("constant") << "PROP(QString foo CONSTANT)" << "QString" << "foo" << QString() << ASTProperty::Constant << false;
+ QTest::newRow("readwrite") << "PROP(QString foo READWRITE)" << "QString" << "foo" << QString() << ASTProperty::ReadWrite << false;
+ QTest::newRow("readpush") << "PROP(QString foo READPUSH)" << "QString" << "foo" << QString() << ASTProperty::ReadPush << false;
+ QTest::newRow("persisted") << "PROP(QString foo PERSISTED)" << "QString" << "foo" << QString() << ASTProperty::ReadPush << true;
+ QTest::newRow("readonly, persisted") << "PROP(QString foo READONLY, PERSISTED)" << "QString" << "foo" << QString() << ASTProperty::ReadOnly << true;
+ QTest::newRow("readwrite, persisted") << "PROP(QString foo READWRITE, PERSISTED)" << "QString" << "foo" << QString() << ASTProperty::ReadWrite << true;
+ QTest::newRow("readpush, persisted") << "PROP(QString foo READPUSH, PERSISTED)" << "QString" << "foo" << QString() << ASTProperty::ReadPush << true;
+ QTest::newRow("constant,persisted") << "PROP(QString foo CONSTANT, PERSISTED)" << "QString" << "foo" << QString() << ASTProperty::Constant << true;
+ QTest::newRow("constant,readonly,persisted") << "PROP(QString foo CONSTANT, READONLY, PERSISTED)" << "QString" << "foo" << QString() << ASTProperty::Constant << true;
+ QTest::newRow("readonly,constant,persisted") << "PROP(QString foo READONLY,CONSTANT, PERSISTED)" << "QString" << "foo" << QString() << ASTProperty::Constant << true;
+ QTest::newRow("defaultWithValue") << "PROP(int foo=1)" << "int" << "foo" << "1" << ASTProperty::ReadPush << false;
+ QTest::newRow("readonlyWithValue") << "PROP(int foo=1 READONLY)" << "int" << "foo" << "1" << ASTProperty::ReadOnly << false;
+ QTest::newRow("constantWithValue") << "PROP(int foo=1 CONSTANT)" << "int" << "foo" << "1" << ASTProperty::Constant << false;
+ QTest::newRow("defaultWhitespaces") << "PROP( QString foo )" << "QString" << "foo" << QString() << ASTProperty::ReadPush << false;
+ QTest::newRow("defaultWhitespacesBeforeParentheses") << "PROP ( QString foo )" << "QString" << "foo" << QString() << ASTProperty::ReadPush << false;
+ QTest::newRow("readonlyWhitespaces") << "PROP( QString foo READONLY )" << "QString" << "foo" << QString() << ASTProperty::ReadOnly << false;
+ QTest::newRow("constantWhitespaces") << "PROP( QString foo CONSTANT )" << "QString" << "foo" << QString() << ASTProperty::Constant << false;
+ QTest::newRow("defaultWithValueWhitespaces") << "PROP( int foo = 1 )" << "int" << "foo" << "1" << ASTProperty::ReadPush << false;
+ QTest::newRow("readonlyWithValueWhitespaces") << "PROP( int foo = 1 READONLY )" << "int" << "foo" << "1" << ASTProperty::ReadOnly << false;
+ QTest::newRow("constantWithValueWhitespaces") << "PROP( int foo = 1 CONSTANT )" << "int" << "foo" << "1" << ASTProperty::Constant << false;
+ QTest::newRow("templatetype") << "PROP(QList<int> bar)" << "QList<int>" << "bar" << QString() << ASTProperty::ReadPush << false;
+ QTest::newRow("nested templatetype") << "PROP(QMap<int, QList<int>> bar)" << "QMap<int, QList<int>>" << "bar" << QString() << ASTProperty::ReadPush << false;
+ QTest::newRow("non-int default value") << "PROP(double foo=1.1 CONSTANT)" << "double" << "foo" << "1.1" << ASTProperty::Constant << false;
+ QTest::newRow("tab") << "PROP(double\tfoo)" << "double" << "foo" << "" << ASTProperty::ReadPush << false;
+ QTest::newRow("two tabs") << "PROP(double\t\tfoo)" << "double" << "foo" << "" << ASTProperty::ReadPush << false;
+ QTest::newRow("stringWithValue") << "PROP(QString foo=\"Hello World\")" << "QString" << "foo"
+ << QString("\"Hello World\"") << ASTProperty::ReadPush << false;
+ QTest::newRow("stringWithValueWhitespaces") << "PROP(QString foo = \"Hello World\")"
+ << "QString" << "foo" << QString("\"Hello World\"")
+ << ASTProperty::ReadPush << false;
+ QTest::newRow("readonlyStringWithValueWhitespaces") << "PROP(QString foo = \"Hello World\" READONLY )"
+ << "QString" << "foo" << "\"Hello World\""
+ << ASTProperty::ReadOnly << false;
+ QTest::newRow("readonlyStringWithValue") << "PROP(QString foo=\"Hello World\" READONLY)"
+ << "QString" << "foo" << "\"Hello World\""
+ << ASTProperty::ReadOnly << false;
+}
+
+void tst_Parser::testProperties()
+{
+ QFETCH(QString, propertyDeclaration);
+ QFETCH(QString, expectedType);
+ QFETCH(QString, expectedName);
+ QFETCH(QString, expectedDefaultValue);
+ QFETCH(ASTProperty::Modifier, expectedModifier);
+ QFETCH(bool, expectedPersistence);
+
+ QTemporaryFile file;
+ file.open();
+ QTextStream stream(&file);
+ stream << "class TestClass" << Qt::endl;
+ stream << "{" << Qt::endl;
+ stream << propertyDeclaration << Qt::endl;
+ stream << "};" << Qt::endl;
+ file.seek(0);
+
+ RepParser parser(file);
+ QVERIFY(parser.parse());
+
+ const AST ast = parser.ast();
+ QCOMPARE(ast.classes.count(), 1);
+
+ const ASTClass astClass = ast.classes.first();
+ const QList<ASTProperty> properties = astClass.properties;
+ QCOMPARE(properties.count(), 1);
+
+ const ASTProperty property = properties.first();
+ QCOMPARE(property.type, expectedType);
+ QCOMPARE(property.name, expectedName);
+ QCOMPARE(property.defaultValue, expectedDefaultValue);
+ QCOMPARE(property.modifier, expectedModifier);
+ QCOMPARE(property.persisted, expectedPersistence);
+}
+
+void tst_Parser::testSlots_data()
+{
+ QTest::addColumn<QString>("slotDeclaration");
+ QTest::addColumn<QString>("expectedSlot");
+ QTest::addColumn<bool>("voidWarning");
+ QTest::newRow("slotwithoutspacebeforeparentheses") << "SLOT(test())" << "void test()" << true;
+ QTest::newRow("slotwithspacebeforeparentheses") << "SLOT (test())" << "void test()" << true;
+ QTest::newRow("slotwitharguments") << "SLOT(void test(QString value, int number))" << "void test(QString value, int number)" << false;
+ QTest::newRow("slotwithunnamedarguments") << "SLOT(void test(QString, int))" << "void test(QString __repc_variable_1, int __repc_variable_2)" << false;
+ QTest::newRow("slotwithspaces") << "SLOT( void test (QString value, int number) )" << "void test(QString value, int number)" << false;
+ QTest::newRow("slotwithtemplates") << "SLOT(test(QMap<QString,int> foo))" << "void test(QMap<QString,int> foo)" << true;
+ QTest::newRow("slotwithmultitemplates") << "SLOT(test(QMap<QString,int> foo, QMap<QString,int> bla))" << "void test(QMap<QString,int> foo, QMap<QString,int> bla)" << true;
+ QTest::newRow("slotwithtemplatetemplates") << "SLOT(test(QMap<QList<QString>,int> foo))" << "void test(QMap<QList<QString>,int> foo)" << true;
+ QTest::newRow("slotwithtemplateswithspace") << "SLOT ( test (QMap<QString , int> foo ) )" << "void test(QMap<QString , int> foo)" << true;
+ QTest::newRow("slotWithConstRefArgument") << "SLOT (test(const QString &val))" << "void test(const QString & val)" << true;
+ QTest::newRow("slotWithRefArgument") << "SLOT (test(QString &val))" << "void test(QString & val)" << true;
+ QTest::newRow("slotwithtemplatetemplatesAndConstRef") << "SLOT(test(const QMap<QList<QString>,int> &foo))" << "void test(const QMap<QList<QString>,int> & foo)" << true;
+ QTest::newRow("slotWithConstRefArgumentAndWithout") << "SLOT (test(const QString &val, int value))" << "void test(const QString & val, int value)" << true;
+}
+
+void tst_Parser::testSlots()
+{
+ QFETCH(QString, slotDeclaration);
+ QFETCH(QString, expectedSlot);
+ QFETCH(bool, voidWarning);
+
+ QTemporaryFile file;
+ file.open();
+ QTextStream stream(&file);
+ stream << "class TestClass" << Qt::endl;
+ stream << "{" << Qt::endl;
+ stream << slotDeclaration << Qt::endl;
+ stream << "};" << Qt::endl;
+ file.seek(0);
+
+ if (voidWarning)
+ QTest::ignoreMessage(QtWarningMsg, "[repc] - Adding 'void' for unspecified return type on test");
+ RepParser parser(file);
+ QVERIFY(parser.parse());
+
+ const AST ast = parser.ast();
+ QCOMPARE(ast.classes.count(), 1);
+
+ const ASTClass astClass = ast.classes.first();
+ const QList<ASTFunction> slotsList = astClass.slotsList;
+ QCOMPARE(slotsList.count(), 1);
+ ASTFunction slot = slotsList.first();
+ QCOMPARE(QString("%1 %2(%3)").arg(slot.returnType).arg(slot.name).arg(slot.paramsAsString()), expectedSlot);
+}
+
+void tst_Parser::testSignals_data()
+{
+ QTest::addColumn<QString>("signalDeclaration");
+ QTest::addColumn<QString>("expectedSignal");
+ QTest::newRow("signalwithoutspacebeforeparentheses") << "SIGNAL(test())" << "test()";
+ QTest::newRow("signalwithspacebeforeparentheses") << "SIGNAL (test())" << "test()";
+ QTest::newRow("signalwitharguments") << "SIGNAL(test(QString value, int value))" << "test(QString value, int value)";
+ QTest::newRow("signalwithtemplates") << "SIGNAL(test(QMap<QString,int> foo))" << "test(QMap<QString,int> foo)";
+ QTest::newRow("signalwithtemplateswithspace") << "SIGNAL ( test (QMap<QString , int> foo ) )" << "test(QMap<QString , int> foo)";
+ QTest::newRow("signalWithConstRefArgument") << "SIGNAL (test(const QString &val))" << "test(const QString & val)";
+ QTest::newRow("signalWithRefArgument") << "SIGNAL (test(QString &val))" << "test(QString & val)";
+}
+
+void tst_Parser::testSignals()
+{
+ QFETCH(QString, signalDeclaration);
+ QFETCH(QString, expectedSignal);
+
+ QTemporaryFile file;
+ file.open();
+ QTextStream stream(&file);
+ stream << "class TestClass" << Qt::endl;
+ stream << "{" << Qt::endl;
+ stream << signalDeclaration << Qt::endl;
+ stream << "};" << Qt::endl;
+ file.seek(0);
+
+ RepParser parser(file);
+ QVERIFY(parser.parse());
+
+ const AST ast = parser.ast();
+ QCOMPARE(ast.classes.count(), 1);
+
+ const ASTClass astClass = ast.classes.first();
+ const QList<ASTFunction> signalsList = astClass.signalsList;
+ ASTFunction signal = signalsList.first();
+ QCOMPARE(QString("%1(%2)").arg(signal.name).arg(signal.paramsAsString()), expectedSignal);
+}
+
+void tst_Parser::testPods_data()
+{
+ QTest::addColumn<QString>("podsdeclaration");
+ QTest::addColumn<QString>("expectedtypes");
+ QTest::addColumn<QString>("expectedvariables");
+
+ //Variable/Type separate by ";"
+ QTest::newRow("one pod") << "POD preset(int presetNumber)" << "int" << "presetNumber";
+ QTest::newRow("two pod") << "POD preset(int presetNumber, double foo)" << "int;double" << "presetNumber;foo";
+ QTest::newRow("two pod with space") << "POD preset ( int presetNumber , double foo ) " << "int;double" << "presetNumber;foo";
+ QTest::newRow("two pod multiline") << "POD preset(\nint presetNumber,\ndouble foo\n)" << "int;double" << "presetNumber;foo";
+ //Template
+ QTest::newRow("pod template") << "POD preset(QMap<QString,int> foo) " << "QMap<QString,int>" << "foo";
+ QTest::newRow("pod template (QList)") << "POD preset(QList<QString> foo) " << "QList<QString>" << "foo";
+ QTest::newRow("two pod template") << "POD preset(QMap<QString,int> foo, QMap<double,int> bla) " << "QMap<QString,int>;QMap<double,int>" << "foo;bla";
+ QTest::newRow("two pod template with space") << "POD preset( QMap<QString , int > foo , QMap< double , int > bla ) " << "QMap<QString , int >;QMap< double , int >" << "foo;bla";
+
+}
+
+void tst_Parser::testPods()
+{
+ QFETCH(QString, podsdeclaration);
+ QFETCH(QString, expectedtypes);
+ QFETCH(QString, expectedvariables);
+
+ QTemporaryFile file;
+ file.open();
+ QTextStream stream(&file);
+ stream << podsdeclaration << Qt::endl;
+ stream << "class TestClass" << Qt::endl;
+ stream << "{" << Qt::endl;
+ stream << "};" << Qt::endl;
+ file.seek(0);
+
+ RepParser parser(file);
+ QVERIFY(parser.parse());
+
+ const AST ast = parser.ast();
+ QCOMPARE(ast.classes.count(), 1);
+
+ QCOMPARE(ast.pods.count(), 1);
+ const POD pods = ast.pods.first();
+ const QList<PODAttribute> podsList = pods.attributes;
+ const QStringList typeList = expectedtypes.split(QLatin1Char(';'));
+ const QStringList variableList = expectedvariables.split(QLatin1Char(';'));
+ QVERIFY(typeList.count() == variableList.count());
+ QVERIFY(podsList.count() == variableList.count());
+ for (int i=0; i < podsList.count(); ++i) {
+ QCOMPARE(podsList.at(i).name, variableList.at(i));
+ QCOMPARE(podsList.at(i).type, typeList.at(i));
+ }
+}
+
+void tst_Parser::testPods2_data()
+{
+ QTest::addColumn<QString>("podsdeclaration");
+ QTest::addColumn<QString>("expectedtypes");
+ QTest::addColumn<QString>("expectedvariables");
+
+ //Variable/Type separate by ";"
+ QTest::newRow("one pod") << "POD preset{int presetNumber}" << "int" << "presetNumber";
+ QTest::newRow("two pod") << "POD preset{int presetNumber, double foo}" << "int;double" << "presetNumber;foo";
+ QTest::newRow("two pod with space") << "POD preset { int presetNumber , double foo } " << "int;double" << "presetNumber;foo";
+ QTest::newRow("two pod multiline") << "POD preset{\nint presetNumber,\ndouble foo\n}" << "int;double" << "presetNumber;foo";
+ //Template
+ QTest::newRow("pod template") << "POD preset{QMap<QString,int> foo} " << "QMap<QString,int>" << "foo";
+ QTest::newRow("pod template (QList)") << "POD preset{QList<QString> foo} " << "QList<QString>" << "foo";
+ QTest::newRow("two pod template") << "POD preset{QMap<QString,int> foo, QMap<double,int> bla} " << "QMap<QString,int>;QMap<double,int>" << "foo;bla";
+ QTest::newRow("two pod template with space") << "POD preset{ QMap<QString , int > foo , QMap< double , int > bla } " << "QMap<QString,int>;QMap<double,int>" << "foo;bla";
+ //Enum
+ QTest::newRow("enum multiline") << "POD preset{ENUM val {val1 = 1,\nval2,\nval3=12}\nval value,\ndouble foo\n}" << "val;double" << "value;foo";
+
+}
+
+void tst_Parser::testPods2()
+{
+ QFETCH(QString, podsdeclaration);
+ QFETCH(QString, expectedtypes);
+ QFETCH(QString, expectedvariables);
+
+ QTemporaryFile file;
+ file.open();
+ QTextStream stream(&file);
+ stream << podsdeclaration << Qt::endl;
+ stream << "class TestClass" << Qt::endl;
+ stream << "{" << Qt::endl;
+ stream << "};" << Qt::endl;
+ file.seek(0);
+
+ RepParser parser(file);
+ QVERIFY(parser.parse());
+
+ const AST ast = parser.ast();
+ QCOMPARE(ast.classes.count(), 1);
+
+ QCOMPARE(ast.pods.count(), 1);
+ const POD pods = ast.pods.first();
+ const QVector<PODAttribute> podsList = pods.attributes;
+ const QStringList typeList = expectedtypes.split(QLatin1Char(';'));
+ const QStringList variableList = expectedvariables.split(QLatin1Char(';'));
+ QVERIFY(typeList.count() == variableList.count());
+ QVERIFY(podsList.count() == variableList.count());
+ for (int i=0; i < podsList.count(); ++i) {
+ QCOMPARE(podsList.at(i).name, variableList.at(i));
+ QCOMPARE(podsList.at(i).type, typeList.at(i));
+ }
+}
+
+void tst_Parser::testEnums_data()
+{
+ QTest::addColumn<QString>("enumdeclaration");
+ QTest::addColumn<QString>("expectednames");
+ QTest::addColumn<QList<int> >("expectedvalues");
+ QTest::addColumn<int>("expectedmax");
+ QTest::addColumn<bool>("expectedsigned");
+ QTest::addColumn<bool>("inclass");
+
+ for (int i = 0; i <= 1; ++i) {
+ bool inclass = i == 1;
+ QString identifier = inclass ? QLatin1String("%1 in class") : QLatin1String("%1 outside class");
+ //Separate by ";"
+ QTest::newRow(identifier.arg("one enum val").toLatin1()) << "ENUM preset {presetNumber}" << "presetNumber" << (QList<int>() << 0) << 0 << false << inclass;
+ QTest::newRow(identifier.arg("two enum val").toLatin1()) << "ENUM preset {presetNumber, foo}" << "presetNumber;foo" << (QList<int>() << 0 << 1) << 1 << false << inclass;
+ QTest::newRow(identifier.arg("two enum val -1 2nd").toLatin1()) << "ENUM preset {presetNumber, foo = -1}" << "presetNumber;foo" << (QList<int>() << 0 << -1) << 1 << true << inclass;
+ QTest::newRow(identifier.arg("two enum val -1 1st").toLatin1()) << "ENUM preset {presetNumber=-1, foo}" << "presetNumber;foo" << (QList<int>() << -1 << 0) << 1 << true << inclass;
+ QTest::newRow(identifier.arg("two enum val hex").toLatin1()) << "ENUM preset {presetNumber=0xf, foo}" << "presetNumber;foo" << (QList<int>() << 15 << 16) << 16 << false << inclass;
+ QTest::newRow(identifier.arg("two enum val hex").toLatin1()) << "ENUM preset {presetNumber=0xff, foo}" << "presetNumber;foo" << (QList<int>() << 255 << 256) << 256 << false << inclass;
+ QTest::newRow(identifier.arg("two enum val with space").toLatin1()) << "ENUM preset { presetNumber , foo } " << "presetNumber;foo" << (QList<int>() << 0 << 1) << 1 << false << inclass;
+ QTest::newRow(identifier.arg("set values").toLatin1()) << "ENUM preset { val1=1 , val3=3, val5=5 } " << "val1;val3;val5" << (QList<int>() << 1 << 3 << 5) << 5 << false << inclass;
+ QTest::newRow(identifier.arg("multiline").toLatin1()) << "ENUM preset {\nval1,\nval2,\nval3\n} " << "val1;val2;val3" << (QList<int>() << 0 << 1 << 2) << 2 << false << inclass;
+ QTest::newRow(identifier.arg("multiline indented").toLatin1()) << " ENUM preset {\n val1,\n val2,\n val3\n } " << "val1;val2;val3" << (QList<int>() << 0 << 1 << 2) << 2 << false << inclass;
+ }
+}
+
+void tst_Parser::testEnums()
+{
+ QFETCH(QString, enumdeclaration);
+ QFETCH(QString, expectednames);
+ QFETCH(QList<int>, expectedvalues);
+ QFETCH(int, expectedmax);
+ QFETCH(bool, expectedsigned);
+ QFETCH(bool, inclass);
+
+ QTemporaryFile file;
+ file.open();
+ QTextStream stream(&file);
+ if (!inclass)
+ stream << enumdeclaration << Qt::endl;
+ stream << "class TestClass" << Qt::endl;
+ stream << "{" << Qt::endl;
+ if (inclass)
+ stream << enumdeclaration << Qt::endl;
+ stream << "};" << Qt::endl;
+ file.seek(0);
+
+ RepParser parser(file);
+ QVERIFY(parser.parse());
+
+ const AST ast = parser.ast();
+ QCOMPARE(ast.classes.count(), 1);
+ ASTEnum enums;
+ if (inclass) {
+ const ASTClass astClass = ast.classes.first();
+ QCOMPARE(astClass.enums.count(), 1);
+ enums = astClass.enums.first();
+ } else {
+ QCOMPARE(ast.enums.count(), 1);
+ enums = ast.enums.first();
+ }
+ QVERIFY(enums.isScoped == false);
+ QVERIFY(enums.type.isEmpty());
+ const QList<ASTEnumParam> paramList = enums.params;
+ const QStringList nameList = expectednames.split(QLatin1Char(';'));
+ QVERIFY(nameList.count() == expectedvalues.count());
+ QVERIFY(paramList.count() == expectedvalues.count());
+ for (int i=0; i < paramList.count(); ++i) {
+ QCOMPARE(paramList.at(i).name, nameList.at(i));
+ QCOMPARE(paramList.at(i).value, expectedvalues.at(i));
+ }
+ QCOMPARE(enums.max, expectedmax);
+ QCOMPARE(enums.isSigned, expectedsigned);
+}
+
+void tst_Parser::testTypedEnums_data()
+{
+ QTest::addColumn<QString>("enumdeclaration");
+ QTest::addColumn<QString>("expectedtype");
+ QTest::addColumn<bool>("inclass");
+ QTest::addColumn<bool>("isscoped");
+ QTest::addColumn<bool>("isflag");
+
+ for (int i = 0; i <= 7; ++i) {
+ bool inclass = i % 2 == 1;
+ bool isscoped = i % 4 > 1;
+ bool isflag = i > 3;
+ QString identifier = inclass ? QLatin1String("%1 %2 %3 in class") : QLatin1String("%1 %2 %3 outside class");
+ QString scopeString = isscoped ? QLatin1String("Scoped") : QLatin1String("Non-scoped");
+ QString flagString = isflag ? QLatin1String("Flag") : QLatin1String("Enum");
+ QTest::newRow(identifier.arg(scopeString, flagString, "no type").toLatin1()) << "preset {presetNumber}" << QString() << inclass << isscoped << isflag;
+ QTest::newRow(identifier.arg(scopeString, flagString, "quint16").toLatin1()) << "preset : quint16 {presetNumber}" << "quint16" << inclass << isscoped << isflag;
+ QTest::newRow(identifier.arg(scopeString, flagString, "qint64").toLatin1()) << "preset : qint64 {presetNumber}" << "qint64" << inclass << isscoped << isflag;
+ QTest::newRow(identifier.arg(scopeString, flagString, "unsigned char").toLatin1()) << "preset: unsigned char {presetNumber}" << "unsigned char" << inclass << isscoped << isflag;
+ }
+}
+
+void tst_Parser::testTypedEnums()
+{
+ QFETCH(QString, enumdeclaration);
+ QFETCH(QString, expectedtype);
+ QFETCH(bool, inclass);
+ QFETCH(bool, isscoped);
+ QFETCH(bool, isflag);
+
+ QTemporaryFile file;
+ file.open();
+ QTextStream stream(&file);
+ if (!inclass) {
+ stream << "ENUM " << (isscoped ? "class " : "") << enumdeclaration << Qt::endl;
+ if (isflag)
+ stream << "FLAG(MyFlags preset)" << Qt::endl;
+ }
+ stream << "class TestClass" << Qt::endl;
+ stream << "{" << Qt::endl;
+ if (inclass) {
+ stream << "ENUM " << (isscoped ? "class " : "") << enumdeclaration << Qt::endl;
+ if (isflag)
+ stream << "FLAG(MyFlags preset)" << Qt::endl;
+ }
+ stream << "};" << Qt::endl;
+ file.seek(0);
+
+ RepParser parser(file);
+ QVERIFY(parser.parse());
+
+ const AST ast = parser.ast();
+ QCOMPARE(ast.classes.count(), 1);
+ ASTEnum enums;
+ ASTFlag flags;
+ if (inclass) {
+ const ASTClass astClass = ast.classes.first();
+ QCOMPARE(astClass.enums.count(), 1);
+ enums = astClass.enums.first();
+ if (isflag)
+ flags = astClass.flags.first();
+ } else {
+ QCOMPARE(ast.enums.count(), 1);
+ enums = ast.enums.first();
+ if (isflag)
+ flags = ast.flags.first();
+ }
+ QVERIFY(enums.isScoped == isscoped);
+ QVERIFY(enums.flagIndex == (isflag ? 0 : -1));
+ QVERIFY(flags.name == (isflag ? "MyFlags" : QString{}));
+ QVERIFY(flags._enum == (isflag ? "preset" : QString{}));
+ QCOMPARE(enums.type, expectedtype);
+ const QList<ASTEnumParam> paramList = enums.params;
+ QVERIFY(paramList.count() == 1);
+ for (int i=0; i < paramList.count(); ++i) {
+ QCOMPARE(paramList.at(i).name, "presetNumber");
+ QCOMPARE(paramList.at(i).value, 0);
+ }
+ QCOMPARE(enums.max, 0);
+ QCOMPARE(enums.isSigned, false);
+}
+
+void tst_Parser::testModels_data()
+{
+ QTest::addColumn<QString>("modelDeclaration");
+ QTest::addColumn<QString>("expectedModel");
+ QTest::addColumn<QList<ASTModelRole>>("expectedRoles");
+ QTest::newRow("basicmodel") << "MODEL test(display)" << "test" << QList<ASTModelRole>({{"display"}});
+ QTest::newRow("basicmodelsemicolon") << "MODEL test(display);" << "test" << QList<ASTModelRole>({{"display"}});
+}
+
+void tst_Parser::testModels()
+{
+ QFETCH(QString, modelDeclaration);
+ QFETCH(QString, expectedModel);
+ QFETCH(QList<ASTModelRole>, expectedRoles);
+
+ QTemporaryFile file;
+ file.open();
+ QTextStream stream(&file);
+ stream << "class TestClass" << Qt::endl;
+ stream << "{" << Qt::endl;
+ stream << modelDeclaration << Qt::endl;
+ stream << "};" << Qt::endl;
+ file.seek(0);
+
+ RepParser parser(file);
+ QVERIFY(parser.parse());
+
+ const AST ast = parser.ast();
+ QCOMPARE(ast.classes.count(), 1);
+
+ const ASTClass astClass = ast.classes.first();
+ ASTModel model = astClass.modelMetadata.first();
+ ASTProperty property = astClass.properties.at(model.propertyIndex);
+ QCOMPARE(property.name, expectedModel);
+ int i = 0;
+ for (auto role : model.roles) {
+ QCOMPARE(role.name, expectedRoles.at(i).name);
+ i++;
+ }
+}
+
+void tst_Parser::testClasses_data()
+{
+ QTest::addColumn<QString>("classDeclaration");
+ QTest::addColumn<QString>("expectedType");
+ QTest::addColumn<QString>("expectedName");
+ QTest::newRow("basicclass") << "CLASS sub(subObject)" << "subObject" << "sub";
+}
+
+void tst_Parser::testClasses()
+{
+ QFETCH(QString, classDeclaration);
+ QFETCH(QString, expectedType);
+ QFETCH(QString, expectedName);
+
+ QTemporaryFile file;
+ file.open();
+ QTextStream stream(&file);
+ stream << "class subObject" << Qt::endl;
+ stream << "{" << Qt::endl;
+ stream << " PROP(int value)" << Qt::endl;
+ stream << "};" << Qt::endl;
+ stream << "class parentObject" << Qt::endl;
+ stream << "{" << Qt::endl;
+ stream << classDeclaration << Qt::endl;
+ stream << "};" << Qt::endl;
+ file.seek(0);
+
+ RepParser parser(file);
+ QVERIFY(parser.parse());
+
+ const AST ast = parser.ast();
+ QCOMPARE(ast.classes.count(), 2);
+
+ const ASTClass astSub = ast.classes.value(0);
+ const ASTClass astObj = ast.classes.value(1);
+ const ASTProperty property = astObj.properties.at(astObj.subClassPropertyIndices.at(0));
+ QCOMPARE(property.name, expectedName);
+ QCOMPARE(property.type, expectedType);
+}
+
+void tst_Parser::testInvalid_data()
+{
+ QTest::addColumn<QString>("content");
+ QTest::addColumn<QString>("warning");
+
+ QTest::newRow("pod_invalid") << "POD (int foo)" << ".?Unknown token encountered";
+ QTest::newRow("pod_unbalancedparens") << "POD foo(int foo" << ".?Unknown token encountered";
+ QTest::newRow("pod_inclass") << "class Foo\n{\nPOD foo(int)\n}" << ".?POD: Can only be used in global scope";
+ QTest::newRow("class_noidentifier") << "class\n{\n}" << ".?Unknown token encountered";
+ QTest::newRow("class_nested") << "class Foo\n{\nclass Bar\n}" << ".?class: Cannot be nested";
+ QTest::newRow("prop_outsideclass") << "PROP(int foo)" << ".?PROP: Can only be used in class scope";
+ QTest::newRow("prop_toomanyargs") << "class Foo\n{\nPROP(int int foo)\n}" << ".?Invalid property declaration: flag foo is unknown";
+ QTest::newRow("prop_toomanymodifiers") << "class Foo\n{\nPROP(int foo READWRITE, READONLY)\n}" << ".?Invalid property declaration: combination not allowed .READWRITE, READONLY.";
+ QTest::newRow("prop_noargs") << "class Foo\n{\nPROP()\n}" << ".?Unknown token encountered";
+ QTest::newRow("prop_unbalancedparens") << "class Foo\n{\nPROP(int foo\n}" << ".?Unknown token encountered";
+ QTest::newRow("signal_outsideclass") << "SIGNAL(foo())" << ".?SIGNAL: Can only be used in class scope";
+ QTest::newRow("signal_noargs") << "class Foo\n{\nSIGNAL()\n}" << ".?Unknown token encountered";
+ QTest::newRow("slot_outsideclass") << "SLOT(void foo())" << ".?SLOT: Can only be used in class scope";
+ QTest::newRow("slot_noargs") << "class Foo\n{\nSLOT()\n}" << ".?Unknown token encountered";
+ QTest::newRow("model_outsideclass") << "MODEL foo" << ".?Unknown token encountered";
+ QTest::newRow("class_outsideclass") << "CLASS foo" << ".?Unknown token encountered";
+ QTest::newRow("preprecessor_line_inclass") << "class Foo\n{\n#define foo\n}" << ".?Unknown token encountered";
+}
+
+void tst_Parser::testInvalid()
+{
+ QFETCH(QString, content);
+ QFETCH(QString, warning);
+
+ QTest::ignoreMessage(QtWarningMsg, QRegularExpression(warning));
+ QTemporaryFile file;
+ file.open();
+ QTextStream stream(&file);
+ stream << content << Qt::endl;
+ file.seek(0);
+
+ RepParser parser(file);
+ QVERIFY(!parser.parse());
+}
+
+QTEST_APPLESS_MAIN(tst_Parser)
+
+#include "tst_parser.moc"
--- /dev/null
+
+add_subdirectory(client)
+add_subdirectory(server)
+add_subdirectory(tst)
--- /dev/null
+
+#####################################################################
+## restart_client Binary:
+#####################################################################
+
+qt_internal_add_executable(restart_client
+ OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
+ SOURCES
+ main.cpp
+ INCLUDE_DIRECTORIES
+ ${CMAKE_CURRENT_SOURCE_DIR}
+ PUBLIC_LIBRARIES
+ Qt::RemoteObjects
+ Qt::Test
+)
+qt6_add_repc_replicas(restart_client
+ ../subclass.rep
+)
+
+#### Keys ignored in scope 1:.:.:client.pro:<TRUE>:
+# TEMPLATE = "app"
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2019 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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 with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "rep_subclass_replica.h"
+
+#include <QCoreApplication>
+#include <QtRemoteObjects/qremoteobjectnode.h>
+#include <QtTest/QtTest>
+
+class tst_Client_Process : public QObject
+{
+ Q_OBJECT
+
+private Q_SLOTS:
+ void initTestCase()
+ {
+ QLoggingCategory::setFilterRules("qt.remoteobjects.warning=true");
+ m_repNode.reset(new QRemoteObjectNode);
+ m_repNode->connectToNode(QUrl(QStringLiteral("tcp://127.0.0.1:65217")));
+ m_rep.reset(m_repNode->acquire<ParentClassReplica>());
+ connect(m_rep.data(), &QRemoteObjectReplica::stateChanged, [this](QRemoteObjectReplica::State state, QRemoteObjectReplica::State previousState) {
+ qDebug() << "**** stateChanged" << state << previousState;
+ if (state == QRemoteObjectReplica::Suspect) {
+ qWarning() << "Replica suspect";
+ this->serverRestarted = true;
+ } else if (state == QRemoteObjectReplica::Valid) {
+ if (this->serverRestarted) {
+ qWarning() << "Replica valid again";
+ auto reply = m_rep->start();
+ }
+ }
+ });
+ QVERIFY(m_rep->waitForSource());
+ }
+
+ void testRun()
+ {
+ const auto objectMode = qEnvironmentVariable("ObjectMode");
+
+ qWarning() << "From client";
+ const MyPOD initialValue(42, 3.14f, QStringLiteral("SubClass"));
+ if (objectMode == QLatin1String("ObjectPointer")) {
+ QSignalSpy tracksSpy(m_rep->tracks(), &QAbstractItemModelReplica::initialized);
+ QVERIFY(m_rep->subClass() != nullptr);
+ QCOMPARE(m_rep->subClass()->myPOD(), initialValue);
+ QVERIFY(m_rep->tracks() != nullptr);
+ QVERIFY(tracksSpy.count() || tracksSpy.wait());
+ } else {
+ QVERIFY(m_rep->subClass() == nullptr);
+ QVERIFY(m_rep->tracks() == nullptr);
+ }
+ auto reply = m_rep->start();
+ QVERIFY(reply.waitForFinished());
+
+ QSignalSpy advanceSpy(m_rep.data(), SIGNAL(advance()));
+ QVERIFY(advanceSpy.wait());
+ if (objectMode == QLatin1String("ObjectPointer")) {
+ QVERIFY(m_rep->subClass() != nullptr);
+ QCOMPARE(m_rep->subClass()->myPOD(), initialValue);
+ QVERIFY(m_rep->tracks() != nullptr);
+ } else {
+ QVERIFY(m_rep->subClass() == nullptr);
+ QVERIFY(m_rep->tracks() == nullptr);
+ }
+ }
+
+ void cleanupTestCase()
+ {
+ auto reply = m_rep->quit();
+ QVERIFY(reply.waitForFinished());
+ }
+
+private:
+ QScopedPointer<QRemoteObjectNode> m_repNode;
+ QScopedPointer<ParentClassReplica> m_rep;
+ bool serverRestarted = false;
+};
+
+QTEST_MAIN(tst_Client_Process)
+
+#include "main.moc"
--- /dev/null
+
+#####################################################################
+## restart_server Binary:
+#####################################################################
+
+qt_internal_add_executable(restart_server
+ OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
+ SOURCES
+ main.cpp
+ mytestserver.cpp mytestserver.h
+ INCLUDE_DIRECTORIES
+ ${CMAKE_CURRENT_SOURCE_DIR}
+ PUBLIC_LIBRARIES
+ Qt::RemoteObjects
+ Qt::Test
+)
+qt6_add_repc_sources(restart_server
+ ../subclass.rep
+)
+
+#### Keys ignored in scope 1:.:.:server.pro:<TRUE>:
+# TEMPLATE = "app"
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2019 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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 with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "mytestserver.h"
+#include "rep_subclass_source.h"
+
+#include <QCoreApplication>
+#include <QtTest/QtTest>
+
+class tst_Server_Process : public QObject
+{
+ Q_OBJECT
+
+private Q_SLOTS:
+ void testRun()
+ {
+ const auto runMode = qEnvironmentVariable("RunMode");
+ const auto objectMode = qEnvironmentVariable("ObjectMode");
+
+ QRemoteObjectHost srcNode(QUrl(QStringLiteral("tcp://127.0.0.1:65217")));
+ MyTestServer myTestServer;
+ SubClassSimpleSource subclass;
+ QStringListModel model;
+ const MyPOD initialValue(42, 3.14f, QStringLiteral("SubClass"));
+ if (objectMode == QLatin1String("ObjectPointer")) {
+ subclass.setMyPOD(initialValue);
+ model.setStringList(QStringList() << "Track1" << "Track2" << "Track3");
+ myTestServer.setSubClass(&subclass);
+ myTestServer.setTracks(&model);
+ }
+ srcNode.enableRemoting(&myTestServer);
+
+ qDebug() << "Waiting for incoming connections";
+
+ QSignalSpy waitForStartedSpy(&myTestServer, &MyTestServer::startedChanged);
+ QVERIFY(waitForStartedSpy.isValid());
+ QVERIFY(waitForStartedSpy.wait());
+ QCOMPARE(waitForStartedSpy.value(0).value(0).toBool(), true);
+
+ // wait for delivery of events
+ QTest::qWait(200);
+
+ qDebug() << "Client connected";
+ if (runMode != QLatin1String("Baseline")) {
+ qDebug() << "Server quitting" << runMode;
+ if (runMode == QLatin1String("ServerRestartFatal"))
+ qFatal("Fatal");
+ QCoreApplication::exit();
+ return;
+ }
+ emit myTestServer.advance();
+
+ // wait for quit
+ bool quit = false;
+ connect(&myTestServer, &MyTestServer::quitApp, [&quit]{quit = true;});
+ QTRY_VERIFY_WITH_TIMEOUT(quit, 5000);
+
+ // wait for delivery of events
+ QTest::qWait(200);
+
+ qDebug() << "Done. Shutting down.";
+ }
+};
+
+QTEST_MAIN(tst_Server_Process)
+
+#include "main.moc"
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2019 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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 with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <qdebug.h>
+
+#include "mytestserver.h"
+#include "rep_subclass_source.h"
+
+MyTestServer::MyTestServer(QObject *parent)
+ : ParentClassSimpleSource(parent)
+{
+ qDebug() << "Server started";
+}
+
+MyTestServer::~MyTestServer()
+{
+ qDebug() << "Server stopped";
+}
+
+bool MyTestServer::start()
+{
+ setStarted(true);
+ return true;
+}
+
+bool MyTestServer::quit()
+{
+ emit quitApp();
+ return true;
+}
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2019 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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 with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef MYTESTSERVER_H
+#define MYTESTSERVER_H
+
+#include <QTimer>
+
+#include <QtRemoteObjects/qremoteobjectnode.h>
+#include <QtRemoteObjects/qremoteobjectsource.h>
+
+#include "rep_subclass_source.h"
+
+class MyTestServer : public ParentClassSimpleSource
+{
+ Q_OBJECT
+
+public:
+ MyTestServer(QObject *parent = nullptr);
+ ~MyTestServer() override;
+
+public Q_SLOTS:
+ bool start() override;
+ bool quit() override;
+
+Q_SIGNALS:
+ void quitApp();
+};
+
+#endif // MYTESTSERVER_H
--- /dev/null
+POD MyPOD(int i, float f, QString s)
+
+class SubClass
+{
+ PROP(MyPOD myPOD)
+}
+
+class ParentClass
+{
+ PROP(bool started = false)
+
+ SLOT(bool start())
+ SLOT(bool quit())
+ SIGNAL(advance())
+
+ CLASS subClass(SubClass)
+ MODEL tracks(display)
+}
+
--- /dev/null
+
+#####################################################################
+## tst_restart Test:
+#####################################################################
+
+qt_internal_add_test(tst_restart
+ OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
+ SOURCES
+ tst_restart.cpp
+ PUBLIC_LIBRARIES
+ Qt::RemoteObjects
+)
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2019 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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 with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtTest/QtTest>
+#include <QMetaType>
+#include <QProcess>
+
+#include "../../../shared/testutils.h"
+
+class tst_Restart: public QObject
+{
+ Q_OBJECT
+
+public:
+ enum RunMode { Baseline, ServerRestartGraceful, ServerRestartFatal };
+ enum ObjectMode { NullPointer, ObjectPointer };
+ Q_ENUM(RunMode)
+ Q_ENUM(ObjectMode)
+
+private slots:
+ void initTestCase()
+ {
+ QVERIFY(TestUtils::init("tst"));
+ QLoggingCategory::setFilterRules("qt.remoteobjects.warning=false");
+ }
+
+ void cleanup()
+ {
+ // wait for delivery of RemoveObject events to the source
+ QTest::qWait(200);
+ }
+
+ void testRun_data()
+ {
+ QTest::addColumn<RunMode>("runMode");
+ QTest::addColumn<ObjectMode>("objectMode");
+ auto runModeMeta = QMetaEnum::fromType<RunMode>();
+ auto objectModeMeta = QMetaEnum::fromType<ObjectMode>();
+ for (int i = 0; i < runModeMeta.keyCount(); i++) {
+ for (int j = 0; j < objectModeMeta.keyCount(); j++) {
+ auto ba = QByteArray(runModeMeta.valueToKey(i));
+ ba = ba.append("_").append(objectModeMeta.valueToKey(j));
+ QTest::newRow(ba.data()) << static_cast<RunMode>(i) << static_cast<ObjectMode>(j);
+ }
+ }
+ }
+
+ void testRun()
+ {
+ QFETCH(RunMode, runMode);
+ QFETCH(ObjectMode, objectMode);
+
+ qDebug() << "Starting server process" << runMode;
+ bool serverRestart = runMode == ServerRestartFatal || runMode == ServerRestartGraceful;
+ QProcess serverProc;
+ serverProc.setProcessChannelMode(QProcess::ForwardedChannels);
+ QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
+ env.insert("RunMode", QVariant::fromValue(runMode).toString());
+ env.insert("ObjectMode", QVariant::fromValue(objectMode).toString());
+ serverProc.setProcessEnvironment(env);
+ serverProc.start(TestUtils::findExecutable("restart_server", "/server"),
+ QStringList());
+ QVERIFY(serverProc.waitForStarted());
+
+ // wait for server start
+ QTest::qWait(200);
+
+ qDebug() << "Starting client process";
+ QProcess clientProc;
+ clientProc.setProcessChannelMode(QProcess::ForwardedChannels);
+ clientProc.setProcessEnvironment(env);
+ clientProc.start(TestUtils::findExecutable("restart_client", "/client"),
+ QStringList());
+ QVERIFY(clientProc.waitForStarted());
+
+ if (serverRestart) {
+ env.insert("RunMode", QVariant::fromValue(Baseline).toString()); // Don't include ServerRestart environment variable this time
+ qDebug() << "Waiting for server exit";
+ QVERIFY(serverProc.waitForFinished());
+ if (runMode == ServerRestartFatal)
+ QVERIFY(serverProc.exitCode() != 0);
+ else
+ QCOMPARE(serverProc.exitCode(), 0);
+ qDebug() << "Restarting server";
+ serverProc.setProcessEnvironment(env);
+ serverProc.start(TestUtils::findExecutable("restart_server", "/server"),
+ QStringList());
+ QVERIFY(serverProc.waitForStarted());
+ }
+
+ QVERIFY(clientProc.waitForFinished());
+ QVERIFY(serverProc.waitForFinished());
+
+ QCOMPARE(serverProc.exitCode(), 0);
+ QCOMPARE(clientProc.exitCode(), 0);
+ }
+};
+
+QTEST_MAIN(tst_Restart)
+
+#include "tst_restart.moc"
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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 with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtTest/QtTest>
+#include <QModelIndex>
+
+// Helper class which can be used by tests for starting a task and
+// waiting for its completion. It takes care of running an event
+// loop while waiting, until finished() method is called (or the
+// timeout is reached).
+class WaitHelper : public QObject
+{
+ Q_OBJECT
+
+public:
+ WaitHelper() { m_promise.start(); }
+
+ ~WaitHelper()
+ {
+ if (m_promise.future().isRunning())
+ m_promise.finish();
+ }
+
+ /*
+ Starts an event loop and waits until finish() method is called
+ or the timeout is reached.
+ */
+ bool wait(int timeout = 30000)
+ {
+ if (m_promise.future().isFinished())
+ return true;
+
+ QFutureWatcher<void> watcher;
+ QSignalSpy watcherSpy(&watcher, &QFutureWatcher<void>::finished);
+ watcher.setFuture(m_promise.future());
+ return watcherSpy.wait(timeout);
+ }
+
+protected:
+ /*
+ The derived classes need to call this method to stop waiting.
+ */
+ void finish() { m_promise.finish(); }
+
+private:
+ QPromise<void> m_promise;
+};
+
+namespace {
+
+inline bool compareIndices(const QModelIndex &lhs, const QModelIndex &rhs)
+{
+ QModelIndex left = lhs;
+ QModelIndex right = rhs;
+ while (left.row() == right.row() && left.column() == right.column() && left.isValid() && right.isValid()) {
+ left = left.parent();
+ right = right.parent();
+ }
+ if (left.isValid() || right.isValid())
+ return false;
+ return true;
+}
+
+struct WaitForDataChanged : public WaitHelper
+{
+ WaitForDataChanged(const QAbstractItemModel *model, const QList<QModelIndex> &pending)
+ : WaitHelper(), m_model(model), m_pending(pending)
+ {
+ connect(m_model, &QAbstractItemModel::dataChanged, this,
+ [this](const QModelIndex &topLeft, const QModelIndex &bottomRight,
+ const QList<int> &roles) {
+ Q_UNUSED(roles)
+
+ checkAndRemoveRange(topLeft, bottomRight);
+ if (m_pending.isEmpty())
+ finish();
+ });
+ }
+
+ void checkAndRemoveRange(const QModelIndex &topLeft, const QModelIndex &bottomRight)
+ {
+ QVERIFY(topLeft.parent() == bottomRight.parent());
+ const auto isInRange = [topLeft, bottomRight] (const QModelIndex &pending) noexcept -> bool {
+ if (pending.isValid() && compareIndices(pending.parent(), topLeft.parent())) {
+ const bool fitLeft = topLeft.column() <= pending.column();
+ const bool fitRight = bottomRight.column() >= pending.column();
+ const bool fitTop = topLeft.row() <= pending.row();
+ const bool fitBottom = bottomRight.row() >= pending.row();
+ if (fitLeft && fitRight && fitTop && fitBottom)
+ return true;
+ }
+ return false;
+ };
+ m_pending.erase(std::remove_if(m_pending.begin(), m_pending.end(), isInRange),
+ m_pending.end());
+ }
+
+private:
+ const QAbstractItemModel *m_model = nullptr;
+ QList<QModelIndex> m_pending;
+};
+
+} // namespace
--- /dev/null
+
+#####################################################################
+## tst_subclassreplicatest Test:
+#####################################################################
+
+qt_internal_add_test(tst_subclassreplicatest
+ SOURCES
+ tst_subclassreplicatest.cpp
+ DEFINES
+ SRCDIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/\\\"
+ PUBLIC_LIBRARIES
+ Qt::RemoteObjects
+)
+qt6_add_repc_merged(tst_subclassreplicatest
+ class.rep
+)
+
+#### Keys ignored in scope 1:.:.:subclassreplica.pro:<TRUE>:
+# TEMPLATE = "app"
--- /dev/null
+class SubClass
+{
+ PROP(int value)
+}
+class ParentClass
+{
+ CLASS sub1(SubClass)
+ CLASS sub2(SubClass)
+}
+
+class OtherParentClass
+{
+ CLASS sub1(SubClass)
+}
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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 with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QString>
+#include <QtTest>
+#include "rep_class_merged.h"
+
+class SubClassReplicaTest : public QObject
+{
+ Q_OBJECT
+
+public:
+ SubClassReplicaTest();
+
+private Q_SLOTS:
+ void basicFunctions();
+ void basicFunctions_data();
+};
+
+SubClassReplicaTest::SubClassReplicaTest()
+{
+}
+
+void SubClassReplicaTest::basicFunctions_data()
+{
+ QTest::addColumn<bool>("templated");
+ QTest::addColumn<bool>("nullobject");
+ QTest::newRow("non-templated pointer") << false << false;
+ QTest::newRow("templated pointer") << true << false;
+ QTest::newRow("non-templated nullptr") << false << true;
+ QTest::newRow("templated nullptr") << true << true;
+}
+
+void SubClassReplicaTest::basicFunctions()
+{
+ QFETCH(bool, templated);
+ QFETCH(bool, nullobject);
+
+ QRemoteObjectRegistryHost host(QUrl("local:test"));
+ SubClassSimpleSource subclass1, subclass2;
+ ParentClassSimpleSource parent;
+ parent.setSub1(&subclass1);
+
+ SubClassSimpleSource subclass3;
+ subclass3.setValue(4);
+ OtherParentClassSimpleSource otherParent;
+ otherParent.setSub1(&subclass3);
+ host.enableRemoting(&otherParent, "OtherParent1");
+
+ SubClassSimpleSource subclass4;
+ subclass4.setValue(15);
+ OtherParentClassSimpleSource otherParent2;
+ otherParent2.setSub1(&subclass4);
+ host.enableRemoting(&otherParent2, "OtherParent2");
+
+ if (nullobject)
+ parent.setSub2(nullptr);
+ else
+ parent.setSub2(&subclass2);
+ if (templated)
+ host.enableRemoting<ParentClassSourceAPI>(&parent);
+ else
+ host.enableRemoting(&parent);
+
+ QRemoteObjectNode client(QUrl("local:test"));
+ const QScopedPointer<ParentClassReplica> replica(client.acquire<ParentClassReplica>());
+ QVERIFY(replica->waitForSource(1000));
+
+ auto sub1 = replica->sub1();
+ QSignalSpy spy(sub1, &SubClassReplica::valueChanged);
+ subclass1.setValue(10);
+ QVERIFY(spy.wait());
+ QCOMPARE(subclass1.value(), sub1->value());
+ if (nullobject) {
+ QCOMPARE(replica->sub2(), nullptr);
+ QCOMPARE(parent.sub2(), nullptr);
+ } else
+ QCOMPARE(subclass2.value(), replica->sub2()->value());
+
+ const QScopedPointer<OtherParentClassReplica> otherReplica(client.acquire<OtherParentClassReplica>("OtherParent1"));
+ QVERIFY(otherReplica->waitForSource(1000));
+
+ const QScopedPointer<OtherParentClassReplica> otherReplica2(client.acquire<OtherParentClassReplica>("OtherParent2"));
+ QVERIFY(otherReplica2->waitForSource(1000));
+
+ QCOMPARE(otherReplica->sub1()->value(), 4);
+ QCOMPARE(otherReplica2->sub1()->value(), 15);
+ otherReplica->sub1()->pushValue(19);
+ otherReplica2->sub1()->pushValue(24);
+ QTRY_COMPARE(subclass4.value(), 24);
+ QTRY_COMPARE(subclass3.value(), 19);
+}
+
+QTEST_MAIN(SubClassReplicaTest)
+
+#include "tst_subclassreplicatest.moc"
--- /dev/null
+<config>
+<modules>
+<module name="QtRemoteObjects" qtname="remoteobjects"/>
+</modules>
+</config>
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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 with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef TESTUTILS_H
+#define TESTUTILS_H
+
+#include <QDebug>
+#include <QString>
+#include <QDir>
+#include <QStandardPaths>
+#include <QCoreApplication>
+
+namespace TestUtils {
+
+QString subFolder;
+QString rootFolder;
+
+bool init(const QString &folder)
+{
+ if (!TestUtils::rootFolder.isEmpty())
+ return true;
+ const auto appPath = QCoreApplication::applicationDirPath();
+ auto dir = QDir(appPath);
+ while (dir.dirName() != folder) {
+ TestUtils::subFolder.prepend(dir.dirName()).prepend('/');
+ if (!dir.cdUp())
+ return false;
+ }
+ dir.cdUp();
+ TestUtils::rootFolder = dir.absolutePath();
+ return true;
+}
+
+QString findExecutable(const QString &executableName, const QString &folder)
+{
+ const auto path = QStandardPaths::findExecutable(executableName, {TestUtils::rootFolder + folder + TestUtils::subFolder});
+ if (!path.isEmpty()) {
+ return path;
+ }
+
+ qWarning() << "Could not find executable:" << executableName << "in " << TestUtils::rootFolder + folder + TestUtils::subFolder;
+ return QString();
+}
+
+}
+
+#endif // TESTUTILS_H
--- /dev/null
+# Generated from tools.pro.
+
+if(QT_FEATURE_commandlineparser)
+ add_subdirectory(repc)
+endif()
--- /dev/null
+# Generated from repc.pro.
+
+#####################################################################
+## repc Tool:
+#####################################################################
+
+qt_get_tool_target_name(target_name repc)
+qt_add_tool(${target_name}
+ TARGET_DESCRIPTION "Qt Remote Objects Compiler"
+ SOURCES
+ cppcodegenerator.cpp cppcodegenerator.h
+ main.cpp
+ repcodegenerator.cpp repcodegenerator.h
+ utils.cpp utils.h
+ DEFINES
+ QT_NO_CAST_FROM_ASCII
+ QT_NO_CAST_FROM_BYTEARRAY
+ QT_NO_CAST_TO_ASCII
+ QT_NO_URL_CAST_FROM_STRING
+ RO_INSTALL_HEADERS=\"$$[QT_INSTALL_HEADERS]/QtRemoteObjects\"
+ INCLUDE_DIRECTORIES
+ ${CMAKE_SOURCE_DIR}/src/repparser
+ PUBLIC_LIBRARIES
+ Qt::CorePrivate
+)
+
+# QLALR Grammars:
+qt_process_qlalr(
+ repc
+ ${CMAKE_SOURCE_DIR}/src/repparser/parser.g
+ ""
+)
+
+#### Keys ignored in scope 1:.:.:repc.pro:<TRUE>:
+# QMAKE_TARGET_DESCRIPTION = "Qt Remote Objects Compiler"
+# _OPTION = "host_build"
+
+## Scopes:
+#####################################################################
+
+qt_extend_target(${target_name} CONDITION MSVC
+ COMPILE_OPTIONS
+ /wd4129
+)
--- /dev/null
+# Generated from repc.pro.
+
+#####################################################################
+## repc Tool:
+#####################################################################
+
+set(REPPARSER_DIR "${PROJECT_SOURCE_DIR}/src/repparser")
+
+qt_get_tool_target_name(target_name repc)
+qt_internal_add_tool(${target_name}
+ TARGET_DESCRIPTION "Qt Remote Objects Compiler"
+ TOOLS_TARGET RemoteObjects # special case
+ INSTALL_DIR "${INSTALL_LIBEXECDIR}"
+ SOURCES
+ cppcodegenerator.cpp cppcodegenerator.h
+ main.cpp
+ repcodegenerator.cpp repcodegenerator.h
+ utils.cpp utils.h
+ DEFINES
+ QT_NO_CAST_FROM_ASCII
+ QT_NO_CAST_FROM_BYTEARRAY
+ QT_NO_CAST_TO_ASCII
+ QT_NO_URL_CAST_FROM_STRING
+ RO_INSTALL_HEADERS=\"$$[QT_INSTALL_HEADERS]/QtRemoteObjects\"
+ INCLUDE_DIRECTORIES
+ ${REPPARSER_DIR}
+ PUBLIC_LIBRARIES
+ Qt::CorePrivate
+)
+
+# QLALR Grammars:
+qt_process_qlalr(
+ ${target_name}
+ "${REPPARSER_DIR}/parser.g"
+ ""
+)
+
+#### Keys ignored in scope 1:.:.:repc.pro:<TRUE>:
+# QMAKE_TARGET_DESCRIPTION = "Qt Remote Objects Compiler"
+# _OPTION = "host_build"
+
+## Scopes:
+#####################################################################
+
+qt_internal_extend_target(${target_name} CONDITION MSVC
+ COMPILE_OPTIONS
+ /wd4129
+)
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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 with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <qiodevice.h>
+#include <qjsonarray.h>
+#include <qjsonvalue.h>
+
+#include "cppcodegenerator.h"
+#include "utils.h"
+
+QT_BEGIN_NAMESPACE
+
+CppCodeGenerator::CppCodeGenerator(QIODevice *outputDevice)
+ : m_outputDevice(outputDevice)
+{
+ Q_ASSERT(m_outputDevice);
+}
+
+void CppCodeGenerator::generate(const QJsonArray &classList, bool alwaysGenerateClass /* = false */)
+{
+ for (const QJsonValue cdef : classList)
+ m_outputDevice->write(generateClass(cdef, alwaysGenerateClass));
+
+ m_outputDevice->write("\n");
+}
+
+QT_END_NAMESPACE
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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 with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef CPPCODEGENERATOR_H
+#define CPPCODEGENERATOR_H
+
+QT_BEGIN_NAMESPACE
+class QJsonArray;
+class QIODevice;
+
+class CppCodeGenerator
+{
+public:
+ CppCodeGenerator(QIODevice *outputDevice);
+
+ void generate(const QJsonArray &classList, bool alwaysGenerateClass = false);
+
+private:
+ QIODevice *m_outputDevice;
+};
+
+QT_END_NAMESPACE
+
+#endif // CPPCODEGENERATOR_H
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017-2020 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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 with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <qcommandlineoption.h>
+#include <qcommandlineparser.h>
+#include <qcoreapplication.h>
+#include <qfileinfo.h>
+#include <qjsondocument.h>
+#include <qjsonobject.h>
+#include <qjsonarray.h>
+
+#include "cppcodegenerator.h"
+#include "repcodegenerator.h"
+#include "repparser.h"
+#include "utils.h"
+
+#include <cstdio>
+
+#define PROGRAM_NAME "repc"
+#define REPC_VERSION "1.0.0"
+
+enum Mode {
+ InRep = 1,
+ InJson = 2,
+ OutRep = 4,
+ OutSource = 8,
+ OutReplica = 16,
+ OutMerged = OutSource | OutReplica
+};
+
+static const QLatin1String REP("rep");
+static const QLatin1String JSON("json");
+static const QLatin1String REPLICA("replica");
+static const QLatin1String SOURCE("source");
+static const QLatin1String MERGED("merged");
+
+QT_USE_NAMESPACE
+
+int main(int argc, char **argv)
+{
+ QCoreApplication app(argc, argv);
+ QCoreApplication::setApplicationVersion(QString::fromLatin1(REPC_VERSION));
+
+ QString outputFile;
+ QString inputFile;
+ int mode = 0;
+ QCommandLineParser parser;
+ parser.setApplicationDescription(QStringLiteral("repc tool v%1 (Qt %2).\n")
+ .arg(QStringLiteral(REPC_VERSION), QString::fromLatin1(QT_VERSION_STR)));
+ parser.addHelpOption();
+ parser.addVersionOption();
+ QCommandLineOption inputTypeOption(QStringLiteral("i"));
+ inputTypeOption.setDescription(QLatin1String("Input file type:\n"
+ "rep: replicant template files.\n"
+ "json: JSON output from moc of a Qt header file."));
+ inputTypeOption.setValueName(QStringLiteral("rep|json"));
+ parser.addOption(inputTypeOption);
+
+ QCommandLineOption outputTypeOption(QStringLiteral("o"));
+ outputTypeOption.setDescription(QLatin1String("Output file type:\n"
+ "source: generates source header. Is incompatible with \"-i src\" option.\n"
+ "replica: generates replica header.\n"
+ "merged: generates combined replica/source header.\n"
+ "rep: generates replicant template file from C++ QOject classes. Is not compatible with \"-i rep\" option."));
+ outputTypeOption.setValueName(QStringLiteral("source|replica|merged|rep"));
+ parser.addOption(outputTypeOption);
+
+ QCommandLineOption includePathOption(QStringLiteral("I"));
+ includePathOption.setDescription(QStringLiteral("Add dir to the include path for header files. This parameter is needed only if the input file type is src (.h file)."));
+ includePathOption.setValueName(QStringLiteral("dir"));
+ parser.addOption(includePathOption);
+
+ QCommandLineOption alwaysClassOption(QStringLiteral("c"));
+ alwaysClassOption.setDescription(QStringLiteral("Always output `class` type for .rep files and never `POD`."));
+ parser.addOption(alwaysClassOption);
+
+ QCommandLineOption debugOption(QStringLiteral("d"));
+ debugOption.setDescription(QStringLiteral("Print out parsing debug information (for troubleshooting)."));
+ parser.addOption(debugOption);
+
+ parser.addPositionalArgument(QStringLiteral("[json-file/rep-file]"),
+ QStringLiteral("Input json/rep file to read from, otherwise stdin."));
+
+ parser.addPositionalArgument(QStringLiteral("[rep-file/header-file]"),
+ QStringLiteral("Output header/rep file to write to, otherwise stdout."));
+
+ parser.process(app.arguments());
+
+ const QStringList files = parser.positionalArguments();
+
+ if (files.count() > 2) {
+ fprintf(stderr, "%s", qPrintable(QLatin1String(PROGRAM_NAME ": Too many input, output files specified: '") + files.join(QStringLiteral("' '")) + QStringLiteral("\'.\n")));
+ parser.showHelp(1);
+ }
+
+ if (parser.isSet(inputTypeOption)) {
+ const QString &inputType = parser.value(inputTypeOption);
+ if (inputType == REP)
+ mode = InRep;
+ else if (inputType == JSON)
+ mode = InJson;
+ else {
+ fprintf(stderr, PROGRAM_NAME ": Unknown input type\"%s\".\n", qPrintable(inputType));
+ parser.showHelp(1);
+ }
+ }
+
+ if (parser.isSet(outputTypeOption)) {
+ const QString &outputType = parser.value(outputTypeOption);
+ if (outputType == REP)
+ mode |= OutRep;
+ else if (outputType == REPLICA)
+ mode |= OutReplica;
+ else if (outputType == SOURCE)
+ mode |= OutSource;
+ else if (outputType == MERGED)
+ mode |= OutMerged;
+ else {
+ fprintf(stderr, PROGRAM_NAME ": Unknown output type\"%s\".\n", qPrintable(outputType));
+ parser.showHelp(1);
+ }
+ }
+
+ switch (files.count()) {
+ case 2:
+ outputFile = files.last();
+ if (!(mode & (OutRep | OutSource | OutReplica))) {
+ // try to figure out the Out mode from file extension
+ if (outputFile.endsWith(QLatin1String(".rep")))
+ mode |= OutRep;
+ }
+ Q_FALLTHROUGH();
+ case 1:
+ inputFile = files.first();
+ if (!(mode & (InRep | InJson))) {
+ // try to figure out the In mode from file extension
+ if (inputFile.endsWith(QLatin1String(".rep")))
+ mode |= InRep;
+ else
+ mode |= InJson;
+ }
+ break;
+ }
+ // check mode sanity
+ if (!(mode & (InRep | InJson))) {
+ fprintf(stderr, PROGRAM_NAME ": Unknown input type, please use -i option to specify one.\n");
+ parser.showHelp(1);
+ }
+ if (!(mode & (OutRep | OutSource | OutReplica))) {
+ fprintf(stderr, PROGRAM_NAME ": Unknown output type, please use -o option to specify one.\n");
+ parser.showHelp(1);
+ }
+ if (mode & InRep && mode & OutRep) {
+ fprintf(stderr, PROGRAM_NAME ": Invalid input/output type combination, both are rep files.\n");
+ parser.showHelp(1);
+ }
+ if (mode & InJson && mode & OutSource) {
+ fprintf(stderr, PROGRAM_NAME ": Invalid input/output type combination, both are source header files.\n");
+ parser.showHelp(1);
+ }
+
+ QFile input;
+ if (inputFile.isEmpty()) {
+ inputFile = QStringLiteral("<stdin>");
+ input.open(stdin, QIODevice::ReadOnly);
+ } else {
+ input.setFileName(inputFile);
+ if (!input.open(QIODevice::ReadOnly)) {
+ fprintf(stderr, PROGRAM_NAME ": %s: No such file.\n", qPrintable(inputFile));
+ return 1;
+ }
+ }
+
+ QFile output;
+ if (outputFile.isEmpty()) {
+ output.open(stdout, QIODevice::WriteOnly);
+ } else {
+ output.setFileName(outputFile);
+ if (!output.open(QIODevice::WriteOnly)) {
+ fprintf(stderr, PROGRAM_NAME ": could not open output file '%s': %s.\n",
+ qPrintable(outputFile), qPrintable(output.errorString()));
+ return 1;
+ }
+ }
+
+ if (mode & InJson) {
+ QJsonDocument doc(QJsonDocument::fromJson(input.readAll()));
+ input.close();
+ if (!doc.isObject()) {
+ fprintf(stderr, PROGRAM_NAME ": Unable to read json input.\n");
+ return 0;
+ }
+
+ QJsonObject json = doc.object();
+
+ if (!json.contains(QLatin1String("classes")) || !json[QLatin1String("classes")].isArray()) {
+ fprintf(stderr, PROGRAM_NAME ": No QObject classes found.\n");
+ return 0;
+ }
+
+ QJsonArray classes = json[QLatin1String("classes")].toArray();
+
+ if (mode & OutRep) {
+ CppCodeGenerator generator(&output);
+ generator.generate(classes, parser.isSet(alwaysClassOption));
+ } else {
+ Q_ASSERT(mode & OutReplica);
+ RepCodeGenerator generator(&output, classList2AST(classes));
+ generator.generate(RepCodeGenerator::REPLICA, outputFile);
+ }
+ } else {
+ Q_ASSERT(!(mode & OutRep));
+ RepParser repparser(input);
+ if (parser.isSet(debugOption))
+ repparser.setDebug();
+ if (!repparser.parse()) {
+ fprintf(stderr, PROGRAM_NAME ": %s:%d: error: %s\n", qPrintable(inputFile), repparser.lineNumber(), qPrintable(repparser.errorString()));
+ // if everything is okay and only the input was malformed => remove the output file
+ // let's not create an empty file -- make sure the build system tries to run repc again
+ // this is the same behavior other code generators exhibit (e.g. flex)
+ output.remove();
+ return 1;
+ }
+
+ input.close();
+
+ RepCodeGenerator generator(&output, repparser.ast());
+ if ((mode & OutMerged) == OutMerged)
+ generator.generate(RepCodeGenerator::MERGED, outputFile);
+ else if (mode & OutReplica)
+ generator.generate(RepCodeGenerator::REPLICA, outputFile);
+ else if (mode & OutSource)
+ generator.generate(RepCodeGenerator::SOURCE, outputFile);
+ else {
+ fprintf(stderr, PROGRAM_NAME ": Unknown mode.\n");
+ return 1;
+ }
+ }
+
+ output.close();
+ return 0;
+}
--- /dev/null
+option(host_build)
+include(moc_copy/moc.pri)
+QT = core-private
+
+DEFINES += QT_NO_CAST_TO_ASCII QT_NO_CAST_FROM_ASCII QT_NO_CAST_FROM_BYTEARRAY QT_NO_URL_CAST_FROM_STRING
+DEFINES += RO_INSTALL_HEADERS=$$shell_quote(\"$$clean_path($$[QT_INSTALL_HEADERS]/QtRemoteObjects)\")
+msvc: QMAKE_CXXFLAGS += /wd4129
+
+CONFIG += qlalr
+QLALRSOURCES += $$QTRO_SOURCE_TREE/src/repparser/parser.g
+INCLUDEPATH += $$QTRO_SOURCE_TREE/src/repparser
+
+SOURCES += \
+ main.cpp \
+ repcodegenerator.cpp \
+ cppcodegenerator.cpp \
+ utils.cpp
+
+HEADERS += \
+ repcodegenerator.h \
+ cppcodegenerator.h \
+ utils.h
+
+QMAKE_TARGET_DESCRIPTION = "Qt Remote Objects Compiler"
+load(qt_tool)
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017-2020 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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 with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "repcodegenerator.h"
+
+#include <QFileInfo>
+#include <QMetaType>
+#include <QCryptographicHash>
+#include <QRegularExpression>
+
+using namespace Qt;
+
+QT_BEGIN_NAMESPACE
+
+template <typename C>
+static int accumulatedSizeOfNames(const C &c)
+{
+ int result = 0;
+ for (const auto &e : c)
+ result += e.name.size();
+ return result;
+}
+
+template <typename C>
+static int accumulatedSizeOfTypes(const C &c)
+{
+ int result = 0;
+ for (const auto &e : c)
+ result += e.type.size();
+ return result;
+}
+
+static QString cap(QString name)
+{
+ if (!name.isEmpty())
+ name[0] = name[0].toUpper();
+ return name;
+}
+
+static bool isClassEnum(const ASTClass &classContext, const QString &typeName)
+{
+ for (const ASTEnum &astEnum : classContext.enums) {
+ if (astEnum.name == typeName) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static bool hasScopedEnum(const ASTClass &classContext)
+{
+ for (const ASTEnum &astEnum : classContext.enums) {
+ if (astEnum.isScoped) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static bool hasScopedEnum(const POD &pod)
+{
+ for (const ASTEnum &astEnum : pod.enums) {
+ if (astEnum.isScoped) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static QString fullyQualifiedName(const ASTClass& classContext, const QString &className,
+ const QString &typeName)
+{
+ static const QRegularExpression re = QRegularExpression(QLatin1String("([^<>,\\s]+)"));
+ QString copy = typeName;
+ qsizetype offset = 0;
+ for (const QRegularExpressionMatch &match : re.globalMatch(typeName)) {
+ if (isClassEnum(classContext, match.captured(1))) {
+ copy.insert(match.capturedStart(1) + offset, className + QStringLiteral("::"));
+ offset += className.length() + 2;
+ }
+ }
+ return copy;
+}
+
+// for enums we need to transform signal/slot arguments to include the class scope
+static QList<ASTFunction> transformEnumParams(const ASTClass& classContext,
+ const QList<ASTFunction> &methodList,
+ const QString &typeName) {
+ QList<ASTFunction> localList = methodList;
+ for (ASTFunction &astFunction : localList) {
+ for (ASTDeclaration &astParam : astFunction.params) {
+ for (const ASTEnum &astEnum : classContext.enums) {
+ if (astEnum.name == astParam.type) {
+ astParam.type = typeName + QStringLiteral("::") + astParam.type;
+ }
+ }
+ }
+ }
+ return localList;
+}
+
+/*
+ Returns \c true if the type is a built-in type.
+*/
+static bool isBuiltinType(const QString &type)
+ {
+ const auto metaType = QMetaType::fromName(type.toLatin1().constData());
+ if (!metaType.isValid())
+ return false;
+ return (metaType.id() < QMetaType::User);
+}
+
+RepCodeGenerator::RepCodeGenerator(QIODevice *outputDevice, const AST &ast)
+ : m_stream(outputDevice), m_ast(ast)
+{
+}
+
+QByteArray RepCodeGenerator::classSignature(const ASTClass &ac)
+{
+ return m_ast.typeSignatures[ac.name];
+}
+
+void RepCodeGenerator::generate(Mode mode, QString fileName)
+{
+ if (fileName.isEmpty())
+ m_stream << "#pragma once" << Qt::endl << Qt::endl;
+ else {
+ fileName = QFileInfo(fileName).fileName();
+ fileName = fileName.toUpper();
+ fileName.replace(QLatin1Char('.'), QLatin1Char('_'));
+ m_stream << "#ifndef " << fileName << Qt::endl;
+ m_stream << "#define " << fileName << Qt::endl << Qt::endl;
+ }
+
+ generateHeader(mode);
+ for (const ASTEnum &en : m_ast.enums)
+ generateEnumGadget(en, QStringLiteral("%1Enum").arg(en.name));
+ for (const POD &pod : m_ast.pods)
+ generatePOD(pod);
+
+ QSet<QString> metaTypes;
+ QSet<QString> enumTypes;
+ for (const POD &pod : m_ast.pods) {
+ metaTypes << pod.name;
+ // We register from within the code generated for classes, not PODs
+ // Thus, for enums/flags in PODs, we need the to prefix with the POD
+ // name. The enumTypes set is used to make sure we don't try to
+ // register the non-prefixed name if it is used as a member variable
+ // type.
+ for (const ASTEnum &en : pod.enums) {
+ metaTypes << QLatin1String("%1::%2").arg(pod.name, en.name);
+ enumTypes << en.name;
+ }
+ for (const ASTFlag &flag : pod.flags) {
+ metaTypes << QLatin1String("%1::%2").arg(pod.name, flag.name);
+ enumTypes << flag.name;
+ }
+ for (const PODAttribute &attribute : pod.attributes) {
+ if (!enumTypes.contains(attribute.type))
+ metaTypes << attribute.type;
+ }
+ }
+ const QString metaTypeRegistrationCode = generateMetaTypeRegistration(metaTypes);
+
+ for (const ASTClass &astClass : m_ast.classes) {
+ QSet<QString> classMetaTypes;
+ QSet<QString> pendingMetaTypes;
+ for (const ASTEnum &en : astClass.enums)
+ classMetaTypes << en.name;
+ for (const ASTProperty &property : astClass.properties) {
+ if (property.isPointer)
+ continue;
+ classMetaTypes << property.type;
+ }
+ const auto extractClassMetaTypes = [&](const ASTFunction &function) {
+ classMetaTypes << function.returnType;
+ pendingMetaTypes << function.returnType;
+ for (const ASTDeclaration &decl : function.params) {
+ classMetaTypes << decl.type;
+
+ // Collect types packaged by Qt containers, to register their metatypes if needed
+ QRegularExpression re(
+ QStringLiteral("(QList|QMap|QHash)<\\s*([\\w]+)\\s*(,\\s*([\\w]+))?\\s*>"));
+ QRegularExpressionMatch m = re.match(decl.type);
+ if (m.hasMatch()) {
+ if (auto captured = m.captured(2);
+ !captured.isNull() && !metaTypes.contains(captured)) {
+ classMetaTypes << captured;
+ }
+ if (auto captured = m.captured(4);
+ !captured.isNull() && !metaTypes.contains(captured)) {
+ classMetaTypes << captured;
+ }
+ }
+ }
+ };
+ for (const ASTFunction &function : astClass.signalsList)
+ extractClassMetaTypes(function);
+ for (const ASTFunction &function : astClass.slotsList)
+ extractClassMetaTypes(function);
+
+ const QString classMetaTypeRegistrationCode = metaTypeRegistrationCode
+ + generateMetaTypeRegistration(classMetaTypes);
+ const QString replicaMetaTypeRegistrationCode = classMetaTypeRegistrationCode
+ + generateMetaTypeRegistrationForPending(pendingMetaTypes);
+
+ if (mode == MERGED) {
+ generateClass(REPLICA, astClass, replicaMetaTypeRegistrationCode);
+ generateClass(SOURCE, astClass, classMetaTypeRegistrationCode);
+ generateClass(SIMPLE_SOURCE, astClass, classMetaTypeRegistrationCode);
+ generateSourceAPI(astClass);
+ } else {
+ generateClass(mode, astClass, mode == REPLICA ? replicaMetaTypeRegistrationCode
+ : classMetaTypeRegistrationCode);
+ if (mode == SOURCE) {
+ generateClass(SIMPLE_SOURCE, astClass, classMetaTypeRegistrationCode);
+ generateSourceAPI(astClass);
+ }
+ }
+ }
+
+ m_stream << Qt::endl;
+ if (!fileName.isEmpty())
+ m_stream << "#endif // " << fileName << Qt::endl;
+}
+
+void RepCodeGenerator::generateHeader(Mode mode)
+{
+ m_stream <<
+ "// This is an autogenerated file.\n"
+ "// Do not edit this file, any changes made will be lost the next time it is generated.\n"
+ "\n"
+ "#include <QtCore/qobject.h>\n"
+ "#include <QtCore/qdatastream.h>\n"
+ "#include <QtCore/qvariant.h>\n"
+ "#include <QtCore/qmetatype.h>\n";
+ bool hasModel = false;
+ for (auto c : m_ast.classes)
+ {
+ if (c.modelMetadata.count() > 0)
+ {
+ hasModel = true;
+ break;
+ }
+ }
+ if (hasModel)
+ m_stream << "#include <QtCore/qabstractitemmodel.h>\n";
+ m_stream << "\n"
+ "#include <QtRemoteObjects/qremoteobjectnode.h>\n";
+
+ if (mode == MERGED) {
+ m_stream << "#include <QtRemoteObjects/qremoteobjectpendingcall.h>\n";
+ m_stream << "#include <QtRemoteObjects/qremoteobjectreplica.h>\n";
+ m_stream << "#include <QtRemoteObjects/qremoteobjectsource.h>\n";
+ if (hasModel)
+ m_stream << "#include <QtRemoteObjects/qremoteobjectabstractitemmodelreplica.h>\n";
+ } else if (mode == REPLICA) {
+ m_stream << "#include <QtRemoteObjects/qremoteobjectpendingcall.h>\n";
+ m_stream << "#include <QtRemoteObjects/qremoteobjectreplica.h>\n";
+ if (hasModel)
+ m_stream << "#include <QtRemoteObjects/qremoteobjectabstractitemmodelreplica.h>\n";
+ } else
+ m_stream << "#include <QtRemoteObjects/qremoteobjectsource.h>\n";
+ m_stream << "\n";
+
+ m_stream << m_ast.preprocessorDirectives.join(QLatin1Char('\n'));
+ m_stream << "\n";
+}
+
+static QString formatTemplateStringArgTypeNameCapitalizedName(int numberOfTypeOccurrences,
+ int numberOfNameOccurrences,
+ QString templateString,
+ const POD &pod)
+{
+ QString out;
+ const int LengthOfPlaceholderText = 2;
+ Q_ASSERT(templateString.count(QRegularExpression(QStringLiteral("%\\d")))
+ == numberOfNameOccurrences + numberOfTypeOccurrences);
+ const auto expectedOutSize
+ = numberOfNameOccurrences * accumulatedSizeOfNames(pod.attributes)
+ + numberOfTypeOccurrences * accumulatedSizeOfTypes(pod.attributes)
+ + pod.attributes.size() * (templateString.size()
+ - (numberOfNameOccurrences + numberOfTypeOccurrences)
+ * LengthOfPlaceholderText);
+ out.reserve(expectedOutSize);
+ for (const PODAttribute &a : pod.attributes)
+ out += templateString.arg(a.type, a.name, cap(a.name));
+ return out;
+}
+
+QString RepCodeGenerator::formatQPropertyDeclarations(const POD &pod)
+{
+ QString prop = QStringLiteral(" Q_PROPERTY(%1 %2 READ %2 WRITE set%3)\n");
+ return formatTemplateStringArgTypeNameCapitalizedName(1, 3, prop, pod);
+}
+
+QString RepCodeGenerator::formatConstructors(const POD &pod)
+{
+ QString initializerString = QStringLiteral(": ");
+ QString defaultInitializerString = initializerString;
+ QString argString;
+ for (const PODAttribute &a : pod.attributes) {
+ initializerString += QString::fromLatin1("m_%1(%1), ").arg(a.name);
+ defaultInitializerString += QString::fromLatin1("m_%1(), ").arg(a.name);
+ argString += QString::fromLatin1("%1 %2, ").arg(a.type, a.name);
+ }
+ argString.chop(2);
+ initializerString.chop(2);
+ defaultInitializerString.chop(2);
+
+ return QString::fromLatin1(" %1() %2 {}\n"
+ " explicit %1(%3) %4 {}\n")
+ .arg(pod.name, defaultInitializerString, argString, initializerString);
+}
+
+QString RepCodeGenerator::formatPropertyGettersAndSetters(const POD &pod)
+{
+ QString templateString
+ = QString::fromLatin1(" %1 %2() const { return m_%2; }\n"
+ " void set%3(%1 %2) { if (%2 != m_%2) { m_%2 = %2; } }\n");
+ return formatTemplateStringArgTypeNameCapitalizedName(2, 8, qMove(templateString), pod);
+}
+
+QString RepCodeGenerator::formatDataMembers(const POD &pod)
+{
+ QString out;
+ const QString prefix = QStringLiteral(" ");
+ const QString infix = QStringLiteral(" m_");
+ const QString suffix = QStringLiteral(";\n");
+ const auto expectedOutSize
+ = accumulatedSizeOfNames(pod.attributes)
+ + accumulatedSizeOfTypes(pod.attributes)
+ + pod.attributes.size() * (prefix.size() + infix.size() + suffix.size());
+ out.reserve(expectedOutSize);
+ for (const PODAttribute &a : pod.attributes) {
+ out += prefix;
+ out += a.type;
+ out += infix;
+ out += a.name;
+ out += suffix;
+ }
+ Q_ASSERT(out.size() == expectedOutSize);
+ return out;
+}
+
+QString RepCodeGenerator::formatDebugOperator(const POD &pod)
+{
+ QString props;
+ int count = 0;
+ for (const PODAttribute &attribute : pod.attributes) {
+ if (count++ > 0)
+ props.append(QLatin1String(" << \", \""));
+ props.append(QLatin1String(" << \"%1: \" << obj.%1()").arg(attribute.name));
+ }
+
+ return QLatin1String("inline QDebug operator<<(QDebug dbg, const %1 &obj) {\n" \
+ " dbg.nospace() << \"%1(\" %2 << \")\";\n" \
+ " return dbg.maybeSpace();\n}\n\n").arg(pod.name, props);
+}
+
+QString RepCodeGenerator::formatMarshallingOperators(const POD &pod)
+{
+ return QLatin1String("inline QDataStream &operator<<(QDataStream &ds, const ") + pod.name
+ + QLatin1String(" &obj) {\n"
+ " QtRemoteObjects::copyStoredProperties(&obj, ds);\n"
+ " return ds;\n"
+ "}\n"
+ "\n"
+ "inline QDataStream &operator>>(QDataStream &ds, ") + pod.name
+ + QLatin1String(" &obj) {\n"
+ " QtRemoteObjects::copyStoredProperties(ds, &obj);\n"
+ " return ds;\n"
+ "}\n")
+ ;
+}
+
+QString RepCodeGenerator::typeForMode(const ASTProperty &property, RepCodeGenerator::Mode mode)
+{
+ if (!property.isPointer)
+ return property.type;
+
+ if (property.type.startsWith(QStringLiteral("QAbstractItemModel")))
+ return mode == REPLICA ? property.type + QStringLiteral("Replica*")
+ : property.type + QStringLiteral("*");
+
+ switch (mode) {
+ case REPLICA: return property.type + QStringLiteral("Replica*");
+ case SIMPLE_SOURCE:
+ Q_FALLTHROUGH();
+ case SOURCE: return property.type + QStringLiteral("Source*");
+ default: qCritical("Invalid mode");
+ }
+
+ return QStringLiteral("InvalidPropertyName");
+}
+
+void RepCodeGenerator::generateSimpleSetter(const ASTProperty &property, bool generateOverride)
+{
+ if (!generateOverride)
+ m_stream << " virtual ";
+ else
+ m_stream << " ";
+ m_stream << "void set" << cap(property.name) << "(" << typeForMode(property, SIMPLE_SOURCE)
+ << " " << property.name << ")";
+ if (generateOverride)
+ m_stream << " override";
+ m_stream << Qt::endl;
+ m_stream << " {" << Qt::endl;
+ m_stream << " if (" << property.name << " != m_" << property.name << ") {" << Qt::endl;
+ m_stream << " m_" << property.name << " = " << property.name << ";" << Qt::endl;
+ m_stream << " Q_EMIT " << property.name << "Changed(m_" << property.name << ");"
+ << Qt::endl;
+ m_stream << " }" << Qt::endl;
+ m_stream << " }" << Qt::endl;
+}
+
+void RepCodeGenerator::generatePOD(const POD &pod)
+{
+ QStringList equalityCheck;
+ for (const PODAttribute &attr : pod.attributes)
+ equalityCheck << QStringLiteral("left.%1() == right.%1()").arg(attr.name);
+ m_stream << "class " << pod.name << "\n"
+ "{\n"
+ " Q_GADGET\n"
+ << "\n"
+ << formatQPropertyDeclarations(pod);
+ if (hasScopedEnum(pod)) // See https://bugreports.qt.io/browse/QTBUG-73360
+ m_stream << " Q_CLASSINFO(\"RegisterEnumClassesUnscoped\", \"false\")\n";
+ m_stream << "public:\n";
+ generateDeclarationsForEnums(pod.enums);
+ for (auto &flag : pod.flags) {
+ m_stream << " Q_DECLARE_FLAGS(" << flag.name << ", " << flag._enum << ")\n";
+ m_stream << " Q_FLAG(" << flag.name << ")\n";
+ }
+ m_stream << formatConstructors(pod)
+ << formatPropertyGettersAndSetters(pod)
+ << "private:\n"
+ << formatDataMembers(pod)
+ << "};\n"
+ << "\n"
+ << "inline bool operator==(const " << pod.name << " &left, const " << pod.name <<
+ " &right) Q_DECL_NOTHROW {\n"
+ << " return " << equalityCheck.join(QStringLiteral(" && ")) << ";\n"
+ << "}\n"
+ << "inline bool operator!=(const " << pod.name << " &left, const " << pod.name <<
+ " &right) Q_DECL_NOTHROW {\n"
+ << " return !(left == right);\n"
+ << "}\n"
+ << "\n"
+ << formatDebugOperator(pod)
+ << formatMarshallingOperators(pod);
+ for (auto &flag : pod.flags)
+ m_stream << "Q_DECLARE_OPERATORS_FOR_FLAGS(" << pod.name << "::" << flag.name << ")\n";
+ m_stream << "\n";
+}
+
+QString getEnumType(const ASTEnum &en)
+{
+ if (!en.type.isEmpty())
+ return en.type;
+ if (en.isSigned) {
+ if (en.max < 0x7F)
+ return QStringLiteral("qint8");
+ if (en.max < 0x7FFF)
+ return QStringLiteral("qint16");
+ return QStringLiteral("qint32");
+ } else {
+ if (en.max < 0xFF)
+ return QStringLiteral("quint8");
+ if (en.max < 0xFFFF)
+ return QStringLiteral("quint16");
+ return QStringLiteral("quint32");
+ }
+}
+
+void RepCodeGenerator::generateDeclarationsForEnums(const QList<ASTEnum> &enums,
+ bool generateQENUM)
+{
+ if (!generateQENUM) {
+ m_stream << " // You need to add this enum as well as Q_ENUM to your" << Qt::endl;
+ m_stream << " // QObject class in order to use .rep enums over QtRO for" << Qt::endl;
+ m_stream << " // non-repc generated QObjects." << Qt::endl;
+ }
+
+ for (const ASTEnum &en : enums) {
+ m_stream << " enum " << (en.isScoped ? "class " : "") << en.name
+ << (en.type.isEmpty() ? "" : " : ") << en.type << " {\n";
+ for (const ASTEnumParam &p : en.params)
+ m_stream << " " << p.name << " = " << p.value << ",\n";
+
+ m_stream << " };\n";
+
+ if (generateQENUM)
+ m_stream << " Q_ENUM(" << en.name << ")\n";
+ }
+}
+
+void RepCodeGenerator::generateEnumGadget(const ASTEnum &en, const QString &className)
+{
+ m_stream << "class " << className << "\n"
+ "{\n"
+ " Q_GADGET\n";
+ if (en.isScoped)
+ m_stream << " Q_CLASSINFO(\"RegisterEnumClassesUnscoped\", \"false\")\n";
+ m_stream << " " << className << "();\n"
+ "\n"
+ "public:\n";
+
+ auto enums = QList<ASTEnum>() << en;
+ generateDeclarationsForEnums(enums);
+ if (en.flagIndex >= 0) {
+ auto flag = m_ast.flags.at(en.flagIndex);
+ m_stream << " Q_DECLARE_FLAGS(" << flag.name << ", " << flag._enum << ")\n";
+ m_stream << " Q_FLAG(" << flag.name << ")\n";
+ m_stream << "};\n\n";
+ m_stream << "Q_DECLARE_OPERATORS_FOR_FLAGS(" << className << "::" << flag.name << ")\n\n";
+ } else {
+ m_stream << "};\n\n";
+ }
+}
+
+QString RepCodeGenerator::generateMetaTypeRegistration(const QSet<QString> &metaTypes)
+{
+ QString out;
+ const QString qRegisterMetaType = QStringLiteral(" qRegisterMetaType<");
+ const QString lineEnding = QStringLiteral(">();\n");
+ for (const QString &metaType : metaTypes) {
+ if (isBuiltinType(metaType))
+ continue;
+
+ out += qRegisterMetaType;
+ out += metaType;
+ out += lineEnding;
+ }
+ return out;
+}
+
+QString RepCodeGenerator::generateMetaTypeRegistrationForPending(const QSet<QString> &metaTypes)
+{
+ QString out;
+ if (!metaTypes.isEmpty())
+ out += QLatin1String(" qRegisterMetaType<QRemoteObjectPendingCall>();\n");
+ const QString qRegisterMetaType =
+ QStringLiteral(" qRegisterMetaType<QRemoteObjectPendingReply<%1>>();\n");
+ const QString qRegisterConverterConditional =
+ QStringLiteral(" if (!QMetaType::hasRegisteredConverterFunction<"
+ "QRemoteObjectPendingReply<%1>, QRemoteObjectPendingCall>())\n");
+ const QString qRegisterConverter =
+ QStringLiteral(" QMetaType::registerConverter<QRemoteObjectPendingReply<%1>"
+ ", QRemoteObjectPendingCall>();\n");
+ for (const QString &metaType : metaTypes) {
+ out += qRegisterMetaType.arg(metaType);
+ out += qRegisterConverterConditional.arg(metaType);
+ out += qRegisterConverter.arg(metaType);
+ }
+ return out;
+}
+
+void RepCodeGenerator::generateClass(Mode mode, const ASTClass &astClass,
+ const QString &metaTypeRegistrationCode)
+{
+ const QString className = (astClass.name + (mode == REPLICA ?
+ QStringLiteral("Replica") : mode == SOURCE ?
+ QStringLiteral("Source") : QStringLiteral("SimpleSource")));
+ if (mode == REPLICA)
+ m_stream << "class " << className << " : public QRemoteObjectReplica" << Qt::endl;
+ else if (mode == SIMPLE_SOURCE)
+ m_stream << "class " << className << " : public " << astClass.name << "Source"
+ << Qt::endl;
+ else
+ m_stream << "class " << className << " : public QObject" << Qt::endl;
+
+ m_stream << "{\n";
+ m_stream << " Q_OBJECT\n";
+ if (hasScopedEnum(astClass)) // See https://bugreports.qt.io/browse/QTBUG-73360
+ m_stream << " Q_CLASSINFO(\"RegisterEnumClassesUnscoped\", \"false\")\n";
+ if (mode != SIMPLE_SOURCE) {
+ m_stream << " Q_CLASSINFO(QCLASSINFO_REMOTEOBJECT_TYPE, \"" << astClass.name
+ << "\")" << Qt::endl;
+ m_stream << " Q_CLASSINFO(QCLASSINFO_REMOTEOBJECT_SIGNATURE, \""
+ << QLatin1String(classSignature(astClass)) << "\")" << Qt::endl;
+ for (int i = 0; i < astClass.modelMetadata.count(); i++) {
+ const auto model = astClass.modelMetadata.at(i);
+ const auto modelName = astClass.properties.at(model.propertyIndex).name;
+ if (!model.roles.isEmpty()) {
+ QStringList list;
+ for (auto role : model.roles)
+ list << role.name;
+ m_stream << QString::fromLatin1(" Q_CLASSINFO(\"%1_ROLES\", \"%2\")")
+ .arg(modelName.toUpper(), list.join(QChar::fromLatin1('|')))
+ << Qt::endl;
+ }
+ }
+
+
+ //First output properties
+ for (const ASTProperty &property : astClass.properties) {
+ m_stream << " Q_PROPERTY(" << typeForMode(property, mode) << " " << property.name
+ << " READ " << property.name;
+ if (property.modifier == ASTProperty::Constant) {
+ if (mode == REPLICA) // We still need to notify when we get the initial value
+ m_stream << " NOTIFY " << property.name << "Changed";
+ else
+ m_stream << " CONSTANT";
+ } else if (property.modifier == ASTProperty::ReadOnly)
+ m_stream << " NOTIFY " << property.name << "Changed";
+ else if (property.modifier == ASTProperty::ReadWrite)
+ m_stream << " WRITE set" << cap(property.name) << " NOTIFY " << property.name
+ << "Changed";
+ else if (property.modifier == ASTProperty::ReadPush ||
+ property.modifier == ASTProperty::SourceOnlySetter) {
+ if (mode == REPLICA) // The setter slot isn't known to the PROP
+ m_stream << " NOTIFY " << property.name << "Changed";
+ else // The Source can use the setter, since non-asynchronous
+ m_stream << " WRITE set" << cap(property.name) << " NOTIFY "
+ << property.name << "Changed";
+ }
+ m_stream << ")" << Qt::endl;
+ }
+
+ if (!astClass.enums.isEmpty()) {
+ m_stream << "" << Qt::endl;
+ m_stream << "public:" << Qt::endl;
+ generateDeclarationsForEnums(astClass.enums);
+ for (const auto &flag : astClass.flags) {
+ m_stream << " Q_DECLARE_FLAGS(" << flag.name << ", " << flag._enum << ")\n";
+ m_stream << " Q_FLAG(" << flag.name << ")\n";
+ }
+ }
+ }
+
+ m_stream << "" << Qt::endl;
+ m_stream << "public:" << Qt::endl;
+
+ if (mode == REPLICA) {
+ m_stream << " " << className << "() : QRemoteObjectReplica() { initialize(); }"
+ << Qt::endl;
+ m_stream << " static void registerMetatypes()" << Qt::endl;
+ m_stream << " {" << Qt::endl;
+ m_stream << " static bool initialized = false;" << Qt::endl;
+ m_stream << " if (initialized)" << Qt::endl;
+ m_stream << " return;" << Qt::endl;
+ m_stream << " initialized = true;" << Qt::endl;
+
+ if (!metaTypeRegistrationCode.isEmpty())
+ m_stream << metaTypeRegistrationCode << Qt::endl;
+
+ m_stream << " }" << Qt::endl;
+
+ if (astClass.hasPointerObjects())
+ {
+ m_stream << " void setNode(QRemoteObjectNode *node) override" << Qt::endl;
+ m_stream << " {" << Qt::endl;
+ m_stream << " QRemoteObjectReplica::setNode(node);" << Qt::endl;
+ for (int index = 0; index < astClass.properties.count(); ++index) {
+ const ASTProperty &property = astClass.properties.at(index);
+ if (!property.isPointer)
+ continue;
+ const QString acquireName = astClass.name + QLatin1String("::") + property.name;
+ if (astClass.subClassPropertyIndices.contains(index))
+ m_stream << QString::fromLatin1(" setChild(%1, QVariant::fromValue("
+ "node->acquire<%2Replica>(QRemoteObjectStringLiterals::CLASS()"
+ ".arg(\"%3\"))));")
+ .arg(QString::number(index), property.type, acquireName)
+ << Qt::endl;
+ else
+ m_stream << QString::fromLatin1(" setChild(%1, QVariant::fromValue("
+ "node->acquireModel(QRemoteObjectStringLiterals::MODEL()"
+ ".arg(\"%2\"))));")
+ .arg(QString::number(index), acquireName) << Qt::endl;
+ m_stream << " Q_EMIT " << property.name << "Changed(" << property.name
+ << "()" << ");" << Qt::endl;
+
+ }
+ m_stream << " }" << Qt::endl;
+ }
+ m_stream << "" << Qt::endl;
+ m_stream << "private:" << Qt::endl;
+ m_stream << " " << className
+ << "(QRemoteObjectNode *node, const QString &name = QString())" << Qt::endl;
+ m_stream << " : QRemoteObjectReplica(ConstructWithNode)" << Qt::endl;
+ m_stream << " {" << Qt::endl;
+ m_stream << " initializeNode(node, name);" << Qt::endl;
+ for (int index = 0; index < astClass.properties.count(); ++index) {
+ const ASTProperty &property = astClass.properties.at(index);
+ if (!property.isPointer)
+ continue;
+ const QString acquireName = astClass.name + QLatin1String("::") + property.name;
+ if (astClass.subClassPropertyIndices.contains(index))
+ m_stream << QString::fromLatin1(" setChild(%1, QVariant::fromValue("
+ "node->acquire<%2Replica>(QRemoteObjectStringLiterals::CLASS()"
+ ".arg(\"%3\"))));")
+ .arg(QString::number(index), property.type, acquireName) << Qt::endl;
+ else
+ m_stream << QString::fromLatin1(" setChild(%1, QVariant::fromValue("
+ "node->acquireModel(QRemoteObjectStringLiterals::MODEL()"
+ ".arg(\"%2\"))));")
+ .arg(QString::number(index), acquireName) << Qt::endl;
+ }
+ m_stream << " }" << Qt::endl;
+
+ m_stream << "" << Qt::endl;
+
+ m_stream << " void initialize() override" << Qt::endl;
+ m_stream << " {" << Qt::endl;
+ m_stream << " " << className << "::registerMetatypes();" << Qt::endl;
+ m_stream << " QVariantList properties;" << Qt::endl;
+ m_stream << " properties.reserve(" << astClass.properties.size() << ");"
+ << Qt::endl;
+ for (const ASTProperty &property : astClass.properties) {
+ if (property.isPointer)
+ m_stream << " properties << QVariant::fromValue(("
+ << typeForMode(property, mode) << ")" << property.defaultValue
+ << ");" << Qt::endl;
+ else
+ m_stream << " properties << QVariant::fromValue("
+ << typeForMode(property, mode) << "(" << property.defaultValue
+ << "));" << Qt::endl;
+ }
+ int nPersisted = 0;
+ if (astClass.hasPersisted) {
+ m_stream << " QVariantList stored = retrieveProperties(QStringLiteral(\""
+ << astClass.name << "\"), \"" << classSignature(astClass) << "\");"
+ << Qt::endl;
+ m_stream << " if (!stored.isEmpty()) {" << Qt::endl;
+ for (int i = 0; i < astClass.properties.size(); i++) {
+ if (astClass.properties.at(i).persisted) {
+ m_stream << " properties[" << i << "] = stored.at(" << nPersisted
+ << ");" << Qt::endl;
+ nPersisted++;
+ }
+ }
+ m_stream << " }" << Qt::endl;
+ }
+ m_stream << " setProperties(std::move(properties));" << Qt::endl;
+ m_stream << " }" << Qt::endl;
+ } else if (mode == SOURCE) {
+ m_stream << " explicit " << className
+ << "(QObject *parent = nullptr) : QObject(parent)" << Qt::endl;
+ m_stream << " {" << Qt::endl;
+ if (!metaTypeRegistrationCode.isEmpty())
+ m_stream << metaTypeRegistrationCode << Qt::endl;
+ m_stream << " }" << Qt::endl;
+ } else {
+ QList<int> constIndices;
+ for (int index = 0; index < astClass.properties.count(); ++index) {
+ const ASTProperty &property = astClass.properties.at(index);
+ if (property.modifier == ASTProperty::Constant)
+ constIndices.append(index);
+ }
+ if (constIndices.isEmpty()) {
+ m_stream << " explicit " << className << "(QObject *parent = nullptr) : "
+ << astClass.name << "Source(parent)" << Qt::endl;
+ } else {
+ QStringList parameters;
+ for (int index : constIndices) {
+ const ASTProperty &property = astClass.properties.at(index);
+ parameters.append(QString::fromLatin1("%1 %2 = %3")
+ .arg(typeForMode(property, SOURCE), property.name,
+ property.defaultValue));
+ }
+ parameters.append(QStringLiteral("QObject *parent = nullptr"));
+ m_stream << " explicit " << className << "("
+ << parameters.join(QStringLiteral(", ")) << ") : " << astClass.name
+ << "Source(parent)" << Qt::endl;
+ }
+ for (const ASTProperty &property : astClass.properties) {
+ if (property.modifier == ASTProperty::Constant)
+ m_stream << " , m_" << property.name << "(" << property.name << ")"
+ << Qt::endl;
+ else
+ m_stream << " , m_" << property.name << "(" << property.defaultValue << ")"
+ << Qt::endl;
+ }
+ m_stream << " {" << Qt::endl;
+ m_stream << " }" << Qt::endl;
+ }
+
+ m_stream << "" << Qt::endl;
+ m_stream << "public:" << Qt::endl;
+
+ if (mode == REPLICA && astClass.hasPersisted) {
+ m_stream << " ~" << className << "() override {" << Qt::endl;
+ m_stream << " QVariantList persisted;" << Qt::endl;
+ for (int i = 0; i < astClass.properties.size(); i++) {
+ if (astClass.properties.at(i).persisted) {
+ m_stream << " persisted << propAsVariant(" << i << ");" << Qt::endl;
+ }
+ }
+ m_stream << " persistProperties(QStringLiteral(\"" << astClass.name << "\"), \""
+ << classSignature(astClass) << "\", persisted);" << Qt::endl;
+ m_stream << " }" << Qt::endl;
+ } else {
+ m_stream << " ~" << className << "() override = default;" << Qt::endl;
+ }
+ m_stream << "" << Qt::endl;
+
+ //Next output getter/setter
+ if (mode == REPLICA) {
+ int i = 0;
+ for (const ASTProperty &property : astClass.properties) {
+ auto type = typeForMode(property, mode);
+ if (type == QLatin1String("QVariant")) {
+ m_stream << " " << type << " " << property.name << "() const" << Qt::endl;
+ m_stream << " {" << Qt::endl;
+ m_stream << " return propAsVariant(" << i << ");" << Qt::endl;
+ m_stream << " }" << Qt::endl;
+ } else {
+ m_stream << " " << type << " " << property.name << "() const" << Qt::endl;
+ m_stream << " {" << Qt::endl;
+ m_stream << " const QVariant variant = propAsVariant(" << i << ");"
+ << Qt::endl;
+ m_stream << " if (!variant.canConvert<" << type << ">()) {" << Qt::endl;
+ m_stream << " qWarning() << \"QtRO cannot convert the property "
+ << property.name << " to type " << type << "\";" << Qt::endl;
+ m_stream << " }" << Qt::endl;
+ m_stream << " return variant.value<" << type << " >();" << Qt::endl;
+ m_stream << " }" << Qt::endl;
+ }
+ i++;
+ if (property.modifier == ASTProperty::ReadWrite) {
+ m_stream << "" << Qt::endl;
+ m_stream << " void set" << cap(property.name) << "(" << property.type << " "
+ << property.name << ")" << Qt::endl;
+ m_stream << " {" << Qt::endl;
+ m_stream << " static int __repc_index = " << className
+ << "::staticMetaObject.indexOfProperty(\"" << property.name << "\");"
+ << Qt::endl;
+ m_stream << " QVariantList __repc_args;" << Qt::endl;
+ m_stream << " __repc_args << QVariant::fromValue(" << property.name << ");"
+ << Qt::endl;
+ m_stream << " send(QMetaObject::WriteProperty, __repc_index, __repc_args);"
+ << Qt::endl;
+ m_stream << " }" << Qt::endl;
+ }
+ m_stream << "" << Qt::endl;
+ }
+ } else if (mode == SOURCE) {
+ for (const ASTProperty &property : astClass.properties)
+ m_stream << " virtual " << typeForMode(property, mode) << " " << property.name
+ << "() const = 0;" << Qt::endl;
+ for (const ASTProperty &property : astClass.properties) {
+ if (property.modifier == ASTProperty::ReadWrite ||
+ property.modifier == ASTProperty::ReadPush ||
+ property.modifier == ASTProperty::SourceOnlySetter)
+ m_stream << " virtual void set" << cap(property.name) << "("
+ << typeForMode(property, mode) << " " << property.name << ") = 0;"
+ << Qt::endl;
+ }
+ } else {
+ for (const ASTProperty &property : astClass.properties)
+ m_stream << " " << typeForMode(property, mode) << " " << property.name
+ << "() const override { return m_"
+ << property.name << "; }" << Qt::endl;
+ for (const ASTProperty &property : astClass.properties) {
+ if (property.modifier == ASTProperty::ReadWrite ||
+ property.modifier == ASTProperty::ReadPush ||
+ property.modifier == ASTProperty::SourceOnlySetter) {
+ generateSimpleSetter(property);
+ }
+ }
+ }
+
+ if (mode != SIMPLE_SOURCE) {
+ //Next output property signals
+ if (!astClass.properties.isEmpty() || !astClass.signalsList.isEmpty()) {
+ m_stream << "" << Qt::endl;
+ m_stream << "Q_SIGNALS:" << Qt::endl;
+ for (const ASTProperty &property : astClass.properties) {
+ if (property.modifier != ASTProperty::Constant)
+ m_stream
+ << " void " << property.name << "Changed("
+ << fullyQualifiedName(astClass, className, typeForMode(property, mode))
+ << " " << property.name << ");" << Qt::endl;
+ }
+
+ const auto signalsList = transformEnumParams(astClass, astClass.signalsList,
+ className);
+ for (const ASTFunction &signal : signalsList)
+ m_stream << " void " << signal.name << "(" << signal.paramsAsString() << ");"
+ << Qt::endl;
+
+ // CONSTANT source properties still need an onChanged signal on the Replica side to
+ // update (once) when the value is initialized. Put these last, so they don't mess
+ // up the signal index order
+ for (const ASTProperty &property : astClass.properties) {
+ if (mode == REPLICA && property.modifier == ASTProperty::Constant)
+ m_stream
+ << " void " << property.name << "Changed("
+ << fullyQualifiedName(astClass, className, typeForMode(property, mode))
+ << " " << property.name << ");" << Qt::endl;
+ }
+ }
+ bool hasWriteSlots = false;
+ for (const ASTProperty &property : astClass.properties) {
+ if (property.modifier == ASTProperty::ReadPush) {
+ hasWriteSlots = true;
+ break;
+ }
+ }
+ if (hasWriteSlots || !astClass.slotsList.isEmpty()) {
+ m_stream << "" << Qt::endl;
+ m_stream << "public Q_SLOTS:" << Qt::endl;
+ for (const ASTProperty &property : astClass.properties) {
+ if (property.modifier == ASTProperty::ReadPush) {
+ const auto type = fullyQualifiedName(astClass, className, property.type);
+ if (mode != REPLICA) {
+ m_stream << " virtual void push" << cap(property.name) << "(" << type
+ << " " << property.name << ")" << Qt::endl;
+ m_stream << " {" << Qt::endl;
+ m_stream << " set" << cap(property.name) << "(" << property.name
+ << ");" << Qt::endl;
+ m_stream << " }" << Qt::endl;
+ } else {
+ m_stream << " void push" << cap(property.name) << "(" << type << " "
+ << property.name << ")" << Qt::endl;
+ m_stream << " {" << Qt::endl;
+ m_stream << " static int __repc_index = " << className
+ << "::staticMetaObject.indexOfSlot(\"push" << cap(property.name)
+ << "(" << type << ")\");" << Qt::endl;
+ m_stream << " QVariantList __repc_args;" << Qt::endl;
+ m_stream << " __repc_args << QVariant::fromValue(" << property.name
+ << ");" << Qt::endl;
+ m_stream << " send(QMetaObject::InvokeMetaMethod, __repc_index,"
+ << " __repc_args);" << Qt::endl;
+ m_stream << " }" << Qt::endl;
+ }
+ }
+ }
+ const auto slotsList = transformEnumParams(astClass, astClass.slotsList, className);
+ for (const ASTFunction &slot : slotsList) {
+ const auto returnType = fullyQualifiedName(astClass, className, slot.returnType);
+ if (mode != REPLICA) {
+ m_stream << " virtual " << returnType << " " << slot.name << "("
+ << slot.paramsAsString() << ") = 0;" << Qt::endl;
+ } else {
+ // TODO: Discuss whether it is a good idea to special-case for void here,
+ const bool isVoid = slot.returnType == QStringLiteral("void");
+
+ if (isVoid)
+ m_stream << " void " << slot.name << "(" << slot.paramsAsString()
+ << ")" << Qt::endl;
+ else
+ m_stream << " QRemoteObjectPendingReply<" << returnType << "> "
+ << slot.name << "(" << slot.paramsAsString()<< ")" << Qt::endl;
+ m_stream << " {" << Qt::endl;
+ m_stream << " static int __repc_index = " << className
+ << "::staticMetaObject.indexOfSlot(\"" << slot.name << "("
+ << slot.paramsAsString(ASTFunction::Normalized) << ")\");"
+ << Qt::endl;
+ m_stream << " QVariantList __repc_args;" << Qt::endl;
+ const auto ¶mNames = slot.paramNames();
+ if (!paramNames.isEmpty()) {
+ m_stream << " __repc_args" << Qt::endl;
+ for (const QString &name : paramNames)
+ m_stream << " << " << "QVariant::fromValue(" << name << ")"
+ << Qt::endl;
+ m_stream << " ;" << Qt::endl;
+ }
+ if (isVoid)
+ m_stream << " send(QMetaObject::InvokeMetaMethod, __repc_index,"
+ << " __repc_args);" << Qt::endl;
+ else
+ m_stream << " return QRemoteObjectPendingReply<" << returnType
+ << ">(sendWithReply(QMetaObject::InvokeMetaMethod, __repc_index,"
+ << " __repc_args));" << Qt::endl;
+ m_stream << " }" << Qt::endl;
+ }
+ }
+ }
+ } else {
+ if (!astClass.properties.isEmpty()) {
+ bool addProtected = true;
+ for (const ASTProperty &property : astClass.properties) {
+ if (property.modifier == ASTProperty::ReadOnly) {
+ if (addProtected) {
+ m_stream << "" << Qt::endl;
+ m_stream << "protected:" << Qt::endl;
+ addProtected = false;
+ }
+ generateSimpleSetter(property, false);
+ }
+ }
+ }
+ }
+
+ m_stream << "" << Qt::endl;
+ m_stream << "private:" << Qt::endl;
+
+ //Next output data members
+ if (mode == SIMPLE_SOURCE) {
+ for (const ASTProperty &property : astClass.properties)
+ m_stream << " " << typeForMode(property, SOURCE) << " " << "m_" << property.name
+ << ";" << Qt::endl;
+ }
+
+ if (mode != SIMPLE_SOURCE)
+ m_stream << " friend class QT_PREPEND_NAMESPACE(QRemoteObjectNode);" << Qt::endl;
+
+ m_stream << "};\n\n";
+ if (mode != SIMPLE_SOURCE) {
+ for (const ASTFlag &flag : astClass.flags)
+ m_stream << "Q_DECLARE_OPERATORS_FOR_FLAGS(" << className << "::" << flag.name
+ << ")\n\n";
+ }
+}
+
+void RepCodeGenerator::generateSourceAPI(const ASTClass &astClass)
+{
+ const QString className = astClass.name + QStringLiteral("SourceAPI");
+ m_stream << QStringLiteral("template <class ObjectType>") << Qt::endl;
+ m_stream << QString::fromLatin1("struct %1 : public SourceApiMap").arg(className) << Qt::endl;
+ m_stream << QStringLiteral("{") << Qt::endl;
+ if (!astClass.enums.isEmpty()) {
+ // Include enum definition in SourceAPI
+ generateDeclarationsForEnums(astClass.enums, false);
+ }
+ for (const auto &flag : astClass.flags)
+ m_stream << QLatin1String(" typedef QFlags<typename ObjectType::%1> %2;")
+ .arg(flag._enum, flag.name) << Qt::endl;
+ m_stream << QString::fromLatin1(" %1(ObjectType *object, const QString &name = "
+ "QLatin1String(\"%2\"))").arg(className, astClass.name)
+ << Qt::endl;
+ m_stream << QStringLiteral(" : SourceApiMap(), m_name(name)") << Qt::endl;
+ m_stream << QStringLiteral(" {") << Qt::endl;
+ if (!astClass.hasPointerObjects())
+ m_stream << QStringLiteral(" Q_UNUSED(object)") << Qt::endl;
+
+ const auto enumCount = astClass.enums.count();
+ const auto totalCount = enumCount + astClass.flags.count();
+ for (int i : astClass.subClassPropertyIndices) {
+ const ASTProperty &child = astClass.properties.at(i);
+ m_stream << QString::fromLatin1(" using %1_type_t = typename std::remove_pointer<"
+ "decltype(object->%1())>::type;")
+ .arg(child.name) << Qt::endl;
+ }
+ m_stream << QString::fromLatin1(" m_enums[0] = %1;").arg(totalCount) << Qt::endl;
+ for (qsizetype i = 0; i < enumCount; ++i) {
+ const auto enumerator = astClass.enums.at(i);
+ m_stream << QString::fromLatin1(" m_enums[%1] = ObjectType::staticMetaObject."
+ "indexOfEnumerator(\"%2\");")
+ .arg(i+1).arg(enumerator.name) << Qt::endl;
+ }
+ for (qsizetype i = enumCount; i < totalCount; ++i) {
+ const auto flag = astClass.flags.at(i - enumCount);
+ m_stream << QString::fromLatin1(" m_enums[%1] = ObjectType::staticMetaObject."
+ "indexOfEnumerator(\"%2\");")
+ .arg(i+1).arg(flag.name) << Qt::endl;
+ }
+ const auto propCount = astClass.properties.count();
+ m_stream << QString::fromLatin1(" m_properties[0] = %1;").arg(propCount) << Qt::endl;
+ QList<ASTProperty> onChangeProperties;
+ QList<qsizetype> propertyChangeIndex;
+ for (qsizetype i = 0; i < propCount; ++i) {
+ const ASTProperty &prop = astClass.properties.at(i);
+ const QString propTypeName =
+ fullyQualifiedName(astClass, QStringLiteral("typename ObjectType"),
+ typeForMode(prop, SOURCE));
+ m_stream << QString::fromLatin1(" m_properties[%1] = "
+ "QtPrivate::qtro_property_index<ObjectType>("
+ "&ObjectType::%2, static_cast<%3 (QObject::*)()>(nullptr)"
+ ",\"%2\");")
+ .arg(QString::number(i+1), prop.name, propTypeName)
+ << Qt::endl;
+ if (prop.modifier == prop.ReadWrite) //Make sure we have a setter function
+ m_stream << QStringLiteral(" QtPrivate::qtro_method_test<ObjectType>("
+ "&ObjectType::set%1, static_cast<void (QObject::*)(%2)>"
+ "(nullptr));")
+ .arg(cap(prop.name), propTypeName) << Qt::endl;
+ if (prop.modifier != prop.Constant) { //Make sure we have an onChange signal
+ m_stream << QStringLiteral(" QtPrivate::qtro_method_test<ObjectType>("
+ "&ObjectType::%1Changed, static_cast<void (QObject::*)()>("
+ "nullptr));")
+ .arg(prop.name) << Qt::endl;
+ onChangeProperties << prop;
+ propertyChangeIndex << i + 1; //m_properties[0] is the count, so index is one higher
+ }
+ }
+ const auto signalCount = astClass.signalsList.count();
+ const auto changedCount = onChangeProperties.size();
+ m_stream << QString::fromLatin1(" m_signals[0] = %1;")
+ .arg(signalCount+onChangeProperties.size()) << Qt::endl;
+ for (qsizetype i = 0; i < changedCount; ++i)
+ m_stream
+ << QString::fromLatin1(" m_signals[%1] = QtPrivate::qtro_signal_index"
+ "<ObjectType>(&ObjectType::%2Changed, static_cast<void"
+ "(QObject::*)(%3)>(nullptr),m_signalArgCount+%4,"
+ "&m_signalArgTypes[%4]);")
+ .arg(QString::number(i+1), onChangeProperties.at(i).name,
+ fullyQualifiedName(astClass,
+ QStringLiteral("typename ObjectType"),
+ typeForMode(onChangeProperties.at(i),
+ SOURCE)),
+ QString::number(i))
+ << Qt::endl;
+
+ QList<ASTFunction> signalsList = transformEnumParams(astClass, astClass.signalsList,
+ QStringLiteral("typename ObjectType"));
+ for (qsizetype i = 0; i < signalCount; ++i) {
+ const ASTFunction &sig = signalsList.at(i);
+ m_stream << QString::fromLatin1(" m_signals[%1] = QtPrivate::qtro_signal_index"
+ "<ObjectType>(&ObjectType::%2, static_cast<void "
+ "(QObject::*)(%3)>(nullptr),m_signalArgCount+%4,"
+ "&m_signalArgTypes[%4]);")
+ .arg(QString::number(changedCount+i+1), sig.name,
+ sig.paramsAsString(ASTFunction::Normalized),
+ QString::number(changedCount+i))
+ << Qt::endl;
+ }
+ const auto slotCount = astClass.slotsList.count();
+ QList<ASTProperty> pushProps;
+ for (const ASTProperty &property : astClass.properties) {
+ if (property.modifier == ASTProperty::ReadPush)
+ pushProps << property;
+ }
+ const auto pushCount = pushProps.count();
+ const auto methodCount = slotCount + pushCount;
+ m_stream << QString::fromLatin1(" m_methods[0] = %1;").arg(methodCount) << Qt::endl;
+ const QString objType = QStringLiteral("typename ObjectType::");
+ for (qsizetype i = 0; i < pushCount; ++i) {
+ const ASTProperty &prop = pushProps.at(i);
+ const QString propTypeName = fullyQualifiedName(astClass,
+ QStringLiteral("typename ObjectType"),
+ prop.type);
+ m_stream <<
+ QString::fromLatin1(" m_methods[%1] = QtPrivate::qtro_method_index"
+ "<ObjectType>(&ObjectType::push%2, static_cast<void "
+ "(QObject::*)(%3)>(nullptr),\"push%2(%4)\","
+ "m_methodArgCount+%5,&m_methodArgTypes[%5]);")
+ .arg(QString::number(i+1), cap(prop.name), propTypeName,
+ // we don't want "typename ObjectType::" in the signature
+ QString(propTypeName).remove(objType),
+ QString::number(i))
+ << Qt::endl;
+ }
+
+ QList<ASTFunction> slotsList = transformEnumParams(astClass, astClass.slotsList,
+ QStringLiteral("typename ObjectType"));
+ for (qsizetype i = 0; i < slotCount; ++i) {
+ const ASTFunction &slot = slotsList.at(i);
+ const QString params = slot.paramsAsString(ASTFunction::Normalized);
+ m_stream << QString::fromLatin1(" m_methods[%1] = QtPrivate::qtro_method_index"
+ "<ObjectType>(&ObjectType::%2, static_cast<void "
+ "(QObject::*)(%3)>(nullptr),\"%2(%4)\","
+ "m_methodArgCount+%5,&m_methodArgTypes[%5]);")
+ .arg(QString::number(i+pushCount+1), slot.name, params,
+ // we don't want "typename ObjectType::" in the signature
+ QString(params).remove(objType),
+ QString::number(i+pushCount))
+ << Qt::endl;
+ }
+ for (const auto &model : astClass.modelMetadata) {
+ const ASTProperty &property = astClass.properties.at(model.propertyIndex);
+ m_stream << QString::fromLatin1(" m_models << ModelInfo({object->%1(),")
+ .arg(property.name) << Qt::endl;
+ m_stream << QString::fromLatin1(" QStringLiteral(\"%1\"),")
+ .arg(property.name) << Qt::endl;
+ QStringList list;
+ if (!model.roles.isEmpty()) {
+ for (auto role : model.roles)
+ list << role.name;
+ }
+ m_stream <<
+ QString::fromLatin1(" QByteArrayLiteral(\"%1\")});")
+ .arg(list.join(QChar::fromLatin1('|'))) << Qt::endl;
+ }
+ for (int i : astClass.subClassPropertyIndices) {
+ const ASTProperty &child = astClass.properties.at(i);
+ m_stream <<
+ QString::fromLatin1(" m_subclasses << new %2SourceAPI<%1_type_t>(object->%1(),"
+ " QStringLiteral(\"%1\"));")
+ .arg(child.name, child.type) << Qt::endl;
+ }
+ m_stream << QStringLiteral(" }") << Qt::endl;
+ m_stream << QStringLiteral("") << Qt::endl;
+ m_stream << QString::fromLatin1(" QString name() const override { return m_name; }")
+ << Qt::endl;
+ m_stream << QString::fromLatin1(" QString typeName() const override { "
+ "return QStringLiteral(\"%1\"); }")
+ .arg(astClass.name) << Qt::endl;
+ m_stream << QStringLiteral(" int enumCount() const override { return m_enums[0]; }")
+ << Qt::endl;
+ m_stream <<
+ QStringLiteral(" int propertyCount() const override { return m_properties[0]; }")
+ << Qt::endl;
+ m_stream << QStringLiteral(" int signalCount() const override { return m_signals[0]; }")
+ << Qt::endl;
+ m_stream << QStringLiteral(" int methodCount() const override { return m_methods[0]; }")
+ << Qt::endl;
+ m_stream << QStringLiteral(" int sourceEnumIndex(int index) const override") << Qt::endl;
+ m_stream << QStringLiteral(" {") << Qt::endl;
+ m_stream << QStringLiteral(" if (index < 0 || index >= m_enums[0])") << Qt::endl;
+ m_stream << QStringLiteral(" return -1;") << Qt::endl;
+ m_stream << QStringLiteral(" return m_enums[index+1];") << Qt::endl;
+ m_stream << QStringLiteral(" }") << Qt::endl;
+ m_stream << QStringLiteral(" int sourcePropertyIndex(int index) const override")
+ << Qt::endl;
+ m_stream << QStringLiteral(" {") << Qt::endl;
+ m_stream << QStringLiteral(" if (index < 0 || index >= m_properties[0])") << Qt::endl;
+ m_stream << QStringLiteral(" return -1;") << Qt::endl;
+ m_stream << QStringLiteral(" return m_properties[index+1];") << Qt::endl;
+ m_stream << QStringLiteral(" }") << Qt::endl;
+ m_stream << QStringLiteral(" int sourceSignalIndex(int index) const override") << Qt::endl;
+ m_stream << QStringLiteral(" {") << Qt::endl;
+ m_stream << QStringLiteral(" if (index < 0 || index >= m_signals[0])") << Qt::endl;
+ m_stream << QStringLiteral(" return -1;") << Qt::endl;
+ m_stream << QStringLiteral(" return m_signals[index+1];") << Qt::endl;
+ m_stream << QStringLiteral(" }") << Qt::endl;
+ m_stream << QStringLiteral(" int sourceMethodIndex(int index) const override") << Qt::endl;
+ m_stream << QStringLiteral(" {") << Qt::endl;
+ m_stream << QStringLiteral(" if (index < 0 || index >= m_methods[0])") << Qt::endl;
+ m_stream << QStringLiteral(" return -1;") << Qt::endl;
+ m_stream << QStringLiteral(" return m_methods[index+1];") << Qt::endl;
+ m_stream << QStringLiteral(" }") << Qt::endl;
+ if (signalCount+changedCount > 0) {
+ m_stream << QStringLiteral(" int signalParameterCount(int index) const override")
+ << Qt::endl;
+ m_stream << QStringLiteral(" {") << Qt::endl;
+ m_stream << QStringLiteral(" if (index < 0 || index >= m_signals[0])") << Qt::endl;
+ m_stream << QStringLiteral(" return -1;") << Qt::endl;
+ m_stream << QStringLiteral(" return m_signalArgCount[index];") << Qt::endl;
+ m_stream << QStringLiteral(" }") << Qt::endl;
+ m_stream << QStringLiteral(" int signalParameterType(int sigIndex, int paramIndex) "
+ "const override") << Qt::endl;
+ m_stream << QStringLiteral(" {") << Qt::endl;
+ m_stream << QStringLiteral(" if (sigIndex < 0 || sigIndex >= m_signals[0] || "
+ "paramIndex < 0 || paramIndex >= m_signalArgCount[sigIndex])")
+ << Qt::endl;
+ m_stream << QStringLiteral(" return -1;") << Qt::endl;
+ m_stream << QStringLiteral(" return m_signalArgTypes[sigIndex][paramIndex];")
+ << Qt::endl;
+ m_stream << QStringLiteral(" }") << Qt::endl;
+ } else {
+ m_stream << QStringLiteral(" int signalParameterCount(int index) const override "
+ "{ Q_UNUSED(index) return -1; }") << Qt::endl;
+ m_stream << QStringLiteral(" int signalParameterType(int sigIndex, int paramIndex) "
+ "const override") << Qt::endl;
+ m_stream << QStringLiteral(" { Q_UNUSED(sigIndex) Q_UNUSED(paramIndex) return -1; }")
+ << Qt::endl;
+ }
+ if (methodCount > 0) {
+ m_stream << QStringLiteral(" int methodParameterCount(int index) const override")
+ << Qt::endl;
+ m_stream << QStringLiteral(" {") << Qt::endl;
+ m_stream << QStringLiteral(" if (index < 0 || index >= m_methods[0])") << Qt::endl;
+ m_stream << QStringLiteral(" return -1;") << Qt::endl;
+ m_stream << QStringLiteral(" return m_methodArgCount[index];") << Qt::endl;
+ m_stream << QStringLiteral(" }") << Qt::endl;
+ m_stream << QStringLiteral(" int methodParameterType(int methodIndex, int paramIndex) "
+ "const override") << Qt::endl;
+ m_stream << QStringLiteral(" {") << Qt::endl;
+ m_stream <<
+ QStringLiteral(" if (methodIndex < 0 || methodIndex >= m_methods[0] || "
+ "paramIndex < 0 || paramIndex >= m_methodArgCount[methodIndex])")
+ << Qt::endl;
+ m_stream << QStringLiteral(" return -1;") << Qt::endl;
+ m_stream << QStringLiteral(" return m_methodArgTypes[methodIndex][paramIndex];")
+ << Qt::endl;
+ m_stream << QStringLiteral(" }") << Qt::endl;
+ } else {
+ m_stream << QStringLiteral(" int methodParameterCount(int index) const override { "
+ "Q_UNUSED(index) return -1; }") << Qt::endl;
+ m_stream << QStringLiteral(" int methodParameterType(int methodIndex, int paramIndex) "
+ "const override") << Qt::endl;
+ m_stream <<
+ QStringLiteral(" { Q_UNUSED(methodIndex) Q_UNUSED(paramIndex) return -1; }")
+ << Qt::endl;
+ }
+ //propertyIndexFromSignal method
+ m_stream << QStringLiteral(" int propertyIndexFromSignal(int index) const override")
+ << Qt::endl;
+ m_stream << QStringLiteral(" {") << Qt::endl;
+ if (!propertyChangeIndex.isEmpty()) {
+ m_stream << QStringLiteral(" switch (index) {") << Qt::endl;
+ for (int i = 0; i < propertyChangeIndex.size(); ++i)
+ m_stream << QString::fromLatin1(" case %1: return m_properties[%2];")
+ .arg(i).arg(propertyChangeIndex.at(i)) << Qt::endl;
+ m_stream << QStringLiteral(" }") << Qt::endl;
+ } else
+ m_stream << QStringLiteral(" Q_UNUSED(index)") << Qt::endl;
+ m_stream << QStringLiteral(" return -1;") << Qt::endl;
+ m_stream << QStringLiteral(" }") << Qt::endl;
+ //propertyRawIndexFromSignal method
+ m_stream << QStringLiteral(" int propertyRawIndexFromSignal(int index) const override")
+ << Qt::endl;
+ m_stream << QStringLiteral(" {") << Qt::endl;
+ if (!propertyChangeIndex.isEmpty()) {
+ m_stream << QStringLiteral(" switch (index) {") << Qt::endl;
+ for (int i = 0; i < propertyChangeIndex.size(); ++i)
+ m_stream << QString::fromLatin1(" case %1: return %2;").arg(i)
+ .arg(propertyChangeIndex.at(i)-1) << Qt::endl;
+ m_stream << QStringLiteral(" }") << Qt::endl;
+ } else
+ m_stream << QStringLiteral(" Q_UNUSED(index)") << Qt::endl;
+ m_stream << QStringLiteral(" return -1;") << Qt::endl;
+ m_stream << QStringLiteral(" }") << Qt::endl;
+
+ //signalSignature method
+ m_stream << QStringLiteral(" const QByteArray signalSignature(int index) const override")
+ << Qt::endl;
+ m_stream << QStringLiteral(" {") << Qt::endl;
+ if (signalCount+changedCount > 0) {
+ m_stream << QStringLiteral(" switch (index) {") << Qt::endl;
+ for (int i = 0; i < changedCount; ++i) {
+ const ASTProperty &prop = onChangeProperties.at(i);
+ if (isClassEnum(astClass, prop.type))
+ m_stream <<
+ QString::fromLatin1(" case %1: return QByteArrayLiteral(\"%2"
+ "Changed($1)\").replace(\"$1\", "
+ "QtPrivate::qtro_enum_signature<ObjectType>(\"%3\"));")
+ .arg(QString::number(i), prop.name, prop.type)
+ << Qt::endl;
+ else
+ m_stream <<
+ QString::fromLatin1(" case %1: return QByteArrayLiteral(\"%2"
+ "Changed(%3)\");")
+ .arg(QString::number(i), prop.name,
+ typeForMode(prop, SOURCE))
+ << Qt::endl;
+ }
+ for (int i = 0; i < signalCount; ++i)
+ {
+ const ASTFunction &sig = astClass.signalsList.at(i);
+ auto paramsAsString = sig.paramsAsString(ASTFunction::Normalized);
+ const auto paramsAsList = paramsAsString.split(QLatin1String(","));
+ int enumCount = 0;
+ QString enumString;
+ for (int j = 0; j < paramsAsList.count(); j++) {
+ auto const p = paramsAsList.at(j);
+ if (isClassEnum(astClass, p)) {
+ paramsAsString.replace(paramsAsString.indexOf(p), p.size(),
+ QStringLiteral("$%1").arg(enumCount));
+ enumString.append(QString::fromLatin1(".replace(\"$%1\", QtPrivate::"
+ "qtro_enum_signature<ObjectType>"
+ "(\"%2\"))")
+ .arg(enumCount++)
+ .arg(paramsAsList.at(j)));
+ }
+ }
+ m_stream <<
+ QString::fromLatin1(" case %1: return QByteArrayLiteral(\"%2(%3)\")%4;")
+ .arg(QString::number(i+changedCount), sig.name,
+ paramsAsString, enumString) << Qt::endl;
+ }
+ m_stream << QStringLiteral(" }") << Qt::endl;
+ } else
+ m_stream << QStringLiteral(" Q_UNUSED(index)") << Qt::endl;
+ m_stream << QStringLiteral(" return QByteArrayLiteral(\"\");") << Qt::endl;
+ m_stream << QStringLiteral(" }") << Qt::endl;
+
+ //signalParameterNames method
+ m_stream <<
+ QStringLiteral(" QByteArrayList signalParameterNames(int index) const override")
+ << Qt::endl;
+ m_stream << QStringLiteral(" {") << Qt::endl;
+ m_stream << QStringLiteral(" if (index < 0 || index >= m_signals[0])") << Qt::endl;
+ m_stream << QStringLiteral(" return QByteArrayList();") << Qt::endl;
+ m_stream << QStringLiteral(" return ObjectType::staticMetaObject.method(m_signals["
+ "index + 1]).parameterNames();") << Qt::endl;
+ m_stream << QStringLiteral(" }") << Qt::endl;
+
+ //methodSignature method
+ m_stream << QStringLiteral(" const QByteArray methodSignature(int index) const override")
+ << Qt::endl;
+ m_stream << QStringLiteral(" {") << Qt::endl;
+ if (methodCount > 0) {
+ m_stream << QStringLiteral(" switch (index) {") << Qt::endl;
+ for (int i = 0; i < pushCount; ++i)
+ {
+ const ASTProperty &prop = pushProps.at(i);
+ if (isClassEnum(astClass, prop.type))
+ m_stream << QString::fromLatin1(" case %1: return QByteArrayLiteral(\"push"
+ "%2($1)\").replace(\"$1\", QtPrivate::"
+ "qtro_enum_signature<ObjectType>(\"%3\"));")
+ .arg(QString::number(i), prop.name, prop.type)
+ << Qt::endl;
+ else
+ m_stream <<
+ QString::fromLatin1(" case %1: return QByteArrayLiteral(\"push"
+ "%2(%3)\");")
+ .arg(QString::number(i), cap(prop.name), prop.type)
+ << Qt::endl;
+ }
+ for (int i = 0; i < slotCount; ++i)
+ {
+ const ASTFunction &slot = astClass.slotsList.at(i);
+ auto paramsAsString = slot.paramsAsString(ASTFunction::Normalized);
+ const auto paramsAsList = paramsAsString.split(QLatin1String(","));
+ int enumCount = 0;
+ QString enumString;
+ for (int j = 0; j < paramsAsList.count(); j++) {
+ auto const p = paramsAsList.at(j);
+ if (isClassEnum(astClass, p)) {
+ paramsAsString.replace(paramsAsString.indexOf(p), p.size(),
+ QStringLiteral("$%1").arg(enumCount));
+ enumString.append(QString::fromLatin1(".replace(\"$%1\", QtPrivate::"
+ "qtro_enum_signature<ObjectType>"
+ "(\"%2\"))")
+ .arg(enumCount++)
+ .arg(paramsAsList.at(j)));
+ }
+ }
+ m_stream << QString::fromLatin1(" case %1: return QByteArrayLiteral(\"%2(%3)"
+ "\")%4;")
+ .arg(QString::number(i+pushCount), slot.name,
+ paramsAsString, enumString) << Qt::endl;
+ }
+ m_stream << QStringLiteral(" }") << Qt::endl;
+ } else
+ m_stream << QStringLiteral(" Q_UNUSED(index)") << Qt::endl;
+ m_stream << QStringLiteral(" return QByteArrayLiteral(\"\");") << Qt::endl;
+ m_stream << QStringLiteral(" }") << Qt::endl;
+
+ //methodType method
+ m_stream << QStringLiteral(" QMetaMethod::MethodType methodType(int) const override")
+ << Qt::endl;
+ m_stream << QStringLiteral(" {") << Qt::endl;
+ m_stream << QStringLiteral(" return QMetaMethod::Slot;") << Qt::endl;
+ m_stream << QStringLiteral(" }") << Qt::endl;
+
+ //methodParameterNames method
+ m_stream <<
+ QStringLiteral(" QByteArrayList methodParameterNames(int index) const override")
+ << Qt::endl;
+ m_stream << QStringLiteral(" {") << Qt::endl;
+ m_stream << QStringLiteral(" if (index < 0 || index >= m_methods[0])") << Qt::endl;
+ m_stream << QStringLiteral(" return QByteArrayList();") << Qt::endl;
+ m_stream << QStringLiteral(" return ObjectType::staticMetaObject.method(m_methods["
+ "index + 1]).parameterNames();") << Qt::endl;
+ m_stream << QStringLiteral(" }") << Qt::endl;
+
+ //typeName method
+ m_stream << QStringLiteral(" const QByteArray typeName(int index) const override")
+ << Qt::endl;
+ m_stream << QStringLiteral(" {") << Qt::endl;
+ if (methodCount > 0) {
+ m_stream << QStringLiteral(" switch (index) {") << Qt::endl;
+ for (int i = 0; i < pushCount; ++i)
+ {
+ m_stream <<
+ QString::fromLatin1(" case %1: return QByteArrayLiteral(\"void\");")
+ .arg(QString::number(i)) << Qt::endl;
+ }
+ for (int i = 0; i < slotCount; ++i)
+ {
+ const ASTFunction &slot = astClass.slotsList.at(i);
+ if (isClassEnum(astClass, slot.returnType))
+ m_stream <<
+ QString::fromLatin1(" case %1: return QByteArrayLiteral(\"$1\")"
+ ".replace(\"$1\", QtPrivate::qtro_enum_signature"
+ "<ObjectType>(\"%2\"));")
+ .arg(QString::number(i+pushCount), slot.returnType)
+ << Qt::endl;
+ else
+ m_stream <<
+ QString::fromLatin1(" case %1: return QByteArrayLiteral(\"%2\");")
+ .arg(QString::number(i+pushCount), slot.returnType) << Qt::endl;
+ }
+ m_stream << QStringLiteral(" }") << Qt::endl;
+ } else
+ m_stream << QStringLiteral(" Q_UNUSED(index)") << Qt::endl;
+ m_stream << QStringLiteral(" return QByteArrayLiteral(\"\");") << Qt::endl;
+ m_stream << QStringLiteral(" }") << Qt::endl;
+
+ //objectSignature method
+ m_stream <<
+ QStringLiteral(" QByteArray objectSignature() const override { return QByteArray{\"")
+ << QLatin1String(classSignature(astClass))
+ << QStringLiteral("\"}; }") << Qt::endl;
+
+ m_stream << QStringLiteral("") << Qt::endl;
+ m_stream << QString::fromLatin1(" int m_enums[%1];").arg(totalCount + 1) << Qt::endl;
+ m_stream << QString::fromLatin1(" int m_properties[%1];").arg(propCount+1) << Qt::endl;
+ m_stream << QString::fromLatin1(" int m_signals[%1];").arg(signalCount+changedCount+1)
+ << Qt::endl;
+ m_stream << QString::fromLatin1(" int m_methods[%1];").arg(methodCount+1) << Qt::endl;
+ m_stream << QString::fromLatin1(" const QString m_name;") << Qt::endl;
+ if (signalCount+changedCount > 0) {
+ m_stream << QString::fromLatin1(" int m_signalArgCount[%1];")
+ .arg(signalCount+changedCount) << Qt::endl;
+ m_stream << QString::fromLatin1(" const int* m_signalArgTypes[%1];")
+ .arg(signalCount+changedCount) << Qt::endl;
+ }
+ if (methodCount > 0) {
+ m_stream << QString::fromLatin1(" int m_methodArgCount[%1];").arg(methodCount)
+ << Qt::endl;
+ m_stream << QString::fromLatin1(" const int* m_methodArgTypes[%1];").arg(methodCount)
+ << Qt::endl;
+ }
+ m_stream << QStringLiteral("};") << Qt::endl;
+ m_stream << "" << Qt::endl;
+}
+
+QT_END_NAMESPACE
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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 with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef REPCODEGENERATOR_H
+#define REPCODEGENERATOR_H
+
+#include "repparser.h"
+
+#include <QList>
+#include <QSet>
+#include <QString>
+#include <QTextStream>
+
+QT_BEGIN_NAMESPACE
+
+class QIODevice;
+
+class RepCodeGenerator
+{
+public:
+ enum Mode
+ {
+ REPLICA,
+ SOURCE,
+ SIMPLE_SOURCE,
+ MERGED
+ };
+
+ RepCodeGenerator(QIODevice *outputDevice, const AST &ast);
+
+ void generate(Mode mode, QString fileName);
+
+ QByteArray classSignature(const ASTClass &ac);
+private:
+ void generateHeader(Mode mode);
+ QString generateMetaTypeRegistration(const QSet<QString> &metaTypes);
+ QString generateMetaTypeRegistrationForPending(const QSet<QString> &metaTypes);
+
+ void generateSimpleSetter(const ASTProperty &property, bool generateOverride = true);
+ void generatePOD(const POD &pod);
+ void generateEnumGadget(const ASTEnum &en, const QString &className);
+ void generateDeclarationsForEnums(const QList<ASTEnum> &enums, bool generateQENUM=true);
+ QString formatQPropertyDeclarations(const POD &pod);
+ QString formatConstructors(const POD &pod);
+ QString formatPropertyGettersAndSetters(const POD &pod);
+ QString formatSignals(const POD &pod);
+ QString formatDataMembers(const POD &pod);
+ QString formatDebugOperator(const POD &pod);
+ QString formatMarshallingOperators(const POD &pod);
+ QString typeForMode(const ASTProperty &property, Mode mode);
+
+ void generateClass(Mode mode, const ASTClass &astClasses,
+ const QString &metaTypeRegistrationCode);
+ void generateSourceAPI(const ASTClass &astClass);
+
+private:
+ QTextStream m_stream;
+ AST m_ast;
+};
+
+QT_END_NAMESPACE
+
+#endif
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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 with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <qjsonvalue.h>
+#include <qjsonarray.h>
+#include <qjsonobject.h>
+
+#include "utils.h"
+#include "repparser.h"
+
+
+#define _(X) QLatin1String(X)
+
+QT_BEGIN_NAMESPACE
+
+namespace JSON
+{
+ enum Types {
+ Any,
+ Array,
+ Object,
+ String,
+ Bool
+ };
+
+ static QJsonValue _Sub(const QJsonValue &json, const char *key, JSON::Types type=JSON::Any) {
+ if (json.isUndefined())
+ qCritical() << "Invalid metadata json file. Unexpected Undefined value when looking for key:" << key;
+ if (!json.isObject())
+ qCritical() << "Invalid metadata json file. Input (" << json << ") is not an object when looking for key:" << key;
+ QJsonValue value = json.toObject()[_(key)];
+ switch (type) {
+ case JSON::Any: break;
+ case JSON::Array:
+ if (!value.isArray())
+ qCritical() << "Invalid metadata json file. Value (" << value << ") is not an array when looking for key:" << key;
+ break;
+ case JSON::Object:
+ if (!value.isObject())
+ qCritical() << "Invalid metadata json file. Value (" << value << ") is not an object when looking for key:" << key;
+ break;
+ case JSON::String:
+ if (!value.isString())
+ qCritical() << "Invalid metadata json file. Value (" << value << ") is not a string when looking for key:" << key;
+ break;
+ case JSON::Bool:
+ if (!value.isBool())
+ qCritical() << "Invalid metadata json file. Value (" << value << ") is not a bool when looking for key:" << key;
+ break;
+ }
+ return value;
+ }
+
+ static bool _Contains(const QJsonValue &json, const char *key) {
+ if (json.isUndefined())
+ qCritical() << "Invalid metadata json file. Unexpected Undefined value when looking for key:" << key;
+ if (!json.isObject())
+ qCritical() << "Invalid metadata json file. Input (" << json << ") is not an object when looking for key:" << key;
+ return json.toObject().contains(_(key));
+ }
+
+ static bool _Empty(const QJsonValue &json, const char *key) {
+ if (!_Contains(json, key))
+ return true;
+ const auto value = _Sub(json, key);
+ if (!value.isArray())
+ qCritical() << "Invalid metadata json file." << key << "is not an array.";
+ return value.toArray().count() == 0;
+ }
+
+ static QJsonArray _Array(const QJsonValue &json, const char *key) { return _Sub(json, key, JSON::Array).toArray(); }
+ static QString _String(const QJsonValue &json, const char *key) { return _Sub(json, key, JSON::String).toString(); }
+ static QByteArray _Bytes(const QJsonValue &json, const char *key) { return _Sub(json, key, JSON::String).toString().toLatin1(); }
+ static bool _Bool(const QJsonValue &json, const char *key) { return _Sub(json, key, JSON::Bool).toBool(); }
+ static bool _Bool(const QJsonValue &json, const char *key, bool missingValue) {
+ if (!_Contains(json, key))
+ return missingValue;
+ bool res = _Bool(json, key);
+ return res;
+ }
+}
+
+using namespace JSON;
+
+static QByteArray join(const QByteArrayList &array, const QByteArray &separator)
+{
+ QByteArray res;
+ const auto sz = array.size();
+ if (!sz)
+ return res;
+ for (qsizetype i = 0; i < sz - 1; i++)
+ res += array.at(i) + separator;
+ res += array.at(sz - 1);
+ return res;
+}
+
+static QByteArrayList generateProperties(const QJsonArray &properties, bool isPod=false)
+{
+ QByteArrayList ret;
+ for (const QJsonValue prop : properties) {
+ if (!isPod && !_Contains(prop, "notify") && !_Bool(prop, "constant")) {
+ qWarning() << "Skipping property" << _String(prop, "name") << "because it is non-notifiable & non-constant";
+ continue; // skip non-notifiable properties
+ }
+ QByteArray output = _Bytes(prop, "type") + " " + _Bytes(prop, "name");
+ if (_Bool(prop, "constant"))
+ output += " CONSTANT";
+ if (!_Contains(prop, "write") && _Contains(prop, "read."))
+ output += " READONLY";
+ ret << output;
+ }
+ return ret;
+}
+
+static QByteArray generateFunctions(const QByteArray &type, const QJsonArray &functions)
+{
+ QByteArray ret;
+ for (const QJsonValue func : functions) {
+ ret += type + "(" + _Bytes(func, "returnType") + " " + _Bytes(func, "name") + "(";
+ const auto arguments = _Array(func, "arguments");
+ for (const QJsonValue arg : arguments)
+ ret += _Bytes(arg, "type") + " " + _Bytes(arg, "name") + ", ";
+ if (arguments.count())
+ ret.chop(2);
+ ret += "));\n";
+ }
+ return ret;
+}
+
+const auto filterNotPublic = [](const QJsonValue &value) {
+ return _String(value, "access") != QStringLiteral("public"); };
+
+static QJsonArray cleanedSignalList(const QJsonValue &cls)
+{
+ if (_Empty(cls, "signals"))
+ return QJsonArray();
+
+ auto signalList = _Array(cls, "signals");
+ if (_Empty(cls, "properties"))
+ return signalList;
+
+ const auto props = _Array(cls, "properties");
+ const auto filterNotify = [&props](const QJsonValue &value) {
+ const auto filter = [&value](const QJsonValue &prop) {
+ return _Sub(value, "name") == _Sub(prop, "notify"); };
+ return std::find_if(props.begin(), props.end(), filter) != props.end(); };
+ for (auto it = signalList.begin(); it != signalList.end(); /* blank */ ) {
+ if (filterNotify(*it))
+ it = signalList.erase(it);
+ else if (filterNotPublic(*it))
+ it = signalList.erase(it);
+ else
+ it++;
+ }
+ return signalList;
+}
+
+static QJsonArray cleanedSlotList(const QJsonValue &cls)
+{
+ if (_Empty(cls, "slots"))
+ return QJsonArray();
+
+ auto slotList = _Array(cls, "slots");
+ if (!_Empty(cls, "properties"))
+ return slotList;
+
+ const auto props = _Array(cls, "properties");
+ const auto filterWrite = [&props](const QJsonValue &value) {
+ const auto filter = [&value](const QJsonValue &prop) {
+ const auto args = _Array(prop, "arguments");
+ return _Sub(value, "name") == _Sub(prop, "write") &&
+ args.count() == 1 && _Sub(args.at(0), "type") == _Sub(prop, "type"); };
+ return std::find_if(props.begin(), props.end(), filter) != props.end(); };
+ for (auto it = slotList.begin(); it != slotList.end(); /* blank */ ) {
+ if (filterWrite(*it))
+ it = slotList.erase(it);
+ else if (filterNotPublic(*it))
+ it = slotList.erase(it);
+ else
+ it++;
+ }
+ return slotList;
+}
+
+QByteArray generateClass(const QJsonValue &cls, bool alwaysGenerateClass)
+{
+ if (_Bool(cls, "gadget", false) || alwaysGenerateClass ||
+ (_Empty(cls, "signals") && _Empty(cls, "slots")))
+ return "POD " + _Bytes(cls, "className") + "(" + join(generateProperties(_Array(cls, "properties"), true), ", ") + ")\n";
+
+ QByteArray ret("class " + _Bytes(cls, "className") + "\n{\n");
+ if (!_Empty(cls, "properties"))
+ ret += " PROP(" + join(generateProperties(_Array(cls, "properties")), ");\n PROP(") + ");\n";
+ ret += generateFunctions(" SLOT", cleanedSlotList(cls));
+ ret += generateFunctions(" SIGNAL", cleanedSignalList(cls));
+ ret += "}\n";
+ return ret;
+}
+
+static QList<PODAttribute> propertyList2PODAttributes(const QJsonArray &list)
+{
+ QList<PODAttribute> ret;
+ for (const QJsonValue prop : list)
+ ret.push_back(PODAttribute(_String(prop, "type"), _String(prop, "name")));
+ return ret;
+}
+
+QList<ASTProperty> propertyList2AstProperties(const QJsonArray &list)
+{
+ QList<ASTProperty> ret;
+ for (const QJsonValue property : list) {
+ if (!_Contains(property, "notify") && !_Bool(property, "constant")) {
+ qWarning() << "Skipping property" << _String(property, "name") << "because it is non-notifiable & non-constant";
+ continue; // skip non-notifiable properties
+ }
+ ASTProperty prop;
+ prop.name = _String(property, "name");
+ prop.type = _String(property, "type");
+ prop.modifier = _Bool(property, "constant")
+ ? ASTProperty::Constant
+ : !_Contains(property, "write") && _Contains(property, "read")
+ ? ASTProperty::ReadOnly
+ : ASTProperty::ReadWrite;
+ ret.push_back(prop);
+ }
+ return ret;
+}
+
+QList<ASTFunction> functionList2AstFunctionList(const QJsonArray &list)
+{
+ QList<ASTFunction> ret;
+ for (const QJsonValue function : list) {
+ ASTFunction func;
+ func.name = _String(function, "name");
+ func.returnType = _String(function, "returnType");
+ const auto arguments = _Array(function, "arguments");
+ for (const QJsonValue arg : arguments)
+ func.params.push_back(ASTDeclaration(_String(arg, "type"), _String(arg, "name")));
+ ret.push_back(func);
+ }
+ return ret;
+}
+
+AST classList2AST(const QJsonArray &classes)
+{
+ AST ret;
+ for (const QJsonValue cls : classes) {
+ if (_Empty(cls, "signals") && _Empty(cls, "slots")) {
+ POD pod;
+ pod.name = _String(cls, "className");
+ pod.attributes = propertyList2PODAttributes(_Array(cls, "properties"));
+ ret.pods.push_back(pod);
+ } else {
+ ASTClass cl(_String(cls, "className"));
+ cl.properties = propertyList2AstProperties(_Array(cls, "properties"));
+ cl.signalsList = functionList2AstFunctionList(cleanedSignalList(cls));
+ cl.slotsList = functionList2AstFunctionList(cleanedSlotList(cls));
+ ret.classes.push_back(cl);
+ }
+ }
+ return ret;
+}
+
+QT_END_NAMESPACE
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2017 Ford Motor Company
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtRemoteObjects module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** 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 with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef UTILS_H
+#define UTILS_H
+
+#include <QByteArray>
+
+QT_BEGIN_NAMESPACE
+class QJsonValue;
+class QJsonArray;
+struct AST;
+
+QByteArray generateClass(const QJsonValue &cls, bool alwaysGenerateClass = false);
+AST classList2AST(const QJsonArray &classes);
+QT_END_NAMESPACE
+
+#endif // UTILS_H
--- /dev/null
+TEMPLATE = subdirs
+qtConfig(commandlineparser): {
+ SUBDIRS += repc
+}