diff --git a/LICENSE.PREVIEW.COMMERCIAL b/LICENSE.PREVIEW.COMMERCIAL deleted file mode 100644 index 5e5aeb6913..0000000000 --- a/LICENSE.PREVIEW.COMMERCIAL +++ /dev/null @@ -1,626 +0,0 @@ -TECHNOLOGY PREVIEW LICENSE AGREEMENT - -For individuals and/or legal entities resident in the Americas (North -America, Central America and South America), the applicable licensing -terms are specified under the heading "Technology Preview License -Agreement: The Americas". - -For individuals and/or legal entities not resident in The Americas, the -applicable licensing terms are specified under the heading "Technology -Preview License Agreement: Rest of the World". - - -TECHNOLOGY PREVIEW LICENSE AGREEMENT: The Americas -Agreement version 2.4 - -This Technology Preview License Agreement ("Agreement")is a legal agreement -between The Qt Company USA, Inc. ("The Qt Company"), with its registered -office at 2350 Mission College Blvd., Suite 1020, Santa Clara, California -95054, U.S.A. and you (either an individual or a legal entity) ("Licensee") -for the Licensed Software (as defined below). - -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. - -"Applications" shall mean Licensee's software products created using the -Licensed Software which may include portions of the Licensed Software. - -"Term" shall mean the period of time six (6) months from the later of -(a) the Effective Date; or (b) the date the Licensed Software was -initially delivered to Licensee by The Qt Company. If no specific Effective -Date is set forth in the Agreement, the Effective Date shall be deemed to be -the date the Licensed Software was initially delivered to Licensee. - -"Licensed Software" shall mean the computer software, "online" or -electronic documentation, associated media and printed materials, -including the source code, example programs and the documentation -delivered by The Qt Company to Licensee in conjunction with this Agreement. - -"Party" or "Parties" shall mean Licensee and/or The Qt Company. - - -2. OWNERSHIP - -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. - -If Licensee provides any findings, proposals, suggestions or other -feedback ("Feedback") to The Qt Company regarding the Licensed Software, -The Qt Company shall own all right, title and interest including the -intellectual property rights in and to such Feedback, excluding however any -existing patent rights of Licensee. To the extent Licensee owns or controls -any patents for such Feedback Licensee hereby grants to The Qt Company and its -Affiliates, a worldwide, perpetual, non-transferable, sublicensable, -royalty-free license to (i) use, copy and modify Feedback and to create -derivative works thereof, (ii) to make (and have made), use, import, -sell, offer for sale, lease, dispose, offer for disposal or otherwise -exploit any products or services of The Qt Company containing Feedback, and -(iii) sublicense all the foregoing rights to third party licensees and -customers of The Qt Company and/or its Affiliates. - - -3. VALIDITY OF THE AGREEMENT - -By installing, copying, or otherwise using the Licensed Software, -Licensee agrees to be bound by the terms of this Agreement. If Licensee -does not agree to the terms of this Agreement, Licensee may not install, -copy, or otherwise use the Licensed Software. Upon Licensee's acceptance -of the terms and conditions of this Agreement, The Qt Company grants Licensee -the right to use the Licensed Software in the manner provided below. - - -4. LICENSES - -4.1. Using and Copying - -The Qt Company grants to Licensee a non-exclusive, non-transferable, -time-limited license to use and copy the Licensed Software for sole purpose -of designing, developing and testing Applications, and evaluating and the -Licensed Software during the Term. - -Licensee may install copies of the Licensed Software on an unlimited -number of computers provided that (a) if an individual, only such -individual; or (b) if a legal entity only its employees; use the -Licensed Software for the authorized purposes. - -4.2 No Distribution or Modifications - -Licensee may not disclose, modify, sell, market, commercialise, -distribute, loan, rent, lease, or license the Licensed Software or any -copy of it or use the Licensed Software for any purpose that is not -expressly granted in this Section 4. Licensee may not alter or remove -any details of ownership, copyright, trademark or other property right -connected with the Licensed Software. Licensee may not distribute any -software statically or dynamically linked with the Licensed Software. - -4.3 No Technical Support - -The Qt Company has no obligation to furnish Licensee with any technical -support whatsoever. Any such support is subject to separate agreement between -the Parties. - - -5. PRE-RELEASE CODE -The Licensed Software contains pre-release code that is not at the level -of performance and compatibility of a final, generally available, -product offering. The Licensed Software may not operate correctly and -may be substantially modified prior to the first commercial product -release, if any. The Qt Company is not obligated to make this or any later -version of the Licensed Software commercially available. The License -Software is "Not for Commercial Use" and may only be used for the -purposes described in Section 4. The Licensed Software may not be used -in a live operating environment where it may be relied upon to perform -in the same manner as a commercially released product or with data that -has not been sufficiently backed up. - -6. THIRD PARTY SOFTWARE - -The Licensed Software may provide links to third party libraries or code -(collectively "Third Party Software") to implement various functions. -Third Party Software does not comprise part of the Licensed Software. In -some cases, access to Third Party Software may be included along with -the Licensed Software delivery as a convenience for development and -testing only. Such source code and libraries may be listed in the -".../src/3rdparty" source tree delivered with the Licensed Software or -documented in the Licensed Software where the Third Party Software is -used, as may be amended from time to time, do not comprise the Licensed -Software. Licensee acknowledges (1) that some part of Third Party -Software may require additional licensing of copyright and patents from -the owners of such, and (2) that distribution of any of the Licensed -Software referencing any portion of a Third Party Software may require -appropriate licensing from such third parties. - - -7. LIMITED WARRANTY AND WARRANTY DISCLAIMER - -The Licensed Software is licensed to Licensee "as is". To the maximum -extent permitted by applicable law, The Qt Company on behalf of itself and -its suppliers, disclaims all warranties and conditions, either express or -implied, including, but not limited to, implied warranties of -merchantability, fitness for a particular purpose, title and -non-infringement with regard to the Licensed Software. - - -8. LIMITATION OF LIABILITY - -If, The Qt Company's warranty disclaimer notwithstanding, The Qt Company is -held liable to Licensee, whether in contract, tort or any other legal theory, -based on the Licensed Software, The Qt Company's entire liability to Licensee -and Licensee's exclusive remedy shall be, at The Qt Company's option, either -(A) return of the price Licensee paid for the Licensed Software, or (B) -repair or replacement of the Licensed Software, provided Licensee -returns to The Qt Company all copies of the Licensed Software as originally -delivered to Licensee. The Qt Company shall not under any circumstances be -liable to Licensee based on failure of the Licensed Software if the failure -resulted from accident, abuse or misapplication, nor shall The Qt Company -under any circumstances be liable for special damages, punitive or exemplary -damages, damages for loss of profits or interruption of business or for -loss or corruption of data. Any award of damages from The Qt Company to -Licensee shall not exceed the total amount Licensee has paid to The Qt -Company in connection with this Agreement. - - -9. CONFIDENTIALITY - -Each party acknowledges that during the Term of this Agreement it shall -have access to 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 (the -"Confidential Information"). Accordingly, when a party (the "Receiving -Party") receives Confidential Information from another party (the -"Disclosing Party"), the Receiving Party shall, and shall obligate its -employees and agents and employees and agents of its Affiliates to: (i) -maintain the Confidential Information in strict 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. - -"Confidential Information" shall not include information that (a) is or -becomes generally known to the public through no act or omission of the -Receiving Party; (b) was in the Receiving Party's lawful possession -prior to the disclosure hereunder and was not subject to limitations on -disclosure or use; (c) is developed by the Receiving Party without -access to the Confidential Information of the Disclosing Party or by -persons who have not had access to the Confidential Information of the -Disclosing Party as proven by the written records of the Receiving -Party; (d) is lawfully disclosed to the Receiving Party without -restrictions, by a third party not under an obligation of -confidentiality; or (e) the Receiving Party is legally compelled to -disclose the information, in which case the Receiving Party shall assert -the privileged and confidential nature of the information and cooperate -fully with the Disclosing Party to protect against and prevent -disclosure of any Confidential Information and to limit the scope of -disclosure and the dissemination of disclosed Confidential Information -by all legally available means. - -The obligations of the Receiving Party under this Section shall continue -during the Initial Term and for a period of five (5) years after -expiration or termination of this Agreement. To the extent that the -terms of the Non-Disclosure Agreement between The Qt Company and Licensee -conflict with the terms of this Section 9, this Section 9 shall be -controlling over the terms of the Non-Disclosure Agreement. - - -10. GENERAL PROVISIONS - -10.1 No Assignment - -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. - -10.2 Termination - -The Qt Company may terminate the Agreement at any time immediately upon -written notice by The Qt Company to Licensee if Licensee breaches this -Agreement. - -Upon termination of this Agreement, Licensee shall return to The Qt Company -all copies of Licensed Software that were supplied by The Qt Company. All -other copies of Licensed Software in the possession or control of Licensee -must be erased or destroyed. An officer of Licensee must promptly -deliver to The Qt Company a written confirmation that this has occurred. - -10.3 Surviving Sections - -Any terms and conditions that by their nature or otherwise reasonably -should survive a cancellation or termination of this Agreement shall -also be deemed to survive. Such terms and conditions include, but are -not limited to the following Sections: 2, 5, 6, 7, 8, 9, 10.2, 10.3, 10.4, -10.5, 10.6, 10.7, and 10.8 of this Agreement. - -10.4 Entire Agreement - -This Agreement constitutes 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, with the exception of the -non-disclosure agreement executed by the parties in connection with this -Agreement ("Non-Disclosure Agreement"), if any, shall be subject to -Section 9. 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 shall -apply unless expressly accepted by The Qt Company in writing. If any -provision of the Agreement is found void or unenforceable, the remainder -shall remain valid and enforceable according to its terms. If any remedy -provided is determined to have failed for its essential purpose, all -limitations of liability and exclusions of damages set forth in this -Agreement shall remain in effect. - -10.5 Export Control - -Licensee acknowledges that the Licensed Software may be subject to -export control restrictions of various countries. Licensee shall fully -comply with all applicable export license restrictions and requirements -as well as with all laws and regulations relating to the importation of -the Licensed Software 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 Licensed Software., - -10.6 Governing Law and Legal Venue - -This Agreement shall be governed by and construed in accordance with the -federal laws of the United States of America and the internal laws of -the State of New York without given effect to any choice of law rule -that would result in the application of the laws of any other -jurisdiction. The United Nations Convention on Contracts for the -International Sale of Goods (CISG) shall not apply. Each Party (a) -hereby irrevocably submits itself to and consents to the jurisdiction of -the United States District Court for the Southern District of New York -(or if such court lacks jurisdiction, the state courts of the State of -New York) for the purposes of any action, claim, suit or proceeding -between the Parties in connection with any controversy, claim, or -dispute arising out of or relating to this Agreement; and (b) hereby -waives, and agrees not to assert by way of motion, as a defense or -otherwise, in any such action, claim, suit or proceeding, any claim that -is not personally subject to the jurisdiction of such court(s), that the -action, claim, suit or proceeding is brought in an inconvenient forum or -that the venue of the action, claim, suit or proceeding is improper. -Notwithstanding the foregoing, nothing in this Section 9.6 is intended -to, or shall be deemed to, constitute a submission or consent to, or -selection of, jurisdiction, forum or venue for any action for patent -infringement, whether or not such action relates to this Agreement. - -10.7 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. - -10.8 Government End Users - -A "U.S. Government End User" shall mean any agency or entity of the -government of the United States. The following shall apply if Licensee -is a U.S. Government End User. The Licensed Software is a "commercial -item," as that term is defined in 48 C.F.R. 2.101 (Oct. 1995), -consisting of "commercial computer software" and "commercial computer -software documentation," as such terms are used in 48 C.F.R. 12.212 -(Sept. 1995). Consistent with 48 C.F.R. 12.212 and 48 C.F.R. 227.7202-1 -through 227.7202-4 (June 1995), all U.S. Government End Users acquire -the Licensed Software with only those rights set forth herein. The -Licensed Software (including related documentation) is provided to U.S. -Government End Users: (a) only as a commercial end item; and (b) only -pursuant to this Agreement. - - - - - -TECHNOLOGY PREVIEW LICENSE AGREEMENT: Rest of the World -Agreement version 2.4 - -This Technology Preview License Agreement ("Agreement") is a legal -agreement between The Qt Company Ltd ("The Qt Company"), with its registered -office at Valimotie 21,FI-00380 Helsinki, Finland and you (either an -individual or a legal entity) ("Licensee") for the Licensed Software. - -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. - -"Applications" shall mean Licensee's software products created using the -Licensed Software which may include portions of the Licensed Software. - -"Term" shall mean the period of time six (6) months from the later of -(a) the Effective Date; or (b) the date the Licensed Software was -initially delivered to Licensee by The Qt Company. If no specific Effective -Date is set forth in the Agreement, the Effective Date shall be deemed to be -the date the Licensed Software was initially delivered to Licensee. - -"Licensed Software" shall mean the computer software, "online" or -electronic documentation, associated media and printed materials, -including the source code, example programs and the documentation -delivered by The Qt Company to Licensee in conjunction with this Agreement. - -"Party" or "Parties" shall mean Licensee and/or The Qt Company. - - -2. OWNERSHIP - -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. - -If Licensee provides any findings, proposals, suggestions or other -feedback ("Feedback") to The Qt Company regarding the Licensed Software, -The Qt Companyshall own all right, title and interest including the -intellectual property rights in and to such Feedback, excluding however any -existing patent rights of Licensee. To the extent Licensee owns or controls -any patents for such Feedback Licensee hereby grants to The Qt Company and -its Affiliates, a worldwide, perpetual, non-transferable, sublicensable, -royalty-free license to (i) use, copy and modify Feedback and to create -derivative works thereof, (ii) to make (and have made), use, import, -sell, offer for sale, lease, dispose, offer for disposal or otherwise -exploit any products or services of The Qt Company containing Feedback, and -(iii) sublicense all the foregoing rights to third party licensees and -customers of The Qt Company and/or its Affiliates. - -3. VALIDITY OF THE AGREEMENT - -By installing, copying, or otherwise using the Licensed Software, -Licensee agrees to be bound by the terms of this Agreement. If Licensee -does not agree to the terms of this Agreement, Licensee may not install, -copy, or otherwise use the Licensed Software. Upon Licensee's acceptance -of the terms and conditions of this Agreement, The Qt Company grants Licensee -the right to use the Licensed Software in the manner provided below. - - -4. LICENSES - -4.1. Using and Copying - -The Qt Company grants to Licensee a non-exclusive, non-transferable, -time-limited license to use and copy the Licensed Software for sole purpose -of designing, developing and testing Applications, and evaluating and the -Licensed Software during the Term. - -Licensee may install copies of the Licensed Software on an unlimited -number of computers provided that (a) if an individual, only such -individual; or (b) if a legal entity only its employees; use the -Licensed Software for the authorized purposes. - -4.2 No Distribution or Modifications - -Licensee may not disclose, modify, sell, market, commercialise, -distribute, loan, rent, lease, or license the Licensed Software or any -copy of it or use the Licensed Software for any purpose that is not -expressly granted in this Section 4. Licensee may not alter or remove -any details of ownership, copyright, trademark or other property right -connected with the Licensed Software. Licensee may not distribute any -software statically or dynamically linked with the Licensed Software. - -4.3 No Technical Support - -The Qt Company has no obligation to furnish Licensee with any technical -support whatsoever. Any such support is subject to separate agreement -between the Parties. - - -5. PRE-RELEASE CODE - -The Licensed Software contains pre-release code that is not at the level -of performance and compatibility of a final, generally available, -product offering. The Licensed Software may not operate correctly and -may be substantially modified prior to the first commercial product -release, if any. The Qt Company is not obligated to make this or any later -version of the Licensed Software commercially available. The License -Software is "Not for Commercial Use" and may only be used for the -purposes described in Section 4. The Licensed Software may not be used -in a live operating environment where it may be relied upon to perform -in the same manner as a commercially released product or with data that -has not been sufficiently backed up. - -6. THIRD PARTY SOFTWARE - -The Licensed Software may provide links to third party libraries or code -(collectively "Third Party Software") to implement various functions. -Third Party Software does not comprise part of the Licensed Software. In -some cases, access to Third Party Software may be included along with -the Licensed Software delivery as a convenience for development and -testing only. Such source code and libraries may be listed in the -".../src/3rdparty" source tree delivered with the Licensed Software or -documented in the Licensed Software where the Third Party Software is -used, as may be amended from time to time, do not comprise the Licensed -Software. Licensee acknowledges (1) that some part of Third Party -Software may require additional licensing of copyright and patents from -the owners of such, and (2) that distribution of any of the Licensed -Software referencing any portion of a Third Party Software may require -appropriate licensing from such third parties. - - -7. LIMITED WARRANTY AND WARRANTY DISCLAIMER - -The Licensed Software is licensed to Licensee "as is". To the maximum -extent permitted by applicable law, The Qt Company on behalf of itself and -its suppliers, disclaims all warranties and conditions, either express or -implied, including, but not limited to, implied warranties of -merchantability, fitness for a particular purpose, title and -non-infringement with regard to the Licensed Software. - - -8. LIMITATION OF LIABILITY - -If, The Qt Company's warranty disclaimer notwithstanding, The Qt Company is -held liable to Licensee, whether in contract, tort or any other legal theory, -based on the Licensed Software, The Qt Company's entire liability to Licensee -and Licensee's exclusive remedy shall be, at The Qt Company's option, either -(A) return of the price Licensee paid for the Licensed Software, or (B) -repair or replacement of the Licensed Software, provided Licensee -returns to The Qt Company all copies of the Licensed Software as originally -delivered to Licensee. The Qt Company shall not under any circumstances be -liable to Licensee based on failure of the Licensed Software if the failure -resulted from accident, abuse or misapplication, nor shall The Qt Company -under any circumstances be liable for special damages, punitive or exemplary -damages, damages for loss of profits or interruption of business or for -loss or corruption of data. Any award of damages from The Qt Company to -Licensee shall not exceed the total amount Licensee has paid to -The Qt Company in connection with this Agreement. - - -9. CONFIDENTIALITY - -Each party acknowledges that during the Term of this Agreement it shall -have access to 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 (the -"Confidential Information"). Accordingly, when a party (the "Receiving -Party") receives Confidential Information from another party (the -"Disclosing Party"), the Receiving Party shall, and shall obligate its -employees and agents and employees and agents of its Affiliates to: (i) -maintain the Confidential Information in strict 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. - -"Confidential Information" shall not include information that (a) is or -becomes generally known to the public through no act or omission of the -Receiving Party; (b) was in the Receiving Party's lawful possession -prior to the disclosure hereunder and was not subject to limitations on -disclosure or use; (c) is developed by the Receiving Party without -access to the Confidential Information of the Disclosing Party or by -persons who have not had access to the Confidential Information of the -Disclosing Party as proven by the written records of the Receiving -Party; (d) is lawfully disclosed to the Receiving Party without -restrictions, by a third party not under an obligation of -confidentiality; or (e) the Receiving Party is legally compelled to -disclose the information, in which case the Receiving Party shall assert -the privileged and confidential nature of the information and cooperate -fully with the Disclosing Party to protect against and prevent -disclosure of any Confidential Information and to limit the scope of -disclosure and the dissemination of disclosed Confidential Information -by all legally available means. - -The obligations of the Receiving Party under this Section shall continue -during the Initial Term and for a period of five (5) years after -expiration or termination of this Agreement. To the extent that the -terms of the Non-Disclosure Agreement between The Qt Company and Licensee -conflict with the terms of this Section 9, this Section 9 shall be -controlling over the terms of the Non-Disclosure Agreement. - - -10. GENERAL PROVISIONS - -10.1 No Assignment - -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. - -10.2 Termination - -The Qt Company may terminate the Agreement at any time immediately upon -written notice by The Qt Company to Licensee if Licensee breaches this -Agreement. - -Upon termination of this Agreement, Licensee shall return to The Qt Company -all copies of Licensed Software that were supplied by The Qt Company. All -other copies of Licensed Software in the possession or control of Licensee -must be erased or destroyed. An officer of Licensee must promptly -deliver to The Qt Company a written confirmation that this has occurred. - -10.3 Surviving Sections - -Any terms and conditions that by their nature or otherwise reasonably -should survive a cancellation or termination of this Agreement shall -also be deemed to survive. Such terms and conditions include, but are -not limited to the following Sections: 2, 5, 6, 7, 8, 9, 10.2, 10.3, 10.4, -10.5, 10.6, 10.7, and 10.8 of this Agreement. - -10.4 Entire Agreement - -This Agreement constitutes 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, with the exception of the -non-disclosure agreement executed by the parties in connection with this -Agreement ("Non-Disclosure Agreement"), if any, shall be subject to -Section 9. 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 shall -apply unless expressly accepted by The Qt Company in writing. If any provision -of the Agreement is found void or unenforceable, the remainder shall remain -valid and enforceable according to its terms. If any remedy provided is -determined to have failed for its essential purpose, all limitations of -liability and exclusions of damages set forth in this Agreement shall -remain in effect. - -10.5 Export Control - -Licensee acknowledges that the Licensed Software may be subject to -export control restrictions of various countries. Licensee shall fully -comply with all applicable export license restrictions and requirements -as well as with all laws and regulations relating to the importation of -the Licensed Software 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 Licensed Software., - -10.6 Governing Law and Legal Venue - -This Agreement shall be construed and interpreted in accordance with the laws -of Finland, excluding its choice of law provisions. Any disputes arising out -of or relating to this Agreement shall be resolved in arbitration in accordance -with the Arbitration Rules of the Finland 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. - -10.7 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. - -10.8 Government End Users - -A "U.S. Government End User" shall mean any agency or entity of the -government of the United States. The following shall apply if Licensee -is a U.S. Government End User. The Licensed Software is a "commercial -item," as that term is defined in 48 C.F.R. 2.101 (Oct. 1995), -consisting of "commercial computer software" and "commercial computer -software documentation," as such terms are used in 48 C.F.R. 12.212 -(Sept. 1995). Consistent with 48 C.F.R. 12.212 and 48 C.F.R. 227.7202-1 -through 227.7202-4 (June 1995), all U.S. Government End Users acquire -the Licensed Software with only those rights set forth herein. The -Licensed Software (including related documentation) is provided to U.S. -Government End Users: (a) only as a commercial end item; and (b) only -pursuant to this Agreement. - diff --git a/LICENSE.QT-LICENSE-AGREEMENT-4.0 b/LICENSE.QT-LICENSE-AGREEMENT-4.0 new file mode 100644 index 0000000000..74bd6bb41c --- /dev/null +++ b/LICENSE.QT-LICENSE-AGREEMENT-4.0 @@ -0,0 +1,913 @@ +QT LICENSE AGREEMENT +Agreement version 4.0 + +This License Agreement ("Agreement") is a legal agreement between The Qt +Company (as defined below) and the Licensee (as defined below) for the license +of Licensed Software (as defined below). 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; and + +(B). The Qt Company is willing to grant the Licensee a right to use Licensed +Software for such purpose pursuant to term and conditions of this 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. + +"Applications" shall mean Licensee's software products created using the +Licensed Software, which may include the Redistributables, or part +thereof. + +"Contractor(s)" shall mean third party consultants, distributors and +contractors performing services to a Party under applicable contractual +arrangement. + +"Customer(s)" shall mean Licensee's end users to whom Licensee, directly or +indirectly, distributes copies of the Redistributables. + +"Deployment Platforms" shall mean operating systems specified in the License +Certificate, in 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 for Licensee and on +behalf of Licensee. Designated Users shall be named in the License Certificate. + +"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 Platforms" shall mean those operating systems specified in the +License Certificate, in which the Licensed Software can be used under the +Development License, but not distributed in any form or used for any other +purpose. + +"Devices" shall mean hardware devices or products that 1) are manufactured +and/or distributed by the Licensee or its Affiliates or Contractors, and +(2)(i) incorporate or integrate the Redistributables or parts thereof; or (ii) +do not incorporate or integrate the Redistributables at the time of +distribution, but where, when used by a Customer, the main user interface or +substantial functionality of such device is provided by Application(s) or +otherwise depends on the Licensed Software. + +"Distribution License(s)" shall mean the license required for distribution of +Redistributables in connection with Devices pursuant to license grant described +in Section 3.3 of this Agreement. + +"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 hereto, +as the case may be. + +"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. +License Certificate will be available under respective Designated User's Qt +Account at account.qt.io and it will specify the Designated User, the +Development Platforms, Deployment Platforms and the License Term. The terms of +the License Certificate are considered part of this Agreement and shall be +updated from time to time to reflect any agreed changes to the foregoing terms +relating to Designated User's rights to the Licensed Software. + +"License Fee" shall mean the fee charged to the Licensee for rights granted +under the terms of this Agreement. + +"License Term" shall mean the agreed validity period of the Development +License of the respective Designated User, during which time the +Designated User is entitled to use the Licensed Software, as set forth in the +respective License Certificate. + +"Licensed Software" shall mean all versions of the + +(i) Qt Toolkit (including Qt Essentials, Qt Add-Ons and Value-Add modules) as +described in http://doc.qt.io/qt-5/qtmodules.html, + +(ii) Qt Creator (including Creator IDE tool) as described in +http://doc.qt.io/qtcreator/index.html, + +(iii) Qt 3D Studio as described in http://doc.qt.io/qt3dstudio/index.html, and + +as well as corresponding online or electronic documentation, associated media +and printed materials, including the source code, example programs and the +documentation, licensed to the Licensee under this Agreement. Licensed Software +does not include Third Party Software (as defined in Section 4), Open Source +Qt, or other software products of The Qt Company (for example Qt Safe Renderer +and Qt for Automation), unless such other software products of The Qt Company +are separately agreed in writing to be included in scope of the Licensed +Software. + +"Licensee" shall mean the individual or legal entity that is party to this +Agreement, as identified on the signature page hereof. + +"Licensee's Records" shall mean books and records that are likely to contain +information bearing on Licensee's compliance with this Agreement or the +payments due to The Qt Company under this Agreement, including, but not limited +to: 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 the non-commercial Qt computer software products, +licensed 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 nor governed under +this Agreement. + +"Party" or "Parties" shall mean Licensee and/or The Qt Company. + +"Redistributables" shall mean the portions of the Licensed Software set forth +in Appendix 1, Section 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 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 The Qt Company's standard support terms and as further +defined in Section 8 hereunder. + +"Taxes" shall have the meaning set forth in Section 10.5. + +"Term" shall have the meaning set forth in Section 12. + +"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 2350 Mission College Blvd., Suite 1020, Santa Clara, CA 95054, 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 The Qt Company's Intellectual Property Rights are and shall remain the +exclusive property of The Qt Company or its licensors respectively. + +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 +personal, worldwide, non-exclusive, non-transferable license, valid for the +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 end-user Customers. + +Licensee may install copies of the Licensed Software on an unlimited number of +computers provided that (i) only the Designated Users may use the Licensed +Software, and (ii) all Designated Users must have a valid Development License +to use 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, provided that +any Designated User may be replaced only once during any six-month period. + +Upon expiry of the initially agreed License Term, the respective License Terms +shall be automatically extended to one or more Renewal Term(s), unless and +until either Party notifies the other Party in writing that it does not wish to +continue the License Term, such notification to be provided to the other Party +no less than ninety (90) days before expiry of the respective License Term. +Unless otherwise agreed between the Parties, Renewal Term shall be of equal +length with the initial Term. + +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 pricing applicable at the commencement date of any such Renewal Term. + +3.2 Distribution of Applications + +Subject to the terms of this Agreement, The Qt Company grants to Licensee a +personal, worldwide, non-exclusive, non-transferable, revocable (for cause +pursuant to this Agreement) right and license, valid for the 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 sublicenses to Redistributables, as distributed hereunder, for +Customers solely for Customer's internal use and 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 Licensee having paid +the agreed Development Licenses from The Qt Company before distributing any +Redistributables to Customers. + +3.3 Distribution of Devices + +Subject to the terms of this Agreement, The Qt Company grants to Licensee a +personal, worldwide, non-exclusive, non-transferable, revocable (for cause +pursuant to this Agreement) right and license, valid for the 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 sublicenses to Redistributables, as distributed hereunder, for +Customers solely for Customer's internal use and to the extent necessary in +order for the Customers to use the Devices for their respective intended +purposes. + +Right to distribute the Redistributables with Devices as provided herein is +conditional upon the Licensee having purchased and paid the appropriate amount +of Development and Distribution Licenses from The Qt Company before +distributing any Redistributables 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 shall not remove or alter any copyright, trademark or other +proprietary rights notice contained in any portion of the Licensed Software; + +(ii) Applications must add primary and substantial functionality to the +Licensed Software; + +(iii) 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); + +(iv) Applications must not compete with the Licensed Software; + +(v) 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) was developed using the +Licensed Software; + +(vi) 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 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; + +(vii) Licensee shall not grant the Customers a right to (i) make copies of the +Redistributables except when and to the extent required to use the Applications +and/or Devices for their intended purpose, (ii) modify the Redistributables or +create derivative works thereof, (iii) decompile, disassemble or otherwise +reverse engineer Redistributables, or (iv) redistribute any copy or portion of +the Redistributables to any third party, except as part of the onward sale of +the Device on which the Redistributables are installed; + +(viii) Licensee shall not and shall cause that its Affiliates or Contractors +shall not a) 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, or b) incorporate or integrate Applications +into a hardware device or product other than a Device, 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 +Term of a hardware device or product a) which incorporate or integrate any +part of Licensed Software or Open Source Qt; or b) where the main user +interface or substantial functionality is provided by software build with +Licensed Software or Open Source Qt or otherwise depends on the Licensed +Software or Open Source Qt, shall be considered as a Device distribution under +this Agreement and dependent on compliance thereof (including but not limited +to obligation to pay applicable License Fees for such distribution); + +(ix) Licensee shall cause all of its Affiliates and Contractors 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); + +(x) 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 + +(xi) 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. + +4. THIRD PARTY SOFTWARE + +The Licensed Software may provide links to third party libraries or code +(collectively "Third Party Software") to implement various functions. Third +Party Software does not comprise part of the Licensed Software. In some cases, +access to Third Party Software may be included in the Licensed Software. Such +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 marked or +otherwise stated as "Technology Preview", "Alpha", "Beta" or similar +designation. Such pre-release code may be present in order to provide +experimental support for new platforms or preliminary versions of one or more +new functionalities. The pre-release code may not be at the level of +performance and compatibility of a final, generally available, product +offering of the Licensed Software. The pre-release parts of the Licensed +Software 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. + +6. LIMITED WARRANTY AND WARRANTY DISCLAIMER + +The Qt Company hereby represents and warrants that it has the power and +authority to grant the rights and licenses granted to Licensee under this +Agreement. + +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. ALL USE OF AND RELIANCE ON THE LICENSED SOFTWARE IS AT THE SOLE +RISK OF AND RESPONSIBILITY OF LICENSEE. + +7. INDEMNIFICATION AND LIMITATION OF LIABILITY + +7.1 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. PARTIES +SPECIFICALLY AGREE THAT LICENSEE'S OBLIGATION TO PAY LICENSE AND OTHER FEES +CORRESPONDING TO ACTUAL USAGE OF LICENSED SOFTWARE HEREUNDER SHALL BE +CONSIDERED AS A DIRECT DAMAGE. + +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 FROM +LICENSEE DURING THE PERIOD OF TWELVE (12) MONTHS IMMEDIATELY PRECEDING THE +EVENT RESULTING IN SUCH LIABILITY. + +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. + +7.2 Licensee's Indemnification + +Licensee shall indemnify and hold harmless The Qt Company from and against any +claim, injury, judgment, settlement, loss or expense, including attorneys' fees +related to: (a) Licensee's misrepresentation in connection with The Qt Company +or the Licensed Software or breach of this Agreement, (b) the Application or +Device (except where such cause of liability is solely attributable to the +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 License +Term, provided, however, that in the event the License Term is longer than 36 +months, Support is provided only for the first 12 months, unless the Parties +specifically otherwise agree. + +Unless otherwise decided by The 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 License Term the level of Support provided by The +Qt Company 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 Term of this Agreement 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 hereto, as the case may be. + +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 and Distribution 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. + +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. + +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 installing, bundling or +integrating (all jointly "installing") the Redistributables with the Devices or +for otherwise distributing the Redistributables in accordance with this +Agreement. + +Each time Licensee "installs" or distributes a copy of Redistributables, then +one Distribution License is used, and Licensee's account of available +Distribution Licenses is decreased accordingly. + +Licensee may "install" copies of the Redistributables so long as Licensee has +Distribution Licenses remaining on its account. + +Redistributables will be deemed to have been "installed" into a Device when one +of the following circumstances shall have occurred: a) the Redistributables +have been loaded onto the Device and used outside of the Licensee's premises or +b) the Device has been fully tested and placed into Licensee's inventory +(or sold) for the first time (i.e., Licensee will not be required to use +(or pay for) more than one Distribution License for each individual Device, +e.g. in a situation where a Device is returned to Licensee's inventory after +delivery to a distributor or sale to a Customer). In addition, if Licensee +includes a back-up copy of the Redistributables on a CD-ROM or other storage +medium along with the product, that backup copy of the Redistributables will +not be deemed to have been "installed" and will not require an additional +Distribution License. + +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. + +The Qt Company shall have the right to suspend, terminate or withhold grants +of all rights to the Licensed Software hereunder, including but not limited to +the Developer License, Distribution License, and Support, should Licensee fail +to make payment in timely fashion. + +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 and other taxes, duties or +tariffs ("Taxes"). Such applicable Taxes shall be paid by Licensee, or, where +applicable, in lieu of payment of such Taxes, 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 maintain accurate and up-to-date written records of +Licensee's activities related to the use of Licensed Software and distribution +of Redistributables. The records shall be adequate to determine Licensee's +compliance with the provisions of this Agreement and to demonstrate the number +of Designated Users and Redistributables distributed by Licensee. The records +shall conform to good accounting practices reasonably acceptable to The Qt +Company. + +Licensee shall, within thirty (30) days from receiving The Qt Company's request +to that effect, deliver to The Qt Company a report on Licensee's usage of +Licensed Software, such report to copies of Redistributables distributed by +Licensee during that calendar quarter, and also detailing the number of +undistributed copies of Redistributables made by Licensee and remaining in its +account contain information, in sufficient detail, on (i) amount of users +working with Licensed Software, (ii) copies of Redistributables distributed by +Licensee during that calendar quarter, (iii) number of undistributed copies of +Redistributables and corresponding number of unused Distribution Licenses +remaining on Licensee's account, and (iv) any other information 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 five (5) business days' prior written notice and at its +expense, audit Licensee with respect to the use of the Redistributables, 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 such in-person audit shall be conducted during regular +business hours at Licensee's facilities and shall not unreasonably interfere +with Licensee's business activities. The Qt Company or the independent auditor +acting on behalf of The Qt Company shall be entitled to inspect Licensee's +Records. 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 agrees to immediately pay The +Qt Company any amounts owed for such unauthorized use. + +In addition, in the event the audit reveals a material violation of the terms +of this Agreement (underpayment of more than 5% of License Fees shall always 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 Term + +This Agreement shall enter into force upon due acceptance by both Parties and +remain in force for as long as there is any Development License(s) in force +("Term"), unless and until terminated pursuant to the terms of this Section 12. + +12.2 Termination by The Qt Company + +The Qt Company shall have the right to terminate this Agreement upon thirty +(30) days prior written notice if the Licensee is in material breach of any +obligation of this Agreement and fails to remedy such breach within such notice +period. + +12.3 Mutual Right to Terminate + +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 and distribution of the +Redistributables under this Agreement. + +Notwithstanding the above, in the event the Agreement expires or is terminated: + +(i) as a result of The Qt Company choosing not to renew the Development +License(s) as set forth in Section 3.1, then all valid 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; or + +(ii) for reason other than by The Qt Company pursuant to item (i) above or +pursuant to Section 12.2, then the Licensee is entitled, for a period of six +(6) months after the effective date of termination, to continue distribution of +Devices under the Distribution Licenses paid but unused at such effective date +of termination. + +Upon any 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 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. + +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 +shall immediately pay to The Qt Company all such fees upon the effective date +of termination. 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 in case of bankruptcy + +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) pursuant to Section 3.1, assigned to +party, who has assumed The Qt Company's position as a legitimate licensor of +Licensed Software under this Agreement, then all valid 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. + +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 shall be +finally settled by arbitration in accordance with the Arbitration Rules of +Finland 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. + +14.4 Entire Agreement + +This Agreement, the exhibits hereto, the License Certificate and any applicable +Purchase Order 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 shall apply unless expressly +accepted by The Qt Company in writing. + +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 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. + +14.11 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. + + +IN WITNESS WHEREOF, the Parties hereto, intending to be legally bound hereby, +have caused this Agreement to be executed by Licensee's authorized +representative installing the Licensed Software and accepting the terms +hereof in connection therewith. + + +Appendix 1 + +1. Parts of the Licensed Software that are permitted for distribution in +object code form only ("Redistributables") under this Agreement: + +- The Licensed Software's Qt Essentials and Qt Add-on libraries +- The Licensed Software's configuration tool ("qtconfig") +- The Licensed Software's help tool ("Qt Assistant") +- The Licensed Software's internationalization tools ("Qt Linguist", "lupdate", + "lrelease") +- The Licensed Software's QML ("Qt Quick") launcher tool ("qmlscene" or + "qmlviewer") +- The Licensed Software's installer framework + +2. Parts of the Licensed Software that are not permitted for distribution +include, but are not limited to: + +- The Licensed Software's source code and header files +- The Licensed Software's documentation +- The Licensed Software's documentation generation tool ("qdoc") +- The Licensed Software's tool for writing makefiles ("qmake") +- The Licensed Software's Meta Object Compiler ("moc") +- The Licensed Software's User Interface Compiler ("uic") +- The Licensed Software's Resource Compiler ("rcc") +- The Licensed Software's parts of the IDE tool ("Qt Creator") +- The Licensed Software's parts of the Design tools ("Qt 3D Studio" or + "Qt Quick Designer") +- The Licensed Software's Emulator diff --git a/bin/syncqt.pl b/bin/syncqt.pl index 78fe0663b5..8890b31770 100755 --- a/bin/syncqt.pl +++ b/bin/syncqt.pl @@ -84,7 +84,7 @@ $INPUT_RECORD_SEPARATOR = "\r\n" if ($^O eq "msys"); # will be defined based on the modules sync.profile our (%modules, %moduleheaders, @allmoduleheadersprivate, %classnames, %deprecatedheaders); -our @qpa_headers = (); +our (@qpa_headers, @private_headers); # will be derived from sync.profile our %reverse_classnames = (); @@ -659,6 +659,8 @@ sub loadSyncProfile { $reverse_classnames{$cn} = $fn; } } + + push @private_headers, qr/_p(ch)?\.h$/; } sub basePrettify { @@ -701,6 +703,15 @@ sub isQpaHeader return 0; } +sub isPrivateHeader +{ + my ($header) = @_; + foreach my $private_header (@private_headers) { + return 1 if ($header =~ $private_header); + } + return 0; +} + sub globosort($$) { my ($a, $b) = @_; if ($a =~ /^q(.*)global\.h$/) { @@ -1021,7 +1032,7 @@ foreach my $lib (@modules_to_sync) { if(isQpaHeader($public_header)) { $public_header = 0; $qpa_header = 1; - } elsif ($allheadersprivate || $thisprivate || $public_header =~ /_p(ch)?\.h$/) { + } elsif ($allheadersprivate || $thisprivate || isPrivateHeader($public_header)) { $public_header = 0; } diff --git a/configure.pri b/configure.pri index f75c6c211a..5200ad1342 100644 --- a/configure.pri +++ b/configure.pri @@ -72,7 +72,7 @@ defineReplace(qtConfFunc_licenseCheck) { hasOpenSource = true else: \ hasOpenSource = false - exists($$QT_SOURCE_TREE/LICENSE.PREVIEW.COMMERCIAL)|exists($$QT_SOURCE_TREE/bin/licheck*): \ + exists($$QT_SOURCE_TREE/LICENSE.QT-LICENSE-AGREEMENT-4.0): \ hasCommercial = true else: \ hasCommercial = false @@ -128,14 +128,18 @@ defineReplace(qtConfFunc_licenseCheck) { qtConfFatalError("This is the Qt Open Source Edition." \ "Cannot proceed with -commercial.") - exists($$QT_SOURCE_TREE/LICENSE.PREVIEW.COMMERCIAL) { - logn() - logn("This is the Qt Technology Preview Edition.") + !exists($$QT_SOURCE_TREE/.release-timestamp) { + # Build from git - EditionString = "Technology Preview" - config.input.qt_edition = Preview + logn() + logn("This is the Qt Commercial Edition.") + + EditionString = "Commercial" + config.input.qt_edition = Commercial export(config.input.qt_edition) } else { + # Build from a released source package + equals(QMAKE_HOST.os, Linux) { !equals(QMAKE_HOST.arch, x86_64): \ Licheck = licheck32 @@ -194,7 +198,7 @@ defineReplace(qtConfFunc_licenseCheck) { affix = either } } else { - theLicense = $$cat($$QT_SOURCE_TREE/LICENSE.PREVIEW.COMMERCIAL, lines) + theLicense = $$cat($$QT_SOURCE_TREE/LICENSE.QT-LICENSE-AGREEMENT-4.0, lines) theLicense = $$first(theLicense) showWhat = "Type '?' to view the $${theLicense}." } @@ -221,7 +225,7 @@ defineReplace(qtConfFunc_licenseCheck) { } else: equals(val, n)|equals(val, no) { return(false) } else: equals(commercial, yes):equals(val, ?) { - licenseFile = $$QT_SOURCE_TREE/LICENSE.PREVIEW.COMMERCIAL + licenseFile = $$QT_SOURCE_TREE/LICENSE.QT-LICENSE-AGREEMENT-4.0 } else: equals(commercial, no):equals(val, l) { licenseFile = $$QT_SOURCE_TREE/LICENSE.LGPL3 } else: equals(commercial, no):equals(val, g):$$gpl2Ok { diff --git a/dist/changes-5.11.1 b/dist/changes-5.11.1 new file mode 100644 index 0000000000..ed219df454 --- /dev/null +++ b/dist/changes-5.11.1 @@ -0,0 +1,144 @@ +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 + +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. + +**************************************************************************** +* Important Behavior Changes * +**************************************************************************** + + - [QTBUG-68619] In Qt 5.11.0, support for selecting a platform plugin + based on the XDG_SESSION_TYPE environment variable was added. On + gnome-shell, however, bugs—in both Qt and gnome-shell—made many + widget applications almost unusable. So until those bugs are fixed + XDG_SESSION_TYPE=wayland is now ignored on gnome-shell. + +**************************************************************************** +* Library * +**************************************************************************** + +QtCore +------ + + - Item Models: + * [QTBUG-18001] Fixed a bug that made selecting or deselecting a column if + some flags are applied to certain items. + * [QTBUG-44962][QTBUG-67948][QTBUG-68427] Fixed issues with the replacing + of the source model in QSortFilterProxyModel that could lead to empty + views or failed assertions. + + - QJsonDocument + * [QTBUG-61969] Fixed a number of bugs in the parsing of binary data + (QJson::fromRawData) that could lead to crashes or out-of-bounds access. + + - QLocale: + * On Unix, when using LANGUAGE would lose information about script or + country, without changing language, use the locale implied by LC_ALL, + LC_MESSAGES or LANG. + + - QPointF/QRectF: + * [QTBUG-60359][QTBUG-62161] Fixed an issue that led to inconsistent + comparison results for the different edges of a rectangle. + + - QProcess: + * [QTBUG-68472] On Unix, the QProcess SIGCHLD handler now restores errno + on exit. + * [QTBUG-67744] QProcess now properly reports an error state if it failed + to create the communication pipes. + + - QSharedPointer: + * [QTBUG-68300] Fixed a problem that made create() on a type with const + qualification fail to compile. + +QtNetwork +--------- + + - QNetworkCookieJar: + * [QTBUG-52040] Cookies will no longer be rejected when the domain + matches a TLD. However (to avoid problems with TLDs), such cookies are + only accepted, or sent, when the host name matches exactly. + +QtWidgets +--------- + + - [QTBUG-48325] Sending a key press event with sendEvent() now sends a + ShortCutOverride event first to the widget to trigger any shortcuts set + first. + - [QTBUG-67533] QOpenGLWidget/QQuickWidget is now respecting AlwaysStackOnTop. + - [QTBUG-60404] Fixed crash in QMacPanGestureRecognizer. + - [QTBUG-67836] Fixed input method commits that end with newline. + - [QTBUG-33855] Fixed issue with fonts in QHeaderViews + - [QTBUG-56457] Fixed margin issue related to sections in QHeaderView. + +**************************************************************************** +* Platform-specific Changes * +**************************************************************************** + +Android +------- + + - [QTBUG-68344] QTemporaryFile does not try to use O_TMPFILE any more, + to work around outdated sandbox restrictions of linkat(). This also fixes + use of QSettings and QFile::copy(). + +Linux +----- + + - [QTBUG-68586] Fixed a bug that caused QFileSystemWatcher to print a warning + if the file being watched did not exist. The class is documented to return + the list of files that it could not watch. + +macOS +----- + + - [QTBUG-60676] Fixed a bug in using QFileSystemWatcher to watch different + file paths that shared a common prefix. + +Windows +------- + + - [QTBUG-68514] Reverted a change that caused static binaries compiled + with Visual Studio 2015 to crash on start-up. Note that this does not + apply to Visual Studio 2017 static binaries, even though the crash stack + traces are very similar: with 2017, the problem is compiler regression + and requires updating to version 15.8 for the fix. + +**************************************************************************** +* Tools * +**************************************************************************** + +configure & build system +------------------------ + + - [QTBUG-68478] Fixed parallel build of examples in some modules. + +qmake +----- + + - [QTBUG-37417][CMake] Fixed missing include paths in private modules. + - [QTBUG-47325] Fixed crash when $QMAKEFEATURES contains empty paths + (e.g., due to a trailing colon). + - [QTBUG-52474][Xcode] Fixed sources being excluded from Time Machine + backups. + - [QTBUG-66462][Darwin] Fixed overriding QMAKE_TARGET_BUNDLE_PREFIX in + project files. + - [QTBUG-68705][Xcode] Fixed build directory location of app bundles. + - [Xcode] Fixed compatibility with Xcode 10 by opting out from the new + build system. + - [Darwin] Fixed .prl file lookup for suffixed frameworks. + - Fixed look-up of relative files from extra compilers' .depend_command + in shadow builds. diff --git a/dist/changes-5.9.5 b/dist/changes-5.9.5 new file mode 100644 index 0000000000..a71b09bf90 --- /dev/null +++ b/dist/changes-5.9.5 @@ -0,0 +1,122 @@ +Qt 5.9.5 is a bug-fix release. It maintains both forward and backward +compatibility (source and binary) with Qt 5.9.0 through 5.9.4. + +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.9 series is binary compatible with the 5.8.x series. +Applications compiled for 5.8 will continue to run with 5.9. + +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.9.5 Changes * +**************************************************************************** + +QtCore +------ + + - QDateTime and QLocale: + * [QTBUG-66076] Fixed a crash if the date/time parsed with Qt::ISODate and + Qt::ISODateWithMS had a 'T' for the time, but no actual time. + + - QObject: + * [QTBUG-65712] Improved performance of QObject::deleteLater. + + - QPluginLoader: + * [QTBUG-65197] Fixed a bug that would cause the Qt plugin scanning + system to allocate too much memory and possibly crash the process. + + - QStandardPaths: + * [QTBUG-65687] Fixed a memory leak with displayName() on Apple platforms. + * [QTBUG-65820] Fixed QStandardPaths::AppDataLocation on Android. + +QtGui +----- + + - Text: + * [QTBUG-61882] Fixed a bug where mixing different writing systems with + emojis could lead to missing glyphs. + * [QTBUG-65519] Fixed ZWJ and ZWNJ control characters when fallback + fonts are in use. + +QtWidgets +--------- + + - QTreeView: + * [QTBUG-65980] Fixed missing update of QTreeView on changing tree + position. + + - QLabel: + * [QTBUG-66841] Fixed crash related to deleted buddy. + + - QHeaderView: + * [QTBUG-65478] Fixed crash that could happen during layout. + * [QTBUG-66444][QTBUG-65478][QTBUG-65478] Fixed section resize settings + getting lost after layouting. + * [QTBUG-66413][QTBUG-65478] Fixed hidden section issues during layout. + * [QTBUG-65478] Fixed section restore issues after a layout change. + + - QFusionStyle: + * [QTBUG-66343] Fixed checkbox rendering regression in low DPI settings. + + - QComboBox: + * [QTBUG-55251] Fixed context menu opening up at the wrong location. + + - QFileDialog: + * Fixed regression when using QFileDialog::getOpenFileUrl() using + remote URLs. + + - QWidget: + * [QTBUG-65783] Fixed crash when platform window creation fails. + +Third-Party Code +---------------- + + - Documented use of "Unicode Character Database (UCD)" in Qt Core. + - Clarified use of "Unicode Common Local Data Repository (CLDR)" in the + documentation. Also updated SPDX license name / ID. + +Platform-specific changes +------------------------- + + - Android: + * [QTBUG-65863] Fixed the detection of which thread is the main thread on + Android. + + - Windows: + * Named pipes internally created by QProcess now contain the PID in their + name to ensure uniqueness. + + - winrt: + * -qdevel and -qdebug are removed from the command line arguments and + not passed to the application. + +**************************************************************************** +* Tools * +**************************************************************************** + +configure & build system +------------------------ + + - [QTBUG-65753] Fixed installation of example sources for qrc/rc files. + - [Windows] cl.exe is now preferred over clang-cl.exe again. + +qmake +----- + + - [QTBUG-50839][Windows] Paths starting with a (back-)slash but without + a drive letter are not considered absolute any more. + - [QTBUG-63637][MinGW] Fixed cross-compilation from Linux. + - [QTBUG-65106] Fixed complaints about missing modules in $$QT after the + project has already failed requires() (or REQUIRES=). + - [QTBUG-65477][Darwin] Bundle identifiers are now properly escaped. + - [Windows] Fixed 'make check' for executables in subdirectories. diff --git a/dist/changes-5.9.6 b/dist/changes-5.9.6 new file mode 100644 index 0000000000..29f5ec2d57 --- /dev/null +++ b/dist/changes-5.9.6 @@ -0,0 +1,46 @@ +Qt 5.9.6 is a bug-fix release. It maintains both forward and backward +compatibility (source and binary) with Qt 5.9.0 through 5.9.5. + +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.9 series is binary compatible with the 5.8.x series. +Applications compiled for 5.8 will continue to run with 5.9. + +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.9.6 Changes * +**************************************************************************** + + - This release contains only minor code improvements. + +QtCore +------ + + - [QTBUG-61159] Fixed QStandardPaths::standardLocations() returning some + incorrect paths on macOS. + - [QTBUG-57299] Fixed some issues with locking files during save using + QSaveFile if the target directory is monitored by Dropbox. + +QtWidgets +--------- + + - [QTBUG-16252] Fixed geometry not restored correctly for a dock widget + after being docked. + +qmake +----- + + - [QTBUG-52474][Xcode] Fixed sources being excluded from Time Machine + backups. + - [QTBUG-66156] $$relative_path() and $$absolute_path() now resolve + the base directory to an absolute path. diff --git a/doc/global/html-footer.qdocconf b/doc/global/html-footer.qdocconf index 9957e71f20..c0122a7c4f 100644 --- a/doc/global/html-footer.qdocconf +++ b/doc/global/html-footer.qdocconf @@ -10,10 +10,10 @@ HTML.footer = \ "

\n" \ " © 2018 The Qt Company Ltd.\n" \ " Documentation contributions included herein are the copyrights of\n" \ - " their respective owners.
" \ + " their respective owners.
" \ " The documentation provided herein is licensed under the terms of the" \ " GNU Free Documentation" \ - " License version 1.3 as published by the Free Software Foundation.
" \ + " License version 1.3 as published by the Free Software Foundation.
" \ " Qt and respective logos are trademarks of The Qt Company Ltd. " \ " in Finland and/or other countries worldwide. All other trademarks are property\n" \ " of their respective owners.

\n" \ diff --git a/examples/corelib/threads/doc/src/queuedcustomtype.qdoc b/examples/corelib/threads/doc/src/queuedcustomtype.qdoc index 015007cae1..86d5992294 100644 --- a/examples/corelib/threads/doc/src/queuedcustomtype.qdoc +++ b/examples/corelib/threads/doc/src/queuedcustomtype.qdoc @@ -28,7 +28,7 @@ /*! \example threads/queuedcustomtype \title Queued Custom Type Example - \brief Demonstrates multi-thread programming using Qt + \brief Demonstrates multi-thread programming using Qt. \ingroup qtconcurrent-mtexamples \brief The Queued Custom Type example shows how to send custom types between diff --git a/examples/corelib/threads/doc/src/semaphores.qdoc b/examples/corelib/threads/doc/src/semaphores.qdoc index ccbfcdb6e2..5293e80c0e 100644 --- a/examples/corelib/threads/doc/src/semaphores.qdoc +++ b/examples/corelib/threads/doc/src/semaphores.qdoc @@ -28,7 +28,7 @@ /*! \example threads/semaphores \title Semaphores Example - \brief Demonstrates multi-thread programming using Qt + \brief Demonstrates multi-thread programming using Qt. \ingroup qtconcurrent-mtexamples \brief The Semaphores example shows how to use QSemaphore to control diff --git a/examples/corelib/threads/doc/src/waitconditions.qdoc b/examples/corelib/threads/doc/src/waitconditions.qdoc index 5a6831ede4..cfac460345 100644 --- a/examples/corelib/threads/doc/src/waitconditions.qdoc +++ b/examples/corelib/threads/doc/src/waitconditions.qdoc @@ -28,7 +28,7 @@ /*! \example threads/waitconditions \title Wait Conditions Example - \brief Demonstrates multi-thread programming using Qt + \brief Demonstrates multi-thread programming using Qt. \ingroup qtconcurrent-mtexamples \brief The Wait Conditions example shows how to use QWaitCondition and diff --git a/examples/corelib/tools/doc/src/contiguouscache.qdoc b/examples/corelib/tools/doc/src/contiguouscache.qdoc index c2c686b237..0d06036cd1 100644 --- a/examples/corelib/tools/doc/src/contiguouscache.qdoc +++ b/examples/corelib/tools/doc/src/contiguouscache.qdoc @@ -34,7 +34,7 @@ isn't, users still dislike an application using excessive memory. Using QContiguousCache to manage a list, rather than loading the entire list into memory, allows the application to limit the amount - of memory it uses, regardless of the size of the data set it accesses + of memory it uses, regardless of the size of the data set it accesses. The simplest way to use QContiguousCache is to cache as items are requested. When a view requests an item at row N it is also likely to ask for items at rows near diff --git a/examples/dbus/doc/src/complexpingpong.qdoc b/examples/dbus/doc/src/complexpingpong.qdoc index fca654a06a..d09708c0ff 100644 --- a/examples/dbus/doc/src/complexpingpong.qdoc +++ b/examples/dbus/doc/src/complexpingpong.qdoc @@ -40,4 +40,12 @@ \include examples-run.qdocinc To run, execute the \c complexping application. + + \badcode + $ ./complexping + Ask your question: When is the next Qt release? + Reply was: Sorry, I don't know the answer + Ask your question: What is the answer to life, the universe and everything? + Reply was: 42 + \endcode */ diff --git a/examples/network/doc/src/blockingfortuneclient.qdoc b/examples/network/doc/src/blockingfortuneclient.qdoc index 6719a4e0b9..ecb9a7ba62 100644 --- a/examples/network/doc/src/blockingfortuneclient.qdoc +++ b/examples/network/doc/src/blockingfortuneclient.qdoc @@ -29,7 +29,7 @@ \example blockingfortuneclient \title Blocking Fortune Client Example \ingroup examples-network - \brief Demonstrates how to create a client for a network service + \brief Demonstrates how to create a client for a network service. \image blockingfortuneclient-example.png diff --git a/examples/network/doc/src/fortuneclient.qdoc b/examples/network/doc/src/fortuneclient.qdoc index f2ad575125..544fa156b7 100644 --- a/examples/network/doc/src/fortuneclient.qdoc +++ b/examples/network/doc/src/fortuneclient.qdoc @@ -29,7 +29,7 @@ \example fortuneclient \title Fortune Client Example \ingroup examples-network - \brief Demonstrates how to create a client for a network service + \brief Demonstrates how to create a client for a network service. This example uses QTcpSocket, and is intended to be run alongside the \l{fortuneserver}{Fortune Server} example or diff --git a/examples/network/doc/src/googlesuggest.qdoc b/examples/network/doc/src/googlesuggest.qdoc index 50cdb694ba..adb87f4b66 100644 --- a/examples/network/doc/src/googlesuggest.qdoc +++ b/examples/network/doc/src/googlesuggest.qdoc @@ -29,7 +29,7 @@ \example googlesuggest \title Google Suggest Example \ingroup examples-network - \brief Obtains the list of search recommendations by the Google search engine + \brief Obtains the list of search recommendations by the Google search engine. The example uses the QNetworkAccessManager to obtain the list of search recommendations by Google as the user types into a QLineEdit. diff --git a/examples/network/doc/src/http.qdoc b/examples/network/doc/src/http.qdoc index f4301e7d95..1a70187369 100644 --- a/examples/network/doc/src/http.qdoc +++ b/examples/network/doc/src/http.qdoc @@ -29,7 +29,7 @@ \example http \title HTTP Example \ingroup examples-network - \brief Demonstrates a simple HTTP client + \brief Demonstrates a simple HTTP client. This example demonstrates how a simple HTTP client can fetch files from remote hosts. diff --git a/examples/network/doc/src/loopback.qdoc b/examples/network/doc/src/loopback.qdoc index 189c4ee0da..f97c9f9c71 100644 --- a/examples/network/doc/src/loopback.qdoc +++ b/examples/network/doc/src/loopback.qdoc @@ -29,7 +29,7 @@ \example loopback \title Loopback Example \ingroup examples-network - \brief Demonstrates the client-server communication on a local host + \brief Demonstrates the client-server communication on a local host. The example demonstrates how the clients and servers on a local host communicate with each other. diff --git a/examples/network/doc/src/multicastreceiver.qdoc b/examples/network/doc/src/multicastreceiver.qdoc index a0579d7284..3709750436 100644 --- a/examples/network/doc/src/multicastreceiver.qdoc +++ b/examples/network/doc/src/multicastreceiver.qdoc @@ -29,7 +29,7 @@ \example multicastreceiver \title Multicast Receiver Example \ingroup examples-network - \brief Demonstrates how to receive information sent to a multicast group + \brief Demonstrates how to receive information sent to a multicast group. This example demonstrates how to receive messages sent to a multicast group \image multicastreceiver-example.png diff --git a/examples/network/doc/src/multicastsender.qdoc b/examples/network/doc/src/multicastsender.qdoc index 3adc8959ba..72558eb062 100644 --- a/examples/network/doc/src/multicastsender.qdoc +++ b/examples/network/doc/src/multicastsender.qdoc @@ -29,7 +29,7 @@ \example multicastsender \title Multicast Sender Example \ingroup examples-network - \brief Demonstrates how to send messages to a multicast group + \brief Demonstrates how to send messages to a multicast group. This example demonstrates how to send messages to the clients of a multicast group. diff --git a/examples/network/doc/src/network-chat.qdoc b/examples/network/doc/src/network-chat.qdoc index 701dc76ec3..85edf611b6 100644 --- a/examples/network/doc/src/network-chat.qdoc +++ b/examples/network/doc/src/network-chat.qdoc @@ -29,7 +29,7 @@ \example network-chat \title Network Chat Example \ingroup examples-network - \brief Demonstrates a stateful peer-to-peer Chat client + \brief Demonstrates a stateful peer-to-peer Chat client. This example uses broadcasting with QUdpSocket and QNetworkInterface to discover its peers. diff --git a/examples/network/doc/src/network-download.qdoc b/examples/network/doc/src/network-download.qdoc index e51da38ed8..9d171e4142 100644 --- a/examples/network/doc/src/network-download.qdoc +++ b/examples/network/doc/src/network-download.qdoc @@ -28,7 +28,7 @@ /*! \example download \title Network Download Example - \brief Demonstrates how to use networking APIs for multiple downloads + \brief Demonstrates how to use networking APIs for multiple downloads. \ingroup examples-network The Network Download example shows how to perform multiple downloads in diff --git a/examples/network/doc/src/network-downloadmanager.qdoc b/examples/network/doc/src/network-downloadmanager.qdoc index ca65b8e559..f89ed66616 100644 --- a/examples/network/doc/src/network-downloadmanager.qdoc +++ b/examples/network/doc/src/network-downloadmanager.qdoc @@ -28,7 +28,7 @@ /*! \example downloadmanager \title Network Download Manager Example - \brief Demonstrates how to use the networking APIs for multiple downloads + \brief Demonstrates how to use the networking APIs for multiple downloads. \ingroup examples-network The Network Download example shows how to implement a queue for multiple diff --git a/examples/network/doc/src/securesocketclient.qdoc b/examples/network/doc/src/securesocketclient.qdoc index 052e6ad868..78cfab7af4 100644 --- a/examples/network/doc/src/securesocketclient.qdoc +++ b/examples/network/doc/src/securesocketclient.qdoc @@ -29,7 +29,7 @@ \example securesocketclient \title Secure Socket Client Example \ingroup examples-network - \brief Demonstrates how to communicate over an encrypted (SSL) connection + \brief Demonstrates how to communicate over an encrypted (SSL) connection. This example uses QSslSocket to demonstrate how to communicate over an encrypted connection, deal with authenticity problems, and display security diff --git a/examples/network/doc/src/torrent.qdoc b/examples/network/doc/src/torrent.qdoc index 2ef5be8171..8d69bee6d1 100644 --- a/examples/network/doc/src/torrent.qdoc +++ b/examples/network/doc/src/torrent.qdoc @@ -29,7 +29,7 @@ \example torrent \title Torrent Example \ingroup examples-network - \brief Demonstrates complex TCP/IP operations + \brief Demonstrates complex TCP/IP operations. This example demonstrates some of the complex TCP/IP operations supported by the Qt Network APIs. diff --git a/examples/opengl/hellogles3/doc/images/hellogles3-example.png b/examples/opengl/hellogles3/doc/images/hellogles3-example.png new file mode 100644 index 0000000000..e089b9470a Binary files /dev/null and b/examples/opengl/hellogles3/doc/images/hellogles3-example.png differ diff --git a/doc/src/examples/complexpingpong.qdoc b/examples/opengl/hellogles3/doc/src/hellogles3.qdoc similarity index 63% rename from doc/src/examples/complexpingpong.qdoc rename to examples/opengl/hellogles3/doc/src/hellogles3.qdoc index 4a7cec21bb..fbe071f143 100644 --- a/doc/src/examples/complexpingpong.qdoc +++ b/examples/opengl/hellogles3/doc/src/hellogles3.qdoc @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2018 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the documentation of the Qt Toolkit. @@ -26,11 +26,21 @@ ****************************************************************************/ /*! - \example complexpingpong - \title Complex Ping Pong Example + \example hellogles3 + \title Hello GLES3 Example + \ingroup examples-widgets-opengl - The Complex Ping Pong example improves on the \l{D-Bus Ping Pong Example} by providing - a more useful demonstration of D-Bus interfaces. + \brief The Hello GLES3 example demonstrates easy, cross-platform usage of + OpenGL ES 3.0 functions via QOpenGLExtraFunctions in an application that + works identically on desktop platforms with OpenGL 3.3 and mobile/embedded + devices with OpenGL ES 3.0. - \quotefile doc/src/snippets/complexpingpong-example.txt + The code is always the same, with the exception of two places: + \list + \li The OpenGL context creation has to have a sufficiently high version + number for the features that are in use. + \li The shader code's version directive is different. + \endlist + + \image hellogles3-example.png */ diff --git a/examples/opengl/hellogles3/glwindow.cpp b/examples/opengl/hellogles3/glwindow.cpp index 13cbc41ce8..9458b74810 100644 --- a/examples/opengl/hellogles3/glwindow.cpp +++ b/examples/opengl/hellogles3/glwindow.cpp @@ -243,7 +243,8 @@ void GLWindow::initializeGL() f->glEnableVertexAttribArray(0); f->glEnableVertexAttribArray(1); f->glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), 0); - f->glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), reinterpret_cast(3 * sizeof(GLfloat))); + f->glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), + reinterpret_cast(3 * sizeof(GLfloat))); m_vbo->release(); f->glEnable(GL_DEPTH_TEST); diff --git a/examples/opengl/hellogles3/qtlogo.png b/examples/opengl/hellogles3/qtlogo.png index 868fcea860..9cb2e01d38 100644 Binary files a/examples/opengl/hellogles3/qtlogo.png and b/examples/opengl/hellogles3/qtlogo.png differ diff --git a/examples/qtconcurrent/wordcount/doc/src/qtconcurrent-wordcount.qdoc b/examples/qtconcurrent/wordcount/doc/src/qtconcurrent-wordcount.qdoc index 1b112d2966..7486340c7b 100644 --- a/examples/qtconcurrent/wordcount/doc/src/qtconcurrent-wordcount.qdoc +++ b/examples/qtconcurrent/wordcount/doc/src/qtconcurrent-wordcount.qdoc @@ -28,7 +28,7 @@ /*! \example wordcount \title QtConcurrent Word Count Example - \brief Demonstrates how to use the map-reduce algorithm + \brief Demonstrates how to use the map-reduce algorithm. \ingroup qtconcurrentexamples The QtConcurrent Word Count example demonstrates the use of the map-reduce diff --git a/examples/sql/books/bookwindow.cpp b/examples/sql/books/bookwindow.cpp index d85b438956..76f3c9da8f 100644 --- a/examples/sql/books/bookwindow.cpp +++ b/examples/sql/books/bookwindow.cpp @@ -115,6 +115,11 @@ BookWindow::BookWindow() ui.genreEdit->setModelColumn( model->relationModel(genreIdx)->fieldIndex("name")); + // Lock and prohibit resizing of the width of the rating column: + ui.bookTable->horizontalHeader()->setSectionResizeMode( + model->fieldIndex("rating"), + QHeaderView::ResizeToContents); + QDataWidgetMapper *mapper = new QDataWidgetMapper(this); mapper->setModel(model); mapper->setItemDelegate(new BookDelegate(this)); @@ -131,6 +136,7 @@ BookWindow::BookWindow() ); ui.bookTable->setCurrentIndex(model->index(0, 0)); + createMenuBar(); } void BookWindow::showError(const QSqlError &err) @@ -138,3 +144,28 @@ void BookWindow::showError(const QSqlError &err) QMessageBox::critical(this, "Unable to initialize Database", "Error initializing database: " + err.text()); } + +void BookWindow::createMenuBar() +{ + QAction *quitAction = new QAction(tr("&Quit"), this); + QAction *aboutAction = new QAction(tr("&About"), this); + QAction *aboutQtAction = new QAction(tr("&About Qt"), this); + + QMenu *fileMenu = menuBar()->addMenu(tr("&File")); + fileMenu->addAction(quitAction); + + QMenu *helpMenu = menuBar()->addMenu(tr("&Help")); + helpMenu->addAction(aboutAction); + helpMenu->addAction(aboutQtAction); + + connect(quitAction, &QAction::triggered, this, &BookWindow::close); + connect(aboutAction, &QAction::triggered, this, &BookWindow::about); + connect(aboutQtAction, &QAction::triggered, qApp, &QApplication::aboutQt); +} + +void BookWindow::about() +{ + QMessageBox::about(this, tr("About Books"), + tr("

The Books example shows how to use Qt SQL classes " + "with a model/view framework.")); +} diff --git a/examples/sql/books/bookwindow.h b/examples/sql/books/bookwindow.h index 4b2be0e729..ec6b935242 100644 --- a/examples/sql/books/bookwindow.h +++ b/examples/sql/books/bookwindow.h @@ -63,11 +63,16 @@ class BookWindow: public QMainWindow public: BookWindow(); +private slots: + void about(); + private: void showError(const QSqlError &err); Ui::BookWindow ui; QSqlRelationalTableModel *model; int authorIdx, genreIdx; + + void createMenuBar(); }; #endif diff --git a/examples/sql/books/bookwindow.ui b/examples/sql/books/bookwindow.ui index c81a86cb2c..ce8f9f933a 100644 --- a/examples/sql/books/bookwindow.ui +++ b/examples/sql/books/bookwindow.ui @@ -33,7 +33,7 @@ - Books + diff --git a/examples/vulkan/doc/src/hellovulkancubes.qdoc b/examples/vulkan/doc/src/hellovulkancubes.qdoc index 934d2015a1..8fa3243024 100644 --- a/examples/vulkan/doc/src/hellovulkancubes.qdoc +++ b/examples/vulkan/doc/src/hellovulkancubes.qdoc @@ -29,7 +29,7 @@ \example hellovulkancubes \title Hello Vulkan Cubes Example \ingroup examples-vulkan - \brief Shows the basics of using QVulkanWindow + \brief Shows the basics of using QVulkanWindow. The \e{Hello Vulkan Cubes Example} shows more advanced usage of QVulkanWindow. diff --git a/examples/vulkan/doc/src/hellovulkantexture.qdoc b/examples/vulkan/doc/src/hellovulkantexture.qdoc index d0e0ca90a8..4284e4a05c 100644 --- a/examples/vulkan/doc/src/hellovulkantexture.qdoc +++ b/examples/vulkan/doc/src/hellovulkantexture.qdoc @@ -29,7 +29,7 @@ \example hellovulkantexture \ingroup examples-vulkan \title Hello Vulkan Texture Vulkan Example - \brief Shows the basics of rendering with textures in a QVulkanWindow + \brief Shows the basics of rendering with textures in a QVulkanWindow. The \e{Hello Vulkan Texture Example} builds on \l hellovulkantriangle. Here instead of drawing a single triangle, a triangle strip is drawn in order to diff --git a/examples/vulkan/doc/src/hellovulkantriangle.qdoc b/examples/vulkan/doc/src/hellovulkantriangle.qdoc index 81af776ea1..57793cf25a 100644 --- a/examples/vulkan/doc/src/hellovulkantriangle.qdoc +++ b/examples/vulkan/doc/src/hellovulkantriangle.qdoc @@ -29,7 +29,7 @@ \example hellovulkantriangle \ingroup examples-vulkan \title Hello Vulkan Triangle Example - \brief Shows the basics of rendering with QVulkanWindow and the Vulkan API + \brief Shows the basics of rendering with QVulkanWindow and the Vulkan API. The \e{Hello Vulkan Triangle Example} builds on \l hellovulkanwindow. This time a full graphics pipeline is created, including a vertex and fragment diff --git a/examples/vulkan/doc/src/hellovulkanwidget.qdoc b/examples/vulkan/doc/src/hellovulkanwidget.qdoc index 7987bdeff9..b5ad43ba2a 100644 --- a/examples/vulkan/doc/src/hellovulkanwidget.qdoc +++ b/examples/vulkan/doc/src/hellovulkanwidget.qdoc @@ -29,7 +29,7 @@ \example hellovulkanwidget \ingroup examples-vulkan \title Hello Vulkan Widget Example - \brief Shows the usage of QVulkanWindow in QWidget applications + \brief Shows the usage of QVulkanWindow in QWidget applications. The \e{Hello Vulkan Widget Example} is a variant of \l hellovulkantriangle that embeds the QVulkanWindow into a QWidget-based user interface using diff --git a/examples/vulkan/doc/src/hellovulkanwindow.qdoc b/examples/vulkan/doc/src/hellovulkanwindow.qdoc index 06cc9c1c28..a9682b7e90 100644 --- a/examples/vulkan/doc/src/hellovulkanwindow.qdoc +++ b/examples/vulkan/doc/src/hellovulkanwindow.qdoc @@ -29,7 +29,7 @@ \example hellovulkanwindow \title Hello Vulkan Window Example \ingroup examples-vulkan - \brief Shows the basics of using QVulkanWindow + \brief Shows the basics of using QVulkanWindow. The \e{Hello Vulkan Window Example} shows the basics of using QVulkanWindow in order to display rendering with the Vulkan graphics API on systems that diff --git a/examples/widgets/doc/src/basicgraphicslayouts.qdoc b/examples/widgets/doc/src/basicgraphicslayouts.qdoc index 233b8c7c0a..23661d0558 100644 --- a/examples/widgets/doc/src/basicgraphicslayouts.qdoc +++ b/examples/widgets/doc/src/basicgraphicslayouts.qdoc @@ -29,7 +29,7 @@ \example graphicsview/basicgraphicslayouts \title Basic Graphics Layouts Example \ingroup examples-graphicsview-layout - \brief Demonstrates how to create basic graphics layout + \brief Demonstrates how to create basic graphics layout. The Basic Graphics Layouts example shows how to use the layout classes in QGraphicsView: QGraphicsLinearLayout and QGraphicsGridLayout. diff --git a/examples/widgets/doc/src/blurpicker.qdoc b/examples/widgets/doc/src/blurpicker.qdoc index 87f36389e7..d4d84f7248 100644 --- a/examples/widgets/doc/src/blurpicker.qdoc +++ b/examples/widgets/doc/src/blurpicker.qdoc @@ -29,7 +29,7 @@ \example effects/blurpicker \title Blur Picker Effect Example \ingroup examples-graphicsview-graphicseffects - \brief Demonstrates how to apply graphical effects on items in the view + \brief Demonstrates how to apply graphical effects on items in the view. \image blurpickereffect-example.png diff --git a/examples/widgets/doc/src/boxes.qdoc b/examples/widgets/doc/src/boxes.qdoc index 7c9031a003..276c6fa78d 100644 --- a/examples/widgets/doc/src/boxes.qdoc +++ b/examples/widgets/doc/src/boxes.qdoc @@ -29,7 +29,7 @@ \example graphicsview/boxes \title Boxes \ingroup examples-graphicsview - \brief Combines advanced OpenGL rendering with the Graphics View framework + \brief Combines advanced OpenGL rendering with the Graphics View framework. \image boxes-demo.png diff --git a/examples/widgets/doc/src/chip.qdoc b/examples/widgets/doc/src/chip.qdoc index 4cef4984e3..758b692f0e 100644 --- a/examples/widgets/doc/src/chip.qdoc +++ b/examples/widgets/doc/src/chip.qdoc @@ -29,7 +29,7 @@ \example graphicsview/chip \title 40000 Chips \ingroup examples-graphicsview - \brief Visualizes a huge graphic view scene with 40000 chip items + \brief Visualizes a huge graphic view scene with 40000 chip items. This examples demonstrates Graphics View's powerful navigation and interaction features, allowing you to zoom and rotate each of four diff --git a/examples/widgets/doc/src/collidingmice-example.qdoc b/examples/widgets/doc/src/collidingmice-example.qdoc index 535057bb6a..657c416218 100644 --- a/examples/widgets/doc/src/collidingmice-example.qdoc +++ b/examples/widgets/doc/src/collidingmice-example.qdoc @@ -28,7 +28,7 @@ /*! \example graphicsview/collidingmice \title Colliding Mice Example - \brief Demonstrates how to animate items on a graphics view + \brief Demonstrates how to animate items on a graphics view. \ingroup examples-graphicsview The Colliding Mice example shows how to use the Graphics View diff --git a/examples/widgets/doc/src/diagramscene.qdoc b/examples/widgets/doc/src/diagramscene.qdoc index 1c9f4faf88..ca4876f2e8 100644 --- a/examples/widgets/doc/src/diagramscene.qdoc +++ b/examples/widgets/doc/src/diagramscene.qdoc @@ -29,7 +29,7 @@ \example graphicsview/diagramscene \title Diagram Scene Example \ingroup examples-graphicsview - \brief Demonstrate how to use the Graphics View framework + \brief Demonstrate how to use the Graphics View framework. \image diagramscene.png diff --git a/examples/widgets/doc/src/dragdroprobot.qdoc b/examples/widgets/doc/src/dragdroprobot.qdoc index f74b898e1b..ac138072c9 100644 --- a/examples/widgets/doc/src/dragdroprobot.qdoc +++ b/examples/widgets/doc/src/dragdroprobot.qdoc @@ -29,7 +29,7 @@ \example graphicsview/dragdroprobot \title Drag and Drop Robot Example \ingroup examples-graphicsview - \brief Demonstrates how to drag and drop items in a graphics view + \brief Demonstrates how to drag and drop items in a graphics view. The Drag and Drop Robot example shows how to implement Drag and Drop in a QGraphicsItem subclass, as well as how to animate items using Qt's diff --git a/examples/widgets/doc/src/draggabletext.qdoc b/examples/widgets/doc/src/draggabletext.qdoc index 97b2f036bd..e934119e7a 100644 --- a/examples/widgets/doc/src/draggabletext.qdoc +++ b/examples/widgets/doc/src/draggabletext.qdoc @@ -28,7 +28,7 @@ /*! \example draganddrop/draggabletext \title Draggable Text Example - \brief Illustrates how to drag and drop text between widgets + \brief Illustrates how to drag and drop text between widgets. \brief The Draggable Text example shows how to drag and drop textual data between widgets in the same application, and between different applications. diff --git a/examples/widgets/doc/src/elasticnodes.qdoc b/examples/widgets/doc/src/elasticnodes.qdoc index 65e1195121..e78db67be2 100644 --- a/examples/widgets/doc/src/elasticnodes.qdoc +++ b/examples/widgets/doc/src/elasticnodes.qdoc @@ -29,7 +29,7 @@ \example graphicsview/elasticnodes \title Elastic Nodes Example \ingroup examples-graphicsview - \brief Demonstrates how to interact with graphical items in a scene + \brief Demonstrates how to interact with graphical items in a scene. The Elastic Nodes example shows how to implement edges between nodes in a graph, with basic interaction. You can click to drag a node around, and diff --git a/examples/widgets/doc/src/embeddeddialogs.qdoc b/examples/widgets/doc/src/embeddeddialogs.qdoc index 0775c58807..0b31e01e0c 100644 --- a/examples/widgets/doc/src/embeddeddialogs.qdoc +++ b/examples/widgets/doc/src/embeddeddialogs.qdoc @@ -29,7 +29,7 @@ \example graphicsview/embeddeddialogs \title Embedded Dialogs \ingroup examples-graphicsview-layout - \brief Demonstrates how to embed dialogs into a graphics view + \brief Demonstrates how to embed dialogs into a graphics view. This example shows how to embed standard dialogs into Graphics View. It also shows how you can customize the diff --git a/examples/widgets/doc/src/extension.qdoc b/examples/widgets/doc/src/extension.qdoc index d040fbb9ce..c895258acf 100644 --- a/examples/widgets/doc/src/extension.qdoc +++ b/examples/widgets/doc/src/extension.qdoc @@ -36,23 +36,21 @@ \image extension-example.png Screenshot of the Extension example - The Extension application is a dialog that allows the user to - perform a simple search as well as a more advanced search. + The Extension application lets the user add search parameters in + a dialog and launch a simple or advanced search. The simple search has two options: \uicontrol {Match case} and \uicontrol - {Search from start}. The advanced search options include the - possibilities to search for \uicontrol {Whole words}, \uicontrol {Search - backward} and \uicontrol {Search selection}. Only the simple search is - visible when the application starts. The advanced search options - are located in the application's extension part, and can be made - visible by pressing the \uicontrol More button: + {Search from start}. The advanced search offers search for \uicontrol {Whole words}, + \uicontrol {Search backward}, and \uicontrol {Search selection}. The + application starts with simple search as the default. Click the \uicontrol More button + to show the advanced search options: \image extension_more.png Screenshot of the Extension example \section1 FindDialog Class Definition - The \c FindDialog class inherits QDialog. The QDialog class is the - base class of dialog windows. A dialog window is a top-level + The \c FindDialog class inherits QDialog. QDialog is the + base class for dialog windows. A dialog window is a top-level window mostly used for short-term tasks and brief communications with the user. @@ -62,45 +60,53 @@ displays the application's search options and controlling buttons. - In addition to a constructor, we declare the several child - widgets: We need a QLineEdit with an associated QLabel to let the - user type a word to search for, we need several \l - {QCheckBox}{QCheckBox}es to facilitate the search options, and we - need three \l {QPushButton}{QPushButton}s: the \uicontrol Find button to - start a search and the \uicontrol More button to enable an advanced search. - Finally, we need a QWidget representing the application's extension - part. + In addition to the constructor, there are several child widgets: + + \list + \li A QLineEdit with an associated QLabel to let the + user type a word to search for. + \li Several \l {QCheckBox}{QCheckBox}es to facilitate the search options. + \li Three \l {QPushButton}{QPushButton}s: + \list + \li the \uicontrol Find button to start a search + \li the \uicontrol More button to enable an advanced search + \li a QWidget representing the application's extension part + \endlist + \endlist \section1 FindDialog Class Implementation - In the constructor we first create the standard child widgets for - the simple search: the QLineEdit with the associated QLabel, two - of the \l {QCheckBox}{QCheckBox}es and all the \l - {QPushButton}{QPushButton}s. + Create the standard child widgets for the simple search in the constructor: + the QLineEdit with the associated QLabel, two {QCheckBox}es and all the + \l {QPushButton}{QPushButton}s. \snippet dialogs/extension/finddialog.cpp 0 - We give the options and buttons a shortcut key using the & - character. In the \uicontrol {Find what} option's case, we also need to - use the QLabel::setBuddy() function to make the shortcut key work - as expected; then, when the user presses the shortcut key - indicated by the label, the keyboard focus is transferred to the - label's buddy widget, the QLineEdit. + This snippet illustrates how you can define a shortcut key + for a widget. A shortcut should be defined by putting the ampersand + character (\c &) in front of the letter that should + become the shortcut. + For example, for \uicontrol {Find what}, pressing \uicontrol Alt + and \uicontrol w transfers focus to the QLineEdit widget. + Shortcuts can also be used for checking on or off a checkmark. + For example, pressing \uicontrol Alt and \uicontrol c puts the check mark + on \uicontrol {Match Case} if it was unchecked and vice versa. + It is the QLabel::setBuddy() method that links a widget to the shortcut + character if it has been defined. - We set the \uicontrol Find button's default property to true, using the + Set the \uicontrol Find button's default property to true, using the QPushButton::setDefault() function. Then the push button will be pressed if the user presses the Enter (or Return) key. Note that a QDialog can only have one default button. \snippet dialogs/extension/finddialog.cpp 2 - Then we create the extension widget, and the \l - {QCheckBox}{QCheckBox}es associated with the advanced search - options. + Create the extension widget, and the \l {QCheckBox}{QCheckBox}es associated + with the advanced search options. \snippet dialogs/extension/finddialog.cpp 3 - Now that the extension widget is created, we can connect the \uicontrol + Now that the extension widget is created, connect the \uicontrol More button's \l{QAbstractButton::toggled()}{toggled()} signal to the extension widget's \l{QWidget::setVisible()}{setVisible()} slot. @@ -111,26 +117,26 @@ the status is true the widget is shown, otherwise the widget is hidden. - Since we made the \uicontrol More button checkable when we created it, - the connection makes sure that the extension widget is shown - depending on the state of \uicontrol More button. + Since the \uicontrol More button is checkable, the connection makes + sure that the extension widget is shown depending on the state of + the \uicontrol More button. - We also put the check boxes associated with the advanced - search options into a layout we install on the extension widget. + Create checkboxes associated with the advanced search options in + a layout installed on the extension widget. \snippet dialogs/extension/finddialog.cpp 4 - Before we create the main layout, we create several child layouts - for the widgets: First we align the QLabel and its buddy, the - QLineEdit, using a QHBoxLayout. Then we vertically align the - QLabel and QLineEdit with the check boxes associated with the - simple search, using a QVBoxLayout. We also create a QVBoxLayout - for the buttons. In the end we lay out the two latter layouts and - the extension widget using a QGridLayout. + Before creating the main layout, create several child layouts + for the widgets. First align the QLabel and its buddy, the + QLineEdit, using a QHBoxLayout. Then align the QLabel and the QLineEdit + vertically with the checkboxes associated with the simple search, + using a QVBoxLayout. Create also a QVBoxLayout for the buttons. + Finally, lay out the two latter layouts and the extension widget + using a QGridLayout. \snippet dialogs/extension/finddialog.cpp 5 - Finally, we hide the extension widget using the QWidget::hide() + Hide the extension widget using the QWidget::hide() function, making the application only show the simple search options when it starts. When the user wants to access the advanced search options, the dialog only needs to change the visibility of diff --git a/examples/widgets/doc/src/fademessage.qdoc b/examples/widgets/doc/src/fademessage.qdoc index 4703dcda30..2035922067 100644 --- a/examples/widgets/doc/src/fademessage.qdoc +++ b/examples/widgets/doc/src/fademessage.qdoc @@ -29,7 +29,7 @@ \example effects/fademessage \title Fade Message Effect Example \ingroup examples-graphicsview-graphicseffects - \brief Demonstrates how to apply effects on items in the view + \brief Demonstrates how to apply effects on items in the view. \div { style="text-align: left"} \inlineimage fademessageeffect-example.png diff --git a/examples/widgets/doc/src/findfiles.qdoc b/examples/widgets/doc/src/findfiles.qdoc index ad39b003ae..d7428e7d16 100644 --- a/examples/widgets/doc/src/findfiles.qdoc +++ b/examples/widgets/doc/src/findfiles.qdoc @@ -30,7 +30,7 @@ \title Find Files Example \ingroup examples-dialogs - \brief A dialog for finding files in a specified folder + \brief A dialog for finding files in a specified folder. The Find Files application allows the user to search for files in a specified directory, matching a given file name or wildcard, diff --git a/examples/widgets/doc/src/graphicsview-anchorlayout.qdoc b/examples/widgets/doc/src/graphicsview-anchorlayout.qdoc index bd27a0dc4f..7933e3c956 100644 --- a/examples/widgets/doc/src/graphicsview-anchorlayout.qdoc +++ b/examples/widgets/doc/src/graphicsview-anchorlayout.qdoc @@ -29,7 +29,7 @@ \example graphicsview/anchorlayout \title Anchor Layout Example \ingroup examples-graphicsview-layout - \brief Demonstrates anchor layout in a graphics view scene + \brief Demonstrates anchor layout in a graphics view scene. The Anchor Layout example demonstrates the use of the QGraphicsAnchorLayout class. diff --git a/examples/widgets/doc/src/graphicsview-simpleanchorlayout.qdoc b/examples/widgets/doc/src/graphicsview-simpleanchorlayout.qdoc index fd0427fdc0..27b3f86156 100644 --- a/examples/widgets/doc/src/graphicsview-simpleanchorlayout.qdoc +++ b/examples/widgets/doc/src/graphicsview-simpleanchorlayout.qdoc @@ -29,7 +29,7 @@ \example graphicsview/simpleanchorlayout \title Simple Anchor Layout Example \ingroup examples-graphicsview-layout - \brief Demonstrates anchor layout on a graphics view scene + \brief Demonstrates anchor layout on a graphics view scene. The Simple Anchor Layout example shows the basic use of the QGraphicsAnchorLayout class. diff --git a/examples/widgets/doc/src/graphicsview-weatheranchorlayout.qdoc b/examples/widgets/doc/src/graphicsview-weatheranchorlayout.qdoc index fbdd08654d..71ace60355 100644 --- a/examples/widgets/doc/src/graphicsview-weatheranchorlayout.qdoc +++ b/examples/widgets/doc/src/graphicsview-weatheranchorlayout.qdoc @@ -29,7 +29,7 @@ \example graphicsview/weatheranchorlayout \title Weather Anchor Layout Example \ingroup examples-graphicsview-layout - \brief Demonstrates anchor layout on a graphics view scene + \brief Demonstrates anchor layout on a graphics view scene. The Weather Anchor Layout example shows more complex use of the QGraphicsAnchorLayout class to create a real-world window layout. diff --git a/examples/widgets/doc/src/padnavigator.qdoc b/examples/widgets/doc/src/padnavigator.qdoc index 017532622a..e59fa3cdbe 100644 --- a/examples/widgets/doc/src/padnavigator.qdoc +++ b/examples/widgets/doc/src/padnavigator.qdoc @@ -29,7 +29,7 @@ \example graphicsview/padnavigator \title Pad Navigator Example \ingroup examples-graphicsview - \brief Demonstrates how to create animated user interface + \brief Demonstrates how to create animated user interface. The Pad Navigator Example shows how you can use Graphics View together with embedded widgets and Qt's \l{The State Machine Framework}{state machine diff --git a/examples/widgets/doc/src/scribble.qdoc b/examples/widgets/doc/src/scribble.qdoc index 3b1f8dc895..ca79431334 100644 --- a/examples/widgets/doc/src/scribble.qdoc +++ b/examples/widgets/doc/src/scribble.qdoc @@ -149,7 +149,7 @@ For mouse press and mouse release events, we use the QMouseEvent::button() function to find out which button caused - the event. For mose move events, we use QMouseEvent::buttons() + the event. For mouse move events, we use QMouseEvent::buttons() to find which buttons are currently held down (as an OR-combination). If the users press the left mouse button, we store the position diff --git a/examples/widgets/gestures/imagegestures/doc/src/imagegestures.qdoc b/examples/widgets/gestures/imagegestures/doc/src/imagegestures.qdoc index c5911297f5..0ab578f55c 100644 --- a/examples/widgets/gestures/imagegestures/doc/src/imagegestures.qdoc +++ b/examples/widgets/gestures/imagegestures/doc/src/imagegestures.qdoc @@ -28,7 +28,7 @@ /*! \example gestures/imagegestures \title Image Gestures Example - \brief Demonstrates the use of simple gestures in a widget + \brief Demonstrates the use of simple gestures in a widget. This example shows how to enable gestures for a widget and use gesture input to perform actions. diff --git a/examples/widgets/statemachine/factorial/main.cpp b/examples/widgets/statemachine/factorial/main.cpp index 919988051f..f100aa0110 100644 --- a/examples/widgets/statemachine/factorial/main.cpp +++ b/examples/widgets/statemachine/factorial/main.cpp @@ -175,7 +175,7 @@ int main(int argc, char **argv) //! [6] machine.setInitialState(compute); - QObject::connect(&machine, SIGNAL(finished()), &app, SLOT(quit())); + QObject::connect(&machine, &QStateMachine::finished, &app, QCoreApplication::quit); machine.start(); return app.exec(); diff --git a/examples/widgets/tutorials/gettingstartedqt.qdoc b/examples/widgets/tutorials/gettingstartedqt.qdoc index 921dd7a32d..bbe1dd1a8d 100644 --- a/examples/widgets/tutorials/gettingstartedqt.qdoc +++ b/examples/widgets/tutorials/gettingstartedqt.qdoc @@ -28,7 +28,7 @@ /*! \example tutorials/notepad \title Getting Started Programming with Qt Widgets - \brief A tutorial for Qt Widgets based on a notepad application + \brief A tutorial for Qt Widgets based on a notepad application. In this topic, we teach basic Qt knowledge by implementing a simple Notepad application using C++ and the \l{Qt Widgets} module. The diff --git a/examples/widgets/tutorials/notepad/notepad.cpp b/examples/widgets/tutorials/notepad/notepad.cpp index 99a1a52c2b..d0e600e852 100644 --- a/examples/widgets/tutorials/notepad/notepad.cpp +++ b/examples/widgets/tutorials/notepad/notepad.cpp @@ -73,6 +73,17 @@ Notepad::Notepad(QWidget *parent) : { ui->setupUi(this); this->setCentralWidget(ui->textEdit); + +// Disable menu actions for unavailable features +#if !QT_CONFIG(printer) + ui->actionPrint->setEnabled(false); +#endif + +#if !QT_CONFIG(clipboard) + ui->actionCut->setEnabled(false); + ui->actionCopy->setEnabled(false); + ui->actionPaste->setEnabled(false); +#endif } Notepad::~Notepad() @@ -161,17 +172,23 @@ void Notepad::on_actionExit_triggered() void Notepad::on_actionCopy_triggered() { +#if QT_CONFIG(clipboard) ui->textEdit->copy(); +#endif } void Notepad::on_actionCut_triggered() { +#if QT_CONFIG(clipboard) ui->textEdit->cut(); +#endif } void Notepad::on_actionPaste_triggered() { +#if QT_CONFIG(clipboard) ui->textEdit->paste(); +#endif } void Notepad::on_actionUndo_triggered() diff --git a/examples/widgets/widgets/elidedlabel/testwidget.cpp b/examples/widgets/widgets/elidedlabel/testwidget.cpp index 50c12374fd..6392a4b4fa 100644 --- a/examples/widgets/widgets/elidedlabel/testwidget.cpp +++ b/examples/widgets/widgets/elidedlabel/testwidget.cpp @@ -94,25 +94,25 @@ TestWidget::TestWidget(QWidget *parent): //! [2] QPushButton *switchButton = new QPushButton(tr("Switch text")); - connect(switchButton, SIGNAL(clicked(bool)), this, SLOT(switchText())); + connect(switchButton, &QPushButton::clicked, this, &TestWidget::switchText); QPushButton *exitButton = new QPushButton(tr("Exit")); - connect(exitButton, SIGNAL(clicked(bool)), this, SLOT(close())); + connect(exitButton, &QPushButton::clicked, this, &TestWidget::close); QLabel *label = new QLabel(tr("Elided")); label->setVisible(elidedText->isElided()); - connect(elidedText, SIGNAL(elisionChanged(bool)), label, SLOT(setVisible(bool))); + connect(elidedText, &ElidedLabel::elisionChanged, label, &QLabel::setVisible); //! [2] //! [3] widthSlider = new QSlider(Qt::Horizontal); widthSlider->setMinimum(0); - connect(widthSlider, SIGNAL(valueChanged(int)), this, SLOT(onWidthChanged(int))); + connect(widthSlider, &QSlider::valueChanged, this, &TestWidget::onWidthChanged); heightSlider = new QSlider(Qt::Vertical); heightSlider->setInvertedAppearance(true); heightSlider->setMinimum(0); - connect(heightSlider, SIGNAL(valueChanged(int)), this, SLOT(onHeightChanged(int))); + connect(heightSlider, &QSlider::valueChanged, this, &TestWidget::onHeightChanged); //! [3] //! [4] @@ -165,4 +165,3 @@ void TestWidget::onHeightChanged(int height) } //! [8] - diff --git a/examples/xml/dombookmarks/doc/src/dombookmarks.qdoc b/examples/xml/dombookmarks/doc/src/dombookmarks.qdoc index e712ac45e9..84ac1723d5 100644 --- a/examples/xml/dombookmarks/doc/src/dombookmarks.qdoc +++ b/examples/xml/dombookmarks/doc/src/dombookmarks.qdoc @@ -29,7 +29,7 @@ \example dombookmarks \title DOM Bookmarks Example \ingroup xml-examples - \brief Provides a reader for XML Bookmark Exchange Language files + \brief Provides a reader for XML Bookmark Exchange Language files. The DOM Bookmarks example provides a reader for XML Bookmark Exchange Language (XBEL) files that uses Qt's DOM-based XML API to read and parse the files. The SAX Bookmarks diff --git a/examples/xml/saxbookmarks/doc/src/saxbookmarks.qdoc b/examples/xml/saxbookmarks/doc/src/saxbookmarks.qdoc index ca5ca0adbb..0cd89e641e 100644 --- a/examples/xml/saxbookmarks/doc/src/saxbookmarks.qdoc +++ b/examples/xml/saxbookmarks/doc/src/saxbookmarks.qdoc @@ -28,7 +28,7 @@ /*! \example saxbookmarks \title SAX Bookmarks Example - \brief Demonstrates how to read XBEL files + \brief Demonstrates how to read XBEL files. \ingroup xml-examples This example uses Qt's SAX API to read and parse the files. The DOM Bookmarks diff --git a/examples/xml/streambookmarks/doc/src/qxmlstreambookmarks.qdoc b/examples/xml/streambookmarks/doc/src/qxmlstreambookmarks.qdoc index ad093c2098..aa0ddd4991 100644 --- a/examples/xml/streambookmarks/doc/src/qxmlstreambookmarks.qdoc +++ b/examples/xml/streambookmarks/doc/src/qxmlstreambookmarks.qdoc @@ -28,7 +28,7 @@ /*! \example streambookmarks \title QXmlStream Bookmarks Example - \brief Demonstrates how to read and write to XBEL files + \brief Demonstrates how to read and write to XBEL files. \ingroup xml-examples The QXmlStream Bookmarks example provides a reader for XML Bookmark diff --git a/mkspecs/common/clang.conf b/mkspecs/common/clang.conf index 6122a37213..5800aaa5b4 100644 --- a/mkspecs/common/clang.conf +++ b/mkspecs/common/clang.conf @@ -4,8 +4,8 @@ QMAKE_COMPILER = gcc clang llvm # clang pretends to be gcc -QMAKE_CC = clang -QMAKE_CXX = clang++ +QMAKE_CC = $${CROSS_COMPILE}clang +QMAKE_CXX = $${CROSS_COMPILE}clang++ QMAKE_LINK_C = $$QMAKE_CC QMAKE_LINK_C_SHLIB = $$QMAKE_CC diff --git a/mkspecs/common/mac.conf b/mkspecs/common/mac.conf index 5208379f9a..61bea952b2 100644 --- a/mkspecs/common/mac.conf +++ b/mkspecs/common/mac.conf @@ -33,12 +33,19 @@ QMAKE_LIBS_DYNLOAD = QMAKE_LIBS_OPENGL = -framework OpenGL -framework AGL QMAKE_LIBS_THREAD = +QMAKE_INCDIR_WAYLAND = +QMAKE_LIBS_WAYLAND_CLIENT = -lwayland-client +QMAKE_LIBS_WAYLAND_SERVER = -lwayland-server +QMAKE_LIBDIR_WAYLAND = +QMAKE_DEFINES_WAYLAND = +QMAKE_WAYLAND_SCANNER = wayland-scanner + QMAKE_ACTOOL = actool QMAKE_DSYMUTIL = dsymutil -QMAKE_STRIP = strip +QMAKE_STRIP = $${CROSS_COMPILE}strip QMAKE_STRIPFLAGS_LIB += -S -x -QMAKE_AR = ar cq -QMAKE_RANLIB = ranlib -s -QMAKE_NM = nm -P +QMAKE_AR = $${CROSS_COMPILE}ar cq +QMAKE_RANLIB = $${CROSS_COMPILE}ranlib -s +QMAKE_NM = $${CROSS_COMPILE}nm -P diff --git a/mkspecs/common/msvc-version.conf b/mkspecs/common/msvc-version.conf index ccd809abf3..3fb55c9d81 100644 --- a/mkspecs/common/msvc-version.conf +++ b/mkspecs/common/msvc-version.conf @@ -100,11 +100,16 @@ greaterThan(QMAKE_MSC_VER, 1909) { # API is used in direct2d, but also in multimedia, positioning and sensors. # We can try again with a later version of Visual Studio. # QMAKE_CXXFLAGS_STRICTCXX = -permissive- + # MSVC partially supports the following, but '__cplusplus' definition is set # as for C++98 until MSVC fully conforms with C++14, see # https://developercommunity.visualstudio.com/content/problem/139261/msvc-incorrectly-defines-cplusplus.html - # QMAKE_CXXFLAGS_CXX14 = -std:c++14 - # QMAKE_CXXFLAGS_CXX1Z = -std:c++latest + # Support became available in MSVC 2017 15.7: + greaterThan(QMAKE_MSC_VER, 1913) { + QMAKE_CXXFLAGS += -Zc:__cplusplus + QMAKE_CXXFLAGS_CXX14 = -std:c++14 + QMAKE_CXXFLAGS_CXX1Z = -std:c++17 + } } greaterThan(QMAKE_MSC_VER, 1910) { diff --git a/mkspecs/features/default_pre.prf b/mkspecs/features/default_pre.prf index 07a9b1c401..1f2f1ff2de 100644 --- a/mkspecs/features/default_pre.prf +++ b/mkspecs/features/default_pre.prf @@ -11,7 +11,7 @@ CONFIG = \ testcase_targets import_plugins import_qpa_plugin \ $$CONFIG -!build_pass:defined(QT_EDITION, var):!equals(QT_EDITION, "OpenSource"):!equals(QT_EDITION, "Preview") { +!build_pass:!isEmpty(QT_LICHECK) { # # call license checker (but cache result for one day) # diff --git a/mkspecs/features/moc.prf b/mkspecs/features/moc.prf index 37194b2eb8..5c7745e5bb 100644 --- a/mkspecs/features/moc.prf +++ b/mkspecs/features/moc.prf @@ -57,7 +57,7 @@ defineReplace(mocCmdBase) { msvc: RET += --compiler-flavor=msvc isEmpty(MOC_PREDEF_FILE): RET += $$join(QMAKE_COMPILER_DEFINES, " -D", -D) - else: RET += --include $$shell_quote($$moc_predefs.output) + else: RET += --include $$shell_quote($$absolute_path($$moc_predefs.output, $$OUT_PWD)) RET += $$incvar $$QMAKE_MOC_OPTIONS return($$RET) diff --git a/mkspecs/features/qt_configure.prf b/mkspecs/features/qt_configure.prf index 8c891c654b..a61cae9ece 100644 --- a/mkspecs/features/qt_configure.prf +++ b/mkspecs/features/qt_configure.prf @@ -158,7 +158,7 @@ defineTest(qtConfCommandline_optionalString) { nextok = $${3} isEmpty(val) { $$nextok: val = $$qtConfPeekNextCommandlineArg() - contains(val, "^-.*|[A-Z_]+=.*")|isEmpty(val): \ + contains(val, "^-.*|[A-Z0-9_]+=.*")|isEmpty(val): \ val = "yes" else: \ val = $$qtConfGetNextCommandlineArg() @@ -233,9 +233,9 @@ defineTest(qtConfParseCommandLine) { $$didCustomCall: \ next() - contains(c, "([A-Z_]+)=(.*)") { - opt = $$replace(c, "^([A-Z_]+)=(.*)", "\\1") - val = $$replace(c, "^([A-Z_]+)=(.*)", "\\2") + contains(c, "([A-Z0-9_]+)=(.*)") { + opt = $$replace(c, "^([A-Z0-9_]+)=(.*)", "\\1") + val = $$replace(c, "^([A-Z0-9_]+)=(.*)", "\\2") for (cc, allConfigs) { var = $$eval($${cc}.commandline.assignments.$${opt}) !isEmpty(var): \ diff --git a/mkspecs/features/qt_plugin.prf b/mkspecs/features/qt_plugin.prf index bf90adcf1e..40528a65e2 100644 --- a/mkspecs/features/qt_plugin.prf +++ b/mkspecs/features/qt_plugin.prf @@ -35,9 +35,9 @@ CONFIG += relative_qt_rpath # Qt's plugins should be relocatable # Qt libraries should only use Application Extension safe APIs darwin:!no_app_extension_api_only: CONFIG += app_extension_api_only -CONFIG(static, static|shared)|prefix_build { - isEmpty(MODULE): MODULE = $$basename(TARGET) +isEmpty(MODULE): MODULE = $$basename(TARGET) +CONFIG(static, static|shared)|prefix_build { mod_work_pfx = $$MODULE_QMAKE_OUTDIR/mkspecs/modules force_independent: \ mod_inst_pfx = $$MODULE_QMAKE_OUTDIR/mkspecs/modules-inst diff --git a/mkspecs/features/wayland-scanner.prf b/mkspecs/features/wayland-scanner.prf index 9166ae7750..2360917a3b 100644 --- a/mkspecs/features/wayland-scanner.prf +++ b/mkspecs/features/wayland-scanner.prf @@ -14,54 +14,14 @@ isEmpty(QMAKE_WAYLAND_SCANNER):error("QMAKE_WAYLAND_SCANNER not defined for this mkspec") -defineReplace(waylandScannerHeaderFiles) { - side = $$1 - path = $$2 - isEqual(side, "server"): \ - sources_list = $$WAYLANDSERVERSOURCES $$WAYLANDSERVERSOURCES_SYSTEM - else: \ - sources_list = $$WAYLANDCLIENTSOURCES $$WAYLANDCLIENTSOURCES_SYSTEM - wayland_header_files_for_side = - for(file, sources_list) { - basenameFile = $$basename(file) - basenameFile ~= s,\\.xml$,, - wayland_header_files_for_side += $$path/wayland-$$basenameFile-$$side-protocol$${first(QMAKE_EXT_H)} - isEqual(side, "server"): \ - wayland_header_files_for_side += $$path/qwayland-server-$$basenameFile$${first(QMAKE_EXT_H)} - else: \ - wayland_header_files_for_side += $$path/qwayland-$$basenameFile$${first(QMAKE_EXT_H)} - } - return($$wayland_header_files_for_side) -} - -qt_install_headers { - header_dest = $$MODULE_BASE_OUTDIR/include/$$MODULE_INCNAME/$$VERSION/$$MODULE_INCNAME/private - - header_files_client = $$waylandScannerHeaderFiles(client, $$header_dest) - !isEmpty(header_files_client) { - wayland_generated_client_headers.files = $$header_files_client - wayland_generated_client_headers.path = $$private_headers.path - wayland_generated_client_headers.CONFIG = no_check_exist - INSTALLS += wayland_generated_client_headers - WAYLAND_CLIENT_HEADER_DEST = $$header_dest/ - WAYLAND_CLIENT_INCLUDE_DIR = $$MODULE_INCNAME/private - } - - header_files_server = $$waylandScannerHeaderFiles(server, $$header_dest) - !isEmpty(header_files_server) { - wayland_generated_server_headers.files = $$header_files_server - wayland_generated_server_headers.path = $$private_headers.path - wayland_generated_server_headers.CONFIG = no_check_exist - INSTALLS += wayland_generated_server_headers - WAYLAND_SERVER_HEADER_DEST = $$header_dest/ - WAYLAND_SERVER_INCLUDE_DIR = $$MODULE_INCNAME/private - } +!isEmpty(MODULE_INCNAME) { + WAYLAND_INCLUDE_DIR = $$MODULE_INCNAME/private } wayland_server_header.name = wayland ${QMAKE_FILE_BASE} wayland_server_header.input = WAYLANDSERVERSOURCES WAYLANDSERVERSOURCES_SYSTEM wayland_server_header.variable_out = HEADERS -wayland_server_header.output = $${WAYLAND_SERVER_HEADER_DEST}wayland-${QMAKE_FILE_BASE}-server-protocol$${first(QMAKE_EXT_H)} +wayland_server_header.output = wayland-${QMAKE_FILE_BASE}-server-protocol$${first(QMAKE_EXT_H)} wayland_server_header.commands = $$QMAKE_WAYLAND_SCANNER server-header < ${QMAKE_FILE_IN} > ${QMAKE_FILE_OUT} silent:wayland_server_header.commands = @echo Wayland server header ${QMAKE_FILE_IN} && $$wayland_server_header.commands QMAKE_EXTRA_COMPILERS += wayland_server_header @@ -69,7 +29,7 @@ QMAKE_EXTRA_COMPILERS += wayland_server_header wayland_client_header.name = wayland ${QMAKE_FILE_BASE} wayland_client_header.input = WAYLANDCLIENTSOURCES WAYLANDCLIENTSOURCES_SYSTEM wayland_client_header.variable_out = HEADERS -wayland_client_header.output = $${WAYLAND_CLIENT_HEADER_DEST}wayland-${QMAKE_FILE_BASE}-client-protocol$${first(QMAKE_EXT_H)} +wayland_client_header.output = wayland-${QMAKE_FILE_BASE}-client-protocol$${first(QMAKE_EXT_H)} wayland_client_header.commands = $$QMAKE_WAYLAND_SCANNER client-header < ${QMAKE_FILE_IN} > ${QMAKE_FILE_OUT} silent:wayland_client_header.commands = @echo Wayland client header ${QMAKE_FILE_IN} && $$wayland_client_header.commands QMAKE_EXTRA_COMPILERS += wayland_client_header @@ -87,35 +47,35 @@ qtPrepareTool(QMAKE_QTWAYLANDSCANNER, qtwaylandscanner) qtwayland_client_header.name = qtwayland ${QMAKE_FILE_BASE} qtwayland_client_header.input = WAYLANDCLIENTSOURCES WAYLANDCLIENTSOURCES_SYSTEM qtwayland_client_header.variable_out = HEADERS -qtwayland_client_header.depends += $$QMAKE_QTWAYLANDSCANNER_EXE $${WAYLAND_CLIENT_HEADER_DEST}wayland-${QMAKE_FILE_BASE}-client-protocol$${first(QMAKE_EXT_H)} -qtwayland_client_header.output = $${WAYLAND_CLIENT_HEADER_DEST}qwayland-${QMAKE_FILE_BASE}$${first(QMAKE_EXT_H)} -qtwayland_client_header.commands = $$QMAKE_QTWAYLANDSCANNER client-header ${QMAKE_FILE_IN} $$WAYLAND_CLIENT_INCLUDE_DIR > ${QMAKE_FILE_OUT} +qtwayland_client_header.depends += $$QMAKE_QTWAYLANDSCANNER_EXE wayland-${QMAKE_FILE_BASE}-client-protocol$${first(QMAKE_EXT_H)} +qtwayland_client_header.output = qwayland-${QMAKE_FILE_BASE}$${first(QMAKE_EXT_H)} +qtwayland_client_header.commands = $$QMAKE_QTWAYLANDSCANNER client-header ${QMAKE_FILE_IN} $$WAYLAND_INCLUDE_DIR > ${QMAKE_FILE_OUT} silent:qtwayland_client_header.commands = @echo QtWayland client header ${QMAKE_FILE_IN} && $$qtwayland_client_header.commands QMAKE_EXTRA_COMPILERS += qtwayland_client_header qtwayland_client_code.name = qtwayland ${QMAKE_FILE_BASE} qtwayland_client_code.input = WAYLANDCLIENTSOURCES WAYLANDCLIENTSOURCES_SYSTEM qtwayland_client_code.variable_out = SOURCES -qtwayland_client_code.depends += $$QMAKE_QTWAYLANDSCANNER_EXE $${WAYLAND_CLIENT_HEADER_DEST}qwayland-${QMAKE_FILE_BASE}$${first(QMAKE_EXT_H)} +qtwayland_client_code.depends += $$QMAKE_QTWAYLANDSCANNER_EXE qwayland-${QMAKE_FILE_BASE}$${first(QMAKE_EXT_H)} qtwayland_client_code.output = qwayland-${QMAKE_FILE_BASE}.cpp -qtwayland_client_code.commands = $$QMAKE_QTWAYLANDSCANNER client-code ${QMAKE_FILE_IN} $$WAYLAND_CLIENT_INCLUDE_DIR > ${QMAKE_FILE_OUT} +qtwayland_client_code.commands = $$QMAKE_QTWAYLANDSCANNER client-code ${QMAKE_FILE_IN} $$WAYLAND_INCLUDE_DIR > ${QMAKE_FILE_OUT} silent:qtwayland_client_code.commands = @echo QtWayland client code ${QMAKE_FILE_IN} && $$qtwayland_client_code.commands QMAKE_EXTRA_COMPILERS += qtwayland_client_code qtwayland_server_header.name = qtwayland ${QMAKE_FILE_BASE} qtwayland_server_header.input = WAYLANDSERVERSOURCES WAYLANDSERVERSOURCES_SYSTEM qtwayland_server_header.variable_out = HEADERS -qtwayland_server_header.depends += $$QMAKE_QTWAYLANDSCANNER_EXE $${WAYLAND_SERVER_HEADER_DEST}wayland-${QMAKE_FILE_BASE}-server-protocol$${first(QMAKE_EXT_H)} -qtwayland_server_header.output = $${WAYLAND_SERVER_HEADER_DEST}qwayland-server-${QMAKE_FILE_BASE}$${first(QMAKE_EXT_H)} -qtwayland_server_header.commands = $$QMAKE_QTWAYLANDSCANNER server-header ${QMAKE_FILE_IN} $$WAYLAND_SERVER_INCLUDE_DIR > ${QMAKE_FILE_OUT} +qtwayland_server_header.depends += $$QMAKE_QTWAYLANDSCANNER_EXE wayland-${QMAKE_FILE_BASE}-server-protocol$${first(QMAKE_EXT_H)} +qtwayland_server_header.output = qwayland-server-${QMAKE_FILE_BASE}$${first(QMAKE_EXT_H)} +qtwayland_server_header.commands = $$QMAKE_QTWAYLANDSCANNER server-header ${QMAKE_FILE_IN} $$WAYLAND_INCLUDE_DIR > ${QMAKE_FILE_OUT} silent:qtwayland_server_header.commands = @echo QtWayland server header ${QMAKE_FILE_IN} && $$qtwayland_server_header.commands QMAKE_EXTRA_COMPILERS += qtwayland_server_header qtwayland_server_code.name = qtwayland ${QMAKE_FILE_BASE} qtwayland_server_code.input = WAYLANDSERVERSOURCES WAYLANDSERVERSOURCES_SYSTEM qtwayland_server_code.variable_out = SOURCES -qtwayland_server_code.depends += $$QMAKE_QTWAYLANDSCANNER_EXE $${WAYLAND_SERVER_HEADER_DEST}qwayland-server-${QMAKE_FILE_BASE}$${first(QMAKE_EXT_H)} +qtwayland_server_code.depends += $$QMAKE_QTWAYLANDSCANNER_EXE qwayland-server-${QMAKE_FILE_BASE}$${first(QMAKE_EXT_H)} qtwayland_server_code.output = qwayland-server-${QMAKE_FILE_BASE}.cpp -qtwayland_server_code.commands = $$QMAKE_QTWAYLANDSCANNER server-code ${QMAKE_FILE_IN} $$WAYLAND_SERVER_INCLUDE_DIR > ${QMAKE_FILE_OUT} +qtwayland_server_code.commands = $$QMAKE_QTWAYLANDSCANNER server-code ${QMAKE_FILE_IN} $$WAYLAND_INCLUDE_DIR > ${QMAKE_FILE_OUT} silent:qtwayland_server_code.commands = @echo QtWayland server code ${QMAKE_FILE_IN} && $$qtwayland_server_code.commands QMAKE_EXTRA_COMPILERS += qtwayland_server_code diff --git a/mkspecs/macx-xcode/WorkspaceSettings.xcsettings b/mkspecs/macx-xcode/WorkspaceSettings.xcsettings index 08de0be8d3..a3f43a8b38 100644 --- a/mkspecs/macx-xcode/WorkspaceSettings.xcsettings +++ b/mkspecs/macx-xcode/WorkspaceSettings.xcsettings @@ -2,6 +2,8 @@ + BuildSystemType + Original IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded diff --git a/qmake/doc/src/qmake-manual.qdoc b/qmake/doc/src/qmake-manual.qdoc index 9968528b56..2b184887fe 100644 --- a/qmake/doc/src/qmake-manual.qdoc +++ b/qmake/doc/src/qmake-manual.qdoc @@ -3624,7 +3624,7 @@ \section2 mkpath(dirPath) Creates the directory path \c dirPath. This function is a wrapper around the - QDir::makepath function. + QDir::mkpath function. \section2 requires(condition) diff --git a/qmake/generators/mac/pbuilder_pbx.cpp b/qmake/generators/mac/pbuilder_pbx.cpp index 18b62c5135..80891e682f 100644 --- a/qmake/generators/mac/pbuilder_pbx.cpp +++ b/qmake/generators/mac/pbuilder_pbx.cpp @@ -1613,7 +1613,7 @@ ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t) // The configuration build dir however is not treated as excluded, // so we can safely point it to the root output dir. t << "\t\t\t\t" << writeSettings("CONFIGURATION_BUILD_DIR", - Option::output_dir + Option::dir_sep + "$(CONFIGURATION)") << ";\n"; + Option::output_dir + Option::dir_sep + "$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)") << ";\n"; if (!project->isEmpty("DESTDIR")) { ProString dir = project->first("DESTDIR"); diff --git a/qmake/generators/makefile.cpp b/qmake/generators/makefile.cpp index cdbd84b8cc..2f8c653d62 100644 --- a/qmake/generators/makefile.cpp +++ b/qmake/generators/makefile.cpp @@ -1141,7 +1141,7 @@ MakefileGenerator::writeObj(QTextStream &t, const char *src) QString srcf = (*sit).toQString(); QString dstf = (*oit).toQString(); t << escapeDependencyPath(dstf) << ": " << escapeDependencyPath(srcf) - << " " << escapeDependencyPaths(findDependencies(srcf)).join(" \\\n\t\t"); + << " " << finalizeDependencyPaths(findDependencies(srcf)).join(" \\\n\t\t"); ProKey comp; for (const ProString &compiler : project->values("QMAKE_BUILTIN_COMPILERS")) { @@ -2013,7 +2013,7 @@ MakefileGenerator::writeExtraCompilerTargets(QTextStream &t) if (config.indexOf("explicit_dependencies") != -1) { t << " " << valList(escapeDependencyPaths(fileFixify(tmp_dep, FileFixifyFromOutdir))); } else { - t << " " << valList(escapeDependencyPaths(inputs)) << " " << valList(escapeDependencyPaths(deps)); + t << " " << valList(escapeDependencyPaths(inputs)) << " " << valList(finalizeDependencyPaths(deps)); } t << "\n\t" << cmd << endl << endl; continue; @@ -2133,7 +2133,7 @@ MakefileGenerator::writeExtraCompilerTargets(QTextStream &t) else ++i; } - t << escapeDependencyPath(out) << ": " << valList(escapeDependencyPaths(deps)) << "\n\t" + t << escapeDependencyPath(out) << ": " << valList(finalizeDependencyPaths(deps)) << "\n\t" << cmd << endl << endl; } } @@ -2823,6 +2823,19 @@ MakefileGenerator::escapeFilePaths(const ProStringList &paths) const return ret; } +QString +MakefileGenerator::escapeDependencyPath(const QString &path) const +{ + QString ret = path; + if (!ret.isEmpty()) { + // Unix make semantics, to be inherited by unix and mingw generators. + static const QRegExp criticalChars(QStringLiteral("([\t :#])")); + ret.replace(criticalChars, QStringLiteral("\\\\1")); + debug_msg(2, "escapeDependencyPath: %s -> %s", path.toLatin1().constData(), ret.toLatin1().constData()); + } + return ret; +} + ProString MakefileGenerator::escapeDependencyPath(const ProString &path) const { @@ -2851,6 +2864,17 @@ MakefileGenerator::escapeDependencyPaths(const ProStringList &paths) const return ret; } +QStringList +MakefileGenerator::finalizeDependencyPaths(const QStringList &paths) const +{ + QStringList ret; + const int size = paths.size(); + ret.reserve(size); + for (int i = 0; i < size; ++i) + ret.append(escapeDependencyPath(Option::fixPathToTargetOS(paths.at(i), false))); + return ret; +} + QStringList MakefileGenerator::fileFixify(const QStringList &files, FileFixifyTypes fix, bool canon) const { diff --git a/qmake/generators/makefile.h b/qmake/generators/makefile.h index 4ced3bd121..f32bec650e 100644 --- a/qmake/generators/makefile.h +++ b/qmake/generators/makefile.h @@ -130,15 +130,17 @@ protected: QMakeProject *project; //escape - virtual QString escapeFilePath(const QString &path) const { return path; } + virtual QString escapeFilePath(const QString &path) const = 0; ProString escapeFilePath(const ProString &path) const; QStringList escapeFilePaths(const QStringList &paths) const; ProStringList escapeFilePaths(const ProStringList &paths) const; - virtual QString escapeDependencyPath(const QString &path) const { return escapeFilePath(path); } + virtual QString escapeDependencyPath(const QString &path) const; ProString escapeDependencyPath(const ProString &path) const; QStringList escapeDependencyPaths(const QStringList &paths) const; ProStringList escapeDependencyPaths(const ProStringList &paths) const; + QStringList finalizeDependencyPaths(const QStringList &paths) const; + //initialization void verifyCompilers(); virtual void init(); diff --git a/qmake/generators/makefiledeps.cpp b/qmake/generators/makefiledeps.cpp index c68eeb13d6..ffccdefbe1 100644 --- a/qmake/generators/makefiledeps.cpp +++ b/qmake/generators/makefiledeps.cpp @@ -1050,7 +1050,7 @@ void QMakeSourceFileInfo::saveCache(const QString &cf) QFile file(QMakeLocalFileName(cf).local()); if(file.open(QIODevice::WriteOnly)) { QTextStream stream(&file); - stream << qmake_version() << endl << endl; //version + stream << QMAKE_VERSION_STR << endl << endl; //version { //cache verification QMap verify = getCacheVerification(); stream << verify.count() << endl; @@ -1105,11 +1105,11 @@ void QMakeSourceFileInfo::loadCache(const QString &cf) return; QFile file; - if(!file.open(QIODevice::ReadOnly, fd)) + if (!file.open(fd, QIODevice::ReadOnly)) return; QTextStream stream(&file); - if(stream.readLine() == qmake_version()) { //version check + if (stream.readLine() == QMAKE_VERSION_STR) { //version check stream.skipWhiteSpace(); bool verified = true; diff --git a/qmake/generators/projectgenerator.h b/qmake/generators/projectgenerator.h index 587c415055..89c66f1ec8 100644 --- a/qmake/generators/projectgenerator.h +++ b/qmake/generators/projectgenerator.h @@ -42,6 +42,9 @@ class ProjectGenerator : public MakefileGenerator protected: virtual void init(); virtual bool writeMakefile(QTextStream &); + + virtual QString escapeFilePath(const QString &path) const { Q_ASSERT(false); return QString(); } + public: ProjectGenerator(); ~ProjectGenerator(); diff --git a/qmake/generators/unix/unixmake2.cpp b/qmake/generators/unix/unixmake2.cpp index 5468285c2e..3cb3be474a 100644 --- a/qmake/generators/unix/unixmake2.cpp +++ b/qmake/generators/unix/unixmake2.cpp @@ -375,7 +375,7 @@ UnixMakefileGenerator::writeMakeParts(QTextStream &t) QStringList deps = findDependencies((*it).toQString()).filter(QRegExp( "((^|/)" + Option::h_moc_mod + "|" + Option::cpp_moc_ext + "$)")); if(!deps.isEmpty()) - t << d_file_d << ": " << escapeDependencyPaths(deps).join(' ') << endl; + t << d_file_d << ": " << finalizeDependencyPaths(deps).join(' ') << endl; t << "-include " << d_file_d << endl; project->values("QMAKE_DISTCLEAN") += d_file; } @@ -1191,7 +1191,7 @@ UnixMakefileGenerator::writeMakeParts(QTextStream &t) << "EXPORT_QMAKE_XARCH_LFLAGS = $(EXPORT_QMAKE_XARCH_LFLAGS_" << arch << ")" << "\n\n"; } t << pchFilePath_d << ": " << escapeDependencyPath(pchInput) << ' ' - << escapeDependencyPaths(findDependencies(pchInput)).join(" \\\n\t\t"); + << finalizeDependencyPaths(findDependencies(pchInput)).join(" \\\n\t\t"); if (project->isActiveConfig("icc_pch_style")) { QString sourceFile = pchArchOutput + Option::cpp_ext.first(); QString sourceFile_f = escapeFilePath(sourceFile); diff --git a/qmake/generators/win32/mingw_make.cpp b/qmake/generators/win32/mingw_make.cpp index d6d6b04148..6fcfe96380 100644 --- a/qmake/generators/win32/mingw_make.cpp +++ b/qmake/generators/win32/mingw_make.cpp @@ -46,8 +46,7 @@ QString MingwMakefileGenerator::escapeDependencyPath(const QString &path) const { QString ret = path; ret.replace('\\', "/"); // ### this shouldn't be here - ret.replace(' ', QLatin1String("\\ ")); - return ret; + return MakefileGenerator::escapeDependencyPath(ret); } QString MingwMakefileGenerator::getManifestFileForRcFile() const @@ -165,13 +164,13 @@ void MingwMakefileGenerator::writeMingwParts(QTextStream &t) QString header = project->first("PRECOMPILED_HEADER").toQString(); QString cHeader = preCompHeaderOut + Option::dir_sep + "c"; t << escapeDependencyPath(cHeader) << ": " << escapeDependencyPath(header) << " " - << escapeDependencyPaths(findDependencies(header)).join(" \\\n\t\t") + << finalizeDependencyPaths(findDependencies(header)).join(" \\\n\t\t") << "\n\t" << mkdir_p_asstring(preCompHeaderOut) << "\n\t$(CC) -x c-header -c $(CFLAGS) $(INCPATH) -o " << escapeFilePath(cHeader) << ' ' << escapeFilePath(header) << endl << endl; QString cppHeader = preCompHeaderOut + Option::dir_sep + "c++"; t << escapeDependencyPath(cppHeader) << ": " << escapeDependencyPath(header) << " " - << escapeDependencyPaths(findDependencies(header)).join(" \\\n\t\t") + << finalizeDependencyPaths(findDependencies(header)).join(" \\\n\t\t") << "\n\t" << mkdir_p_asstring(preCompHeaderOut) << "\n\t$(CXX) -x c++-header -c $(CXXFLAGS) $(INCPATH) -o " << escapeFilePath(cppHeader) << ' ' << escapeFilePath(header) << endl << endl; diff --git a/qmake/generators/win32/mingw_make.h b/qmake/generators/win32/mingw_make.h index ab9e5a9961..6f041cfd4a 100644 --- a/qmake/generators/win32/mingw_make.h +++ b/qmake/generators/win32/mingw_make.h @@ -39,8 +39,8 @@ public: MingwMakefileGenerator(); ~MingwMakefileGenerator(); protected: - QString escapeDependencyPath(const QString &path) const; - ProString escapeDependencyPath(const ProString &path) const { return MakefileGenerator::escapeDependencyPath(path); } + using MakefileGenerator::escapeDependencyPath; + virtual QString escapeDependencyPath(const QString &path) const; virtual ProString fixLibFlag(const ProString &lib); virtual QString getManifestFileForRcFile() const; bool writeMakefile(QTextStream &); diff --git a/qmake/generators/win32/msvc_nmake.cpp b/qmake/generators/win32/msvc_nmake.cpp index ccc2ea6d2b..92b4eb5054 100644 --- a/qmake/generators/win32/msvc_nmake.cpp +++ b/qmake/generators/win32/msvc_nmake.cpp @@ -321,7 +321,7 @@ void NmakeMakefileGenerator::writeNmakeParts(QTextStream &t) QString precompRule = QString("-c -Yc -Fp%1 -Fo%2") .arg(escapeFilePath(precompPch), escapeFilePath(precompObj)); t << escapeDependencyPath(precompObj) << ": " << escapeDependencyPath(precompH) << ' ' - << escapeDependencyPaths(findDependencies(precompH)).join(" \\\n\t\t") + << finalizeDependencyPaths(findDependencies(precompH)).join(" \\\n\t\t") << "\n\t$(CXX) " + precompRule +" $(CXXFLAGS) $(INCPATH) -TP " << escapeFilePath(precompH) << endl << endl; } @@ -329,7 +329,7 @@ void NmakeMakefileGenerator::writeNmakeParts(QTextStream &t) QString precompRuleC = QString("-c -Yc -Fp%1 -Fo%2") .arg(escapeFilePath(precompPchC), escapeFilePath(precompObjC)); t << escapeDependencyPath(precompObjC) << ": " << escapeDependencyPath(precompH) << ' ' - << escapeDependencyPaths(findDependencies(precompH)).join(" \\\n\t\t") + << finalizeDependencyPaths(findDependencies(precompH)).join(" \\\n\t\t") << "\n\t$(CC) " + precompRuleC +" $(CFLAGS) $(INCPATH) -TC " << escapeFilePath(precompH) << endl << endl; } @@ -619,6 +619,8 @@ void NmakeMakefileGenerator::writeBuildRulesPart(QTextStream &t) } } else { manifest = fileFixify(manifest); + if (linkerSupportsEmbedding) + extraLFlags = "/MANIFEST:embed /MANIFESTINPUT:" + escapeFilePath(manifest); } const QString resourceId = (templateName == "app") ? "1" : "2"; diff --git a/qmake/generators/win32/winmakefile.cpp b/qmake/generators/win32/winmakefile.cpp index 75bb5d236d..bca27b7044 100644 --- a/qmake/generators/win32/winmakefile.cpp +++ b/qmake/generators/win32/winmakefile.cpp @@ -773,6 +773,18 @@ QString Win32MakefileGenerator::escapeFilePath(const QString &path) const return ret; } +QString Win32MakefileGenerator::escapeDependencyPath(const QString &path) const +{ + QString ret = path; + if (!ret.isEmpty()) { + static const QRegExp criticalChars(QStringLiteral("([\t #])")); + if (ret.contains(criticalChars)) + ret = "\"" + ret + "\""; + debug_msg(2, "EscapeDependencyPath: %s -> %s", path.toLatin1().constData(), ret.toLatin1().constData()); + } + return ret; +} + QString Win32MakefileGenerator::cQuoted(const QString &str) { QString ret = str; diff --git a/qmake/generators/win32/winmakefile.h b/qmake/generators/win32/winmakefile.h index 4d5ee9812b..b85a6b67df 100644 --- a/qmake/generators/win32/winmakefile.h +++ b/qmake/generators/win32/winmakefile.h @@ -47,8 +47,10 @@ protected: virtual void writeObjectsPart(QTextStream &t); virtual void writeImplicitRulesPart(QTextStream &t); virtual void writeBuildRulesPart(QTextStream &); + using MakefileGenerator::escapeFilePath; virtual QString escapeFilePath(const QString &path) const; - ProString escapeFilePath(const ProString &path) const { return MakefileGenerator::escapeFilePath(path); } + using MakefileGenerator::escapeDependencyPath; + virtual QString escapeDependencyPath(const QString &path) const; virtual void writeRcFilePart(QTextStream &t); diff --git a/src/3rdparty/angle/src/compiler/preprocessor/MacroExpander.h b/src/3rdparty/angle/src/compiler/preprocessor/MacroExpander.h index 3cc860d753..dc870f626f 100644 --- a/src/3rdparty/angle/src/compiler/preprocessor/MacroExpander.h +++ b/src/3rdparty/angle/src/compiler/preprocessor/MacroExpander.h @@ -83,7 +83,7 @@ class MacroExpander : public Lexer Diagnostics *mDiagnostics; bool mParseDefined; - std::auto_ptr mReserveToken; + std::unique_ptr mReserveToken; std::vector mContextStack; }; diff --git a/src/angle/patches/0017-Remove-usage-of-auto_ptr-in-MacroExpander.patch b/src/angle/patches/0017-Remove-usage-of-auto_ptr-in-MacroExpander.patch new file mode 100644 index 0000000000..314a985bab --- /dev/null +++ b/src/angle/patches/0017-Remove-usage-of-auto_ptr-in-MacroExpander.patch @@ -0,0 +1,31 @@ +From 946903d23ae361ddb05d2c0f64b339eb1694311b Mon Sep 17 00:00:00 2001 +From: Corentin Wallez +Date: Mon, 18 Apr 2016 17:30:07 -0400 +Subject: [PATCH] Remove usage of auto_ptr in MacroExpander + +BUG=angleproject:1269 + +Change-Id: I1fafa102b065f6da1797e8790ec3ed498d9d8b45 +Reviewed-on: https://chromium-review.googlesource.com/339379 +Reviewed-by: Jamie Madill +Commit-Queue: Corentin Wallez +--- + src/compiler/preprocessor/MacroExpander.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/compiler/preprocessor/MacroExpander.h b/src/compiler/preprocessor/MacroExpander.h +index 3cc860d75..dc870f626 100644 +--- a/src/3rdparty/angle/src/compiler/preprocessor/MacroExpander.h ++++ b/src/3rdparty/angle/src/compiler/preprocessor/MacroExpander.h +@@ -83,7 +83,7 @@ class MacroExpander : public Lexer + Diagnostics *mDiagnostics; + bool mParseDefined; + +- std::auto_ptr mReserveToken; ++ std::unique_ptr mReserveToken; + std::vector mContextStack; + }; + +-- +2.15.0.windows.1 + diff --git a/src/concurrent/doc/src/qtconcurrent-module.qdoc b/src/concurrent/doc/src/qtconcurrent-module.qdoc index 7f2b9b9562..9289b4bfa8 100644 --- a/src/concurrent/doc/src/qtconcurrent-module.qdoc +++ b/src/concurrent/doc/src/qtconcurrent-module.qdoc @@ -28,7 +28,7 @@ /*! \module QtConcurrent \title Qt Concurrent C++ Classes - \brief The Qt Concurrent module contains functionality to support concurrent execution of program code + \brief The Qt Concurrent module contains functionality to support concurrent execution of program code. \ingroup modules \qtvariable concurrent diff --git a/src/corelib/Qt5CoreMacros.cmake b/src/corelib/Qt5CoreMacros.cmake index 1627de4002..819b48f973 100644 --- a/src/corelib/Qt5CoreMacros.cmake +++ b/src/corelib/Qt5CoreMacros.cmake @@ -294,3 +294,54 @@ function(QT5_ADD_RESOURCES outfiles ) endfunction() set(_Qt5_COMPONENT_PATH "${CMAKE_CURRENT_LIST_DIR}/..") + +if (NOT CMAKE_VERSION VERSION_LESS 2.8.9) + macro(qt5_use_modules _target _link_type) + if(NOT CMAKE_MINIMUM_REQUIRED_VERSION VERSION_LESS 2.8.11) + if(CMAKE_WARN_DEPRECATED) + set(messageType WARNING) + endif() + if(CMAKE_ERROR_DEPRECATED) + set(messageType FATAL_ERROR) + endif() + if(messageType) + message(${messageType} "The qt5_use_modules macro is obsolete. Use target_link_libraries with IMPORTED targets instead.") + endif() + endif() + + if (NOT TARGET ${_target}) + message(FATAL_ERROR "The first argument to qt5_use_modules must be an existing target.") + endif() + if ("${_link_type}" STREQUAL "LINK_PUBLIC" OR "${_link_type}" STREQUAL "LINK_PRIVATE" ) + set(_qt5_modules ${ARGN}) + set(_qt5_link_type ${_link_type}) + else() + set(_qt5_modules ${_link_type} ${ARGN}) + endif() + + if ("${_qt5_modules}" STREQUAL "") + message(FATAL_ERROR "qt5_use_modules requires at least one Qt module to use.") + endif() + + foreach(_module ${_qt5_modules}) + if (NOT Qt5${_module}_FOUND) + find_package(Qt5${_module} PATHS "${_Qt5_COMPONENT_PATH}" NO_DEFAULT_PATH) + if (NOT Qt5${_module}_FOUND) + message(FATAL_ERROR "Can not use \"${_module}\" module which has not yet been found.") + endif() + endif() + target_link_libraries(${_target} ${_qt5_link_type} ${Qt5${_module}_LIBRARIES}) + set_property(TARGET ${_target} APPEND PROPERTY INCLUDE_DIRECTORIES ${Qt5${_module}_INCLUDE_DIRS}) + set_property(TARGET ${_target} APPEND PROPERTY COMPILE_DEFINITIONS ${Qt5${_module}_COMPILE_DEFINITIONS}) + set_property(TARGET ${_target} APPEND PROPERTY COMPILE_DEFINITIONS_RELEASE QT_NO_DEBUG) + set_property(TARGET ${_target} APPEND PROPERTY COMPILE_DEFINITIONS_RELWITHDEBINFO QT_NO_DEBUG) + set_property(TARGET ${_target} APPEND PROPERTY COMPILE_DEFINITIONS_MINSIZEREL QT_NO_DEBUG) + if (Qt5_POSITION_INDEPENDENT_CODE + AND (CMAKE_VERSION VERSION_LESS 2.8.12 + AND (NOT CMAKE_CXX_COMPILER_ID STREQUAL "GNU" + OR CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.0))) + set_property(TARGET ${_target} PROPERTY POSITION_INDEPENDENT_CODE ${Qt5_POSITION_INDEPENDENT_CODE}) + endif() + endforeach() + endmacro() +endif() diff --git a/src/corelib/animation/qpropertyanimation.cpp b/src/corelib/animation/qpropertyanimation.cpp index 9fd845bb93..5ba2a1fa73 100644 --- a/src/corelib/animation/qpropertyanimation.cpp +++ b/src/corelib/animation/qpropertyanimation.cpp @@ -40,7 +40,7 @@ /*! \class QPropertyAnimation \inmodule QtCore - \brief The QPropertyAnimation class animates Qt properties + \brief The QPropertyAnimation class animates Qt properties. \since 4.6 \ingroup animation diff --git a/src/corelib/global/qcompilerdetection.h b/src/corelib/global/qcompilerdetection.h index 87ade23503..9906425f5b 100644 --- a/src/corelib/global/qcompilerdetection.h +++ b/src/corelib/global/qcompilerdetection.h @@ -629,7 +629,7 @@ # define Q_COMPILER_THREAD_LOCAL # define Q_COMPILER_UDL # endif -# elif defined(__STDC_VERSION__) && __STDC_VERSION__ > 199901L s +# elif defined(__STDC_VERSION__) && __STDC_VERSION__ > 199901L // C11 features supported. Only tested with ICC 17 and up. # define Q_COMPILER_STATIC_ASSERT # if __has_include() diff --git a/src/corelib/global/qglobal.cpp b/src/corelib/global/qglobal.cpp index b654f5863a..3fe91cae65 100644 --- a/src/corelib/global/qglobal.cpp +++ b/src/corelib/global/qglobal.cpp @@ -1038,6 +1038,11 @@ Q_STATIC_ASSERT((std::is_same::value)); \snippet code/src_corelib_global_qglobal.cpp 53 + \note Qt detects the necessary C++14 compiler support by way of the feature + test recommendations from + \l{https://isocpp.org/std/standing-documents/sd-6-sg10-feature-test-recommendations} + {C++ Committee's Standing Document 6}. + \sa qConstOverload(), qNonConstOverload(), {Differences between String-Based and Functor-Based Connections} */ diff --git a/src/corelib/global/qglobalstatic.qdoc b/src/corelib/global/qglobalstatic.qdoc index 63cc968d1c..303709bb1d 100644 --- a/src/corelib/global/qglobalstatic.qdoc +++ b/src/corelib/global/qglobalstatic.qdoc @@ -3,9 +3,9 @@ ** Copyright (C) 2016 Intel Corporation. ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the QtCore module of the Qt Toolkit. +** This file is part of the documentation of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL$ +** $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 @@ -14,25 +14,13 @@ ** 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. -** +** 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$ ** ****************************************************************************/ @@ -336,7 +324,7 @@ \threadsafe \inmodule QtCore \since 5.1 - \brief The QGlobalStatic class is used to implement a global static object + \brief The QGlobalStatic class is used to implement a global static object. The QGlobalStatic class is the front-end API exported when Q_GLOBAL_STATIC() is used. See the documentation for the macro for a diff --git a/src/corelib/global/qoperatingsystemversion.cpp b/src/corelib/global/qoperatingsystemversion.cpp index 4d267e328d..2f8d339ca7 100644 --- a/src/corelib/global/qoperatingsystemversion.cpp +++ b/src/corelib/global/qoperatingsystemversion.cpp @@ -437,6 +437,14 @@ const QOperatingSystemVersion QOperatingSystemVersion::MacOSSierra = const QOperatingSystemVersion QOperatingSystemVersion::MacOSHighSierra = QOperatingSystemVersion(QOperatingSystemVersion::MacOS, 10, 13); +/*! + \variable QOperatingSystemVersion::MacOSMojave + \brief a version corresponding to macOS Mojave (version 10.14). + \since 5.11.2 + */ +const QOperatingSystemVersion QOperatingSystemVersion::MacOSMojave = + QOperatingSystemVersion(QOperatingSystemVersion::MacOS, 10, 14); + /*! \variable QOperatingSystemVersion::AndroidJellyBean \brief a version corresponding to Android Jelly Bean (version 4.1, API level 16). diff --git a/src/corelib/global/qoperatingsystemversion.h b/src/corelib/global/qoperatingsystemversion.h index 5f27deab9e..df01e5438a 100644 --- a/src/corelib/global/qoperatingsystemversion.h +++ b/src/corelib/global/qoperatingsystemversion.h @@ -70,6 +70,7 @@ public: static const QOperatingSystemVersion OSXElCapitan; static const QOperatingSystemVersion MacOSSierra; static const QOperatingSystemVersion MacOSHighSierra; + static const QOperatingSystemVersion MacOSMojave; static const QOperatingSystemVersion AndroidJellyBean; static const QOperatingSystemVersion AndroidJellyBean_MR1; diff --git a/src/corelib/global/qoperatingsystemversion_win.cpp b/src/corelib/global/qoperatingsystemversion_win.cpp index f3662ae1f9..7659fb2550 100644 --- a/src/corelib/global/qoperatingsystemversion_win.cpp +++ b/src/corelib/global/qoperatingsystemversion_win.cpp @@ -97,7 +97,7 @@ static inline OSVERSIONINFOEX determineWinOsVersion() // because linking to it at load time will not pass the Windows App Certification Kit // https://msdn.microsoft.com/en-us/library/windows/hardware/ff561910.aspx RtlGetVersionFunction pRtlGetVersion = reinterpret_cast( - GetProcAddressA(ntdll, "RtlGetVersion")); + reinterpret_cast(GetProcAddressA(ntdll, "RtlGetVersion"))); if (Q_UNLIKELY(!pRtlGetVersion)) return result; diff --git a/src/corelib/global/qsystemdetection.h b/src/corelib/global/qsystemdetection.h index ff0e03108b..cacb95b674 100644 --- a/src/corelib/global/qsystemdetection.h +++ b/src/corelib/global/qsystemdetection.h @@ -216,18 +216,6 @@ # // Numerical checks are preferred to named checks, but to be safe # // we define the missing version names in case Qt uses them. # -# if !defined(__MAC_10_7) -# define __MAC_10_7 1070 -# endif -# if !defined(__MAC_10_8) -# define __MAC_10_8 1080 -# endif -# if !defined(__MAC_10_9) -# define __MAC_10_9 1090 -# endif -# if !defined(__MAC_10_10) -# define __MAC_10_10 101000 -# endif # if !defined(__MAC_10_11) # define __MAC_10_11 101100 # endif @@ -237,17 +225,8 @@ # if !defined(__MAC_10_13) # define __MAC_10_13 101300 # endif -# if !defined(MAC_OS_X_VERSION_10_7) -# define MAC_OS_X_VERSION_10_7 1070 -# endif -# if !defined(MAC_OS_X_VERSION_10_8) -# define MAC_OS_X_VERSION_10_8 1080 -# endif -# if !defined(MAC_OS_X_VERSION_10_9) -# define MAC_OS_X_VERSION_10_9 1090 -# endif -# if !defined(MAC_OS_X_VERSION_10_10) -# define MAC_OS_X_VERSION_10_10 101000 +# if !defined(__MAC_10_14) +# define __MAC_10_14 101400 # endif # if !defined(MAC_OS_X_VERSION_10_11) # define MAC_OS_X_VERSION_10_11 101100 @@ -258,55 +237,10 @@ # if !defined(MAC_OS_X_VERSION_10_13) # define MAC_OS_X_VERSION_10_13 101300 # endif +# if !defined(MAC_OS_X_VERSION_10_14) +# define MAC_OS_X_VERSION_10_14 101400 +# endif # -# if !defined(__IPHONE_4_3) -# define __IPHONE_4_3 40300 -# endif -# if !defined(__IPHONE_5_0) -# define __IPHONE_5_0 50000 -# endif -# if !defined(__IPHONE_5_1) -# define __IPHONE_5_1 50100 -# endif -# if !defined(__IPHONE_6_0) -# define __IPHONE_6_0 60000 -# endif -# if !defined(__IPHONE_6_1) -# define __IPHONE_6_1 60100 -# endif -# if !defined(__IPHONE_7_0) -# define __IPHONE_7_0 70000 -# endif -# if !defined(__IPHONE_7_1) -# define __IPHONE_7_1 70100 -# endif -# if !defined(__IPHONE_8_0) -# define __IPHONE_8_0 80000 -# endif -# if !defined(__IPHONE_8_1) -# define __IPHONE_8_1 80100 -# endif -# if !defined(__IPHONE_8_2) -# define __IPHONE_8_2 80200 -# endif -# if !defined(__IPHONE_8_3) -# define __IPHONE_8_3 80300 -# endif -# if !defined(__IPHONE_8_4) -# define __IPHONE_8_4 80400 -# endif -# if !defined(__IPHONE_9_0) -# define __IPHONE_9_0 90000 -# endif -# if !defined(__IPHONE_9_1) -# define __IPHONE_9_1 90100 -# endif -# if !defined(__IPHONE_9_2) -# define __IPHONE_9_2 90200 -# endif -# if !defined(__IPHONE_9_3) -# define __IPHONE_9_3 90300 -# endif # if !defined(__IPHONE_10_0) # define __IPHONE_10_0 100000 # endif @@ -322,6 +256,9 @@ # if !defined(__IPHONE_11_0) # define __IPHONE_11_0 110000 # endif +# if !defined(__IPHONE_12_0) +# define __IPHONE_12_0 120000 +# endif #endif #ifdef __LSB_VERSION__ diff --git a/src/corelib/io/qdebug.cpp b/src/corelib/io/qdebug.cpp index 0d9a6c8749..013d531581 100644 --- a/src/corelib/io/qdebug.cpp +++ b/src/corelib/io/qdebug.cpp @@ -842,7 +842,7 @@ QDebug &QDebug::resetFormat() /*! \class QDebugStateSaver \inmodule QtCore - \brief Convenience class for custom QDebug operators + \brief Convenience class for custom QDebug operators. Saves the settings used by QDebug, and restores them upon destruction, then calls \l {QDebug::maybeSpace()}{maybeSpace()}, to separate arguments with a space if diff --git a/src/corelib/io/qfilesystemwatcher_inotify.cpp b/src/corelib/io/qfilesystemwatcher_inotify.cpp index 048669b92f..c0c5f9d744 100644 --- a/src/corelib/io/qfilesystemwatcher_inotify.cpp +++ b/src/corelib/io/qfilesystemwatcher_inotify.cpp @@ -302,7 +302,8 @@ QStringList QInotifyFileSystemWatcherEngine::addPaths(const QStringList &paths, | IN_DELETE_SELF ))); if (wd < 0) { - qWarning().nospace() << "inotify_add_watch(" << path << ") failed: " << QSystemError(errno, QSystemError::NativeError).toString(); + if (errno != ENOENT) + qErrnoWarning("inotify_add_watch(%ls) failed:", path.constData()); continue; } diff --git a/src/corelib/io/qlockfile_win.cpp b/src/corelib/io/qlockfile_win.cpp index 6b8028460c..277f8d4230 100644 --- a/src/corelib/io/qlockfile_win.cpp +++ b/src/corelib/io/qlockfile_win.cpp @@ -153,9 +153,8 @@ QString QLockFilePrivate::processNameByPid(qint64 pid) HMODULE hPsapi = LoadLibraryA("psapi"); if (!hPsapi) return QString(); - - GetModuleFileNameExFunc qGetModuleFileNameEx - = (GetModuleFileNameExFunc)GetProcAddress(hPsapi, "GetModuleFileNameExW"); + GetModuleFileNameExFunc qGetModuleFileNameEx = reinterpret_cast( + reinterpret_cast(GetProcAddress(hPsapi, "GetModuleFileNameExW"))); if (!qGetModuleFileNameEx) { FreeLibrary(hPsapi); return QString(); diff --git a/src/corelib/itemmodels/qabstractitemmodel.cpp b/src/corelib/itemmodels/qabstractitemmodel.cpp index d826110ec7..3a6f67521f 100644 --- a/src/corelib/itemmodels/qabstractitemmodel.cpp +++ b/src/corelib/itemmodels/qabstractitemmodel.cpp @@ -182,8 +182,8 @@ QPersistentModelIndex::~QPersistentModelIndex() Returns \c{true} if this persistent model index is equal to the \a other persistent model index; otherwise returns \c{false}. - All values in the persistent model index are used when comparing - with another persistent model index. + The internal data pointer, row, column, and model values in the persistent + model index are used when comparing with another persistent model index. */ bool QPersistentModelIndex::operator==(const QPersistentModelIndex &other) const @@ -199,8 +199,8 @@ bool QPersistentModelIndex::operator==(const QPersistentModelIndex &other) const Returns \c{true} if this persistent model index is smaller than the \a other persistent model index; otherwise returns \c{false}. - All values in the persistent model index are used when comparing - with another persistent model index. + The internal data pointer, row, column, and model values in the persistent + model index are used when comparing with another persistent model index. */ bool QPersistentModelIndex::operator<(const QPersistentModelIndex &other) const @@ -275,13 +275,11 @@ QPersistentModelIndex::operator const QModelIndex&() const } /*! - \fn bool QPersistentModelIndex::operator==(const QModelIndex &other) const - Returns \c{true} if this persistent model index refers to the same location as the \a other model index; otherwise returns \c{false}. - All values in the persistent model index are used when comparing with - another model index. + The internal data pointer, row, column, and model values in the persistent + model index are used when comparing with another model index. */ bool QPersistentModelIndex::operator==(const QModelIndex &other) const @@ -1167,8 +1165,8 @@ void QAbstractItemModel::resetInternalData() Returns \c{true} if this model index refers to the same location as the \a other model index; otherwise returns \c{false}. - All values in the model index are used when comparing with another model - index. + The internal data pointer, row, column, and model values are used when + comparing with another model index. */ diff --git a/src/corelib/itemmodels/qidentityproxymodel.cpp b/src/corelib/itemmodels/qidentityproxymodel.cpp index e984ec194e..c1e23dbd0c 100644 --- a/src/corelib/itemmodels/qidentityproxymodel.cpp +++ b/src/corelib/itemmodels/qidentityproxymodel.cpp @@ -83,7 +83,7 @@ class QIdentityProxyModelPrivate : public QAbstractProxyModelPrivate \since 4.8 \class QIdentityProxyModel \inmodule QtCore - \brief The QIdentityProxyModel class proxies its source model unmodified + \brief The QIdentityProxyModel class proxies its source model unmodified. \ingroup model-view diff --git a/src/corelib/kernel/kernel.pri b/src/corelib/kernel/kernel.pri index ca8bd30698..c528b16f9c 100644 --- a/src/corelib/kernel/kernel.pri +++ b/src/corelib/kernel/kernel.pri @@ -120,7 +120,7 @@ mac { LIBS_PRIVATE += -framework Foundation - osx: LIBS_PRIVATE += -framework CoreServices -framework AppKit + osx: LIBS_PRIVATE += -framework CoreServices -framework AppKit -framework Security ios|tvos { # We need UIKit for UIApplication in qeventdispatcher_cf.mm diff --git a/src/corelib/kernel/qcore_mac_objc.mm b/src/corelib/kernel/qcore_mac_objc.mm index 97a3acacd2..0d7bfad943 100644 --- a/src/corelib/kernel/qcore_mac_objc.mm +++ b/src/corelib/kernel/qcore_mac_objc.mm @@ -44,6 +44,10 @@ #include #endif +#if defined(QT_PLATFORM_UIKIT) +#include +#endif + #include QT_BEGIN_NAMESPACE @@ -190,6 +194,43 @@ AppleApplication *qt_apple_sharedApplication() } #endif +#if defined(Q_OS_MACOS) && !defined(QT_BOOTSTRAPPED) +bool qt_apple_isSandboxed() +{ + static bool isSandboxed = []() { + QCFType staticCode = nullptr; + NSURL *bundleUrl = [[NSBundle mainBundle] bundleURL]; + if (SecStaticCodeCreateWithPath((__bridge CFURLRef)bundleUrl, + kSecCSDefaultFlags, &staticCode) != errSecSuccess) + return false; + + QCFType sandboxRequirement; + if (SecRequirementCreateWithString(CFSTR("entitlement[\"com.apple.security.app-sandbox\"] exists"), + kSecCSDefaultFlags, &sandboxRequirement) != errSecSuccess) + return false; + + if (SecStaticCodeCheckValidityWithErrors(staticCode, + kSecCSBasicValidateOnly, sandboxRequirement, nullptr) != errSecSuccess) + return false; + + return true; + }(); + return isSandboxed; +} + +QT_END_NAMESPACE +@implementation NSObject (QtSandboxHelpers) +- (id)qt_valueForPrivateKey:(NSString *)key +{ + if (qt_apple_isSandboxed()) + return nil; + + return [self valueForKey:key]; +} +@end +QT_BEGIN_NAMESPACE +#endif + #ifdef Q_OS_MACOS /* Ensure that Objective-C objects auto-released in main(), directly or indirectly, diff --git a/src/corelib/kernel/qcore_mac_p.h b/src/corelib/kernel/qcore_mac_p.h index 84978bbbc3..1161e363b7 100644 --- a/src/corelib/kernel/qcore_mac_p.h +++ b/src/corelib/kernel/qcore_mac_p.h @@ -192,6 +192,17 @@ QDebug operator<<(QDebug debug, const QMacAutoReleasePool *pool); Q_CORE_EXPORT void qt_apple_check_os_version(); Q_CORE_EXPORT bool qt_apple_isApplicationExtension(); +#if defined(Q_OS_MACOS) && !defined(QT_BOOTSTRAPPED) +Q_CORE_EXPORT bool qt_apple_isSandboxed(); +# ifdef __OBJC__ +QT_END_NAMESPACE +@interface NSObject (QtSandboxHelpers) +- (id)qt_valueForPrivateKey:(NSString *)key; +@end +QT_BEGIN_NAMESPACE +# endif +#endif + #if !defined(QT_BOOTSTRAPPED) && !defined(Q_OS_WATCHOS) QT_END_NAMESPACE # if defined(Q_OS_MACOS) diff --git a/src/corelib/kernel/qdeadlinetimer.cpp b/src/corelib/kernel/qdeadlinetimer.cpp index 97b98a1376..4fba30050d 100644 --- a/src/corelib/kernel/qdeadlinetimer.cpp +++ b/src/corelib/kernel/qdeadlinetimer.cpp @@ -344,6 +344,11 @@ void QDeadlineTimer::setPreciseRemainingTime(qint64 secs, qint64 nsecs, Qt::Time deadline.setRemainingTime(250ms); \endcode + \note Qt detects the necessary C++14 compiler support by way of the feature + test recommendations from + \l{https://isocpp.org/std/standing-documents/sd-6-sg10-feature-test-recommendations} + {C++ Committee's Standing Document 6}. + \sa setDeadline(), remainingTime(), hasExpired(), isForever() */ diff --git a/src/corelib/kernel/qmetatype.h b/src/corelib/kernel/qmetatype.h index a0969ee908..cf68752f85 100644 --- a/src/corelib/kernel/qmetatype.h +++ b/src/corelib/kernel/qmetatype.h @@ -1413,8 +1413,8 @@ namespace QtPrivate static char checkType(void (X::*)()); static void *checkType(void (T::*)()); enum { - IsRealGadget = sizeof(checkType(&T::qt_check_for_QGADGET_macro)) == sizeof(void *), - IsGadgetOrDerivedFrom = true + IsRealGadget = !IsPointerToTypeDerivedFromQObject::Value && sizeof(checkType(&T::qt_check_for_QGADGET_macro)) == sizeof(void *), + IsGadgetOrDerivedFrom = !IsPointerToTypeDerivedFromQObject::Value }; }; diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp index 3717d7a19e..5387d549c6 100644 --- a/src/corelib/kernel/qobject.cpp +++ b/src/corelib/kernel/qobject.cpp @@ -511,7 +511,7 @@ void QMetaCallEvent::placeMetaCall(QObject *object) /*! \class QSignalBlocker - \brief Exception-safe wrapper around QObject::blockSignals() + \brief Exception-safe wrapper around QObject::blockSignals(). \since 5.3 \ingroup objectmodel \inmodule QtCore diff --git a/src/corelib/kernel/qtimer.cpp b/src/corelib/kernel/qtimer.cpp index 802c8d72f6..d8d520ff58 100644 --- a/src/corelib/kernel/qtimer.cpp +++ b/src/corelib/kernel/qtimer.cpp @@ -117,7 +117,7 @@ QT_BEGIN_NAMESPACE All timer types may time out later than expected if the system is busy or unable to provide the requested accuracy. In such a case of timeout - overrun, Qt will emit activated() only once, even if multiple timeouts have + overrun, Qt will emit timeout() only once, even if multiple timeouts have expired, and then will resume the original interval. \section1 Alternatives to QTimer diff --git a/src/corelib/serialization/qdatastream.h b/src/corelib/serialization/qdatastream.h index 4ae4a3d76c..eae0146553 100644 --- a/src/corelib/serialization/qdatastream.h +++ b/src/corelib/serialization/qdatastream.h @@ -152,7 +152,7 @@ public: QDataStream &operator>>(qint16 &i); QDataStream &operator>>(quint16 &i); QDataStream &operator>>(qint32 &i); - QDataStream &operator>>(quint32 &i); + inline QDataStream &operator>>(quint32 &i); QDataStream &operator>>(qint64 &i); QDataStream &operator>>(quint64 &i); QDataStream &operator>>(std::nullptr_t &ptr) { ptr = nullptr; return *this; } @@ -168,7 +168,7 @@ public: QDataStream &operator<<(qint16 i); QDataStream &operator<<(quint16 i); QDataStream &operator<<(qint32 i); - QDataStream &operator<<(quint32 i); + inline QDataStream &operator<<(quint32 i); QDataStream &operator<<(qint64 i); QDataStream &operator<<(quint64 i); QDataStream &operator<<(std::nullptr_t) { return *this; } diff --git a/src/corelib/serialization/qxmlstream.cpp b/src/corelib/serialization/qxmlstream.cpp index a92dd71df5..f18c4cc8e7 100644 --- a/src/corelib/serialization/qxmlstream.cpp +++ b/src/corelib/serialization/qxmlstream.cpp @@ -2265,7 +2265,7 @@ QXmlStreamAttributes QXmlStreamReader::attributes() const \inmodule QtCore \since 4.3 \reentrant - \brief The QXmlStreamAttribute class represents a single XML attribute + \brief The QXmlStreamAttribute class represents a single XML attribute. \ingroup xml-tools diff --git a/src/corelib/thread/qfuture.qdoc b/src/corelib/thread/qfuture.qdoc index e607d090c5..7db65dacd3 100644 --- a/src/corelib/thread/qfuture.qdoc +++ b/src/corelib/thread/qfuture.qdoc @@ -3,9 +3,9 @@ ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the QtCore module of the Qt Toolkit. +** This file is part of the documentation of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL$ +** $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 @@ -14,25 +14,13 @@ ** 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. -** +** 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$ ** ****************************************************************************/ diff --git a/src/corelib/thread/qfuturesynchronizer.qdoc b/src/corelib/thread/qfuturesynchronizer.qdoc index c9c402ff87..67dafb039e 100644 --- a/src/corelib/thread/qfuturesynchronizer.qdoc +++ b/src/corelib/thread/qfuturesynchronizer.qdoc @@ -3,9 +3,9 @@ ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the QtCore module of the Qt Toolkit. +** This file is part of the documentation of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL$ +** $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 @@ -14,25 +14,13 @@ ** 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. -** +** 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$ ** ****************************************************************************/ diff --git a/src/corelib/thread/qsemaphore.cpp b/src/corelib/thread/qsemaphore.cpp index f418ac1205..82d439a728 100644 --- a/src/corelib/thread/qsemaphore.cpp +++ b/src/corelib/thread/qsemaphore.cpp @@ -501,7 +501,7 @@ bool QSemaphore::tryAcquire(int n, int timeout) /*! \class QSemaphoreReleaser - \brief The QSemaphoreReleaser class provides exception-safe deferral of a QSemaphore::release() call + \brief The QSemaphoreReleaser class provides exception-safe deferral of a QSemaphore::release() call. \since 5.10 \ingroup thread \inmodule QtCore diff --git a/src/corelib/tools/qbytearray.cpp b/src/corelib/tools/qbytearray.cpp index 651f260f0e..d8d8be7a26 100644 --- a/src/corelib/tools/qbytearray.cpp +++ b/src/corelib/tools/qbytearray.cpp @@ -3917,8 +3917,8 @@ T toIntegral_helper(const char *data, bool *ok, int base) Returns 0 if the conversion fails. - If \a ok is not 0: if a conversion error occurs, *\a{ok} is set to - false; otherwise *\a{ok} is set to true. + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. \note The conversion of the number is performed in the default C locale, irrespective of the user's locale. @@ -3943,8 +3943,8 @@ qlonglong QByteArray::toLongLong(bool *ok, int base) const Returns 0 if the conversion fails. - If \a ok is not 0: if a conversion error occurs, *\a{ok} is set to - false; otherwise *\a{ok} is set to true. + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. \note The conversion of the number is performed in the default C locale, irrespective of the user's locale. @@ -3968,8 +3968,8 @@ qulonglong QByteArray::toULongLong(bool *ok, int base) const Returns 0 if the conversion fails. - If \a ok is not 0: if a conversion error occurs, *\a{ok} is set to - false; otherwise *\a{ok} is set to true. + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. \snippet code/src_corelib_tools_qbytearray.cpp 36 @@ -3995,8 +3995,8 @@ int QByteArray::toInt(bool *ok, int base) const Returns 0 if the conversion fails. - If \a ok is not 0: if a conversion error occurs, *\a{ok} is set to - false; otherwise *\a{ok} is set to true. + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. \note The conversion of the number is performed in the default C locale, irrespective of the user's locale. @@ -4022,8 +4022,8 @@ uint QByteArray::toUInt(bool *ok, int base) const Returns 0 if the conversion fails. - If \a ok is not 0: if a conversion error occurs, *\a{ok} is set to - false; otherwise *\a{ok} is set to true. + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. \snippet code/src_corelib_tools_qbytearray.cpp 37 @@ -4050,8 +4050,8 @@ long QByteArray::toLong(bool *ok, int base) const Returns 0 if the conversion fails. - If \a ok is not 0: if a conversion error occurs, *\a{ok} is set to - false; otherwise *\a{ok} is set to true. + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. \note The conversion of the number is performed in the default C locale, irrespective of the user's locale. @@ -4074,8 +4074,8 @@ ulong QByteArray::toULong(bool *ok, int base) const Returns 0 if the conversion fails. - If \a ok is not 0: if a conversion error occurs, *\a{ok} is set to - false; otherwise *\a{ok} is set to true. + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. \note The conversion of the number is performed in the default C locale, irrespective of the user's locale. @@ -4099,8 +4099,8 @@ short QByteArray::toShort(bool *ok, int base) const Returns 0 if the conversion fails. - If \a ok is not 0: if a conversion error occurs, *\a{ok} is set to - false; otherwise *\a{ok} is set to true. + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. \note The conversion of the number is performed in the default C locale, irrespective of the user's locale. @@ -4119,8 +4119,8 @@ ushort QByteArray::toUShort(bool *ok, int base) const Returns 0.0 if the conversion fails. - If \a ok is not 0: if a conversion error occurs, *\a{ok} is set to - false; otherwise *\a{ok} is set to true. + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. \snippet code/src_corelib_tools_qbytearray.cpp 38 @@ -4146,8 +4146,8 @@ double QByteArray::toDouble(bool *ok) const Returns 0.0 if the conversion fails. - If \a ok is not 0: if a conversion error occurs, *\a{ok} is set to - false; otherwise *\a{ok} is set to true. + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. \note The conversion of the number is performed in the default C locale, irrespective of the user's locale. diff --git a/src/corelib/tools/qbytearraymatcher.cpp b/src/corelib/tools/qbytearraymatcher.cpp index 06d01f9829..a54afc5a9d 100644 --- a/src/corelib/tools/qbytearraymatcher.cpp +++ b/src/corelib/tools/qbytearraymatcher.cpp @@ -334,7 +334,7 @@ int qFindByteArray( \class QStaticByteArrayMatcher \since 5.9 \inmodule QtCore - \brief The QStaticByteArrayMatcher class is a compile-time version of QByteArrayMatcher + \brief The QStaticByteArrayMatcher class is a compile-time version of QByteArrayMatcher. \ingroup tools \ingroup string-processing @@ -366,6 +366,11 @@ int qFindByteArray( Since this class is designed to do all the up-front calculations at compile-time, it does not offer a setPattern() method. + \note Qt detects the necessary C++14 compiler support by way of the feature + test recommendations from + \l{https://isocpp.org/std/standing-documents/sd-6-sg10-feature-test-recommendations} + {C++ Committee's Standing Document 6}. + \sa QByteArrayMatcher, QStringMatcher */ diff --git a/src/corelib/tools/qlocale.cpp b/src/corelib/tools/qlocale.cpp index 9c1e78ee61..e70630eb12 100644 --- a/src/corelib/tools/qlocale.cpp +++ b/src/corelib/tools/qlocale.cpp @@ -1262,8 +1262,8 @@ QString QLocale::scriptToString(QLocale::Script script) If the conversion fails the function returns 0. - If \a ok is not 0, failure is reported by setting *ok to false, and - success by setting *ok to true. + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. This function ignores leading and trailing whitespace. @@ -1280,8 +1280,8 @@ short QLocale::toShort(const QString &s, bool *ok) const If the conversion fails the function returns 0. - If \a ok is not 0, failure is reported by setting *ok to false, and - success by setting *ok to true. + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. This function ignores leading and trailing whitespace. @@ -1298,8 +1298,8 @@ ushort QLocale::toUShort(const QString &s, bool *ok) const If the conversion fails the function returns 0. - If \a ok is not 0, failure is reported by setting *ok to false, and - success by setting *ok to true. + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. This function ignores leading and trailing whitespace. @@ -1316,8 +1316,8 @@ int QLocale::toInt(const QString &s, bool *ok) const If the conversion fails the function returns 0. - If \a ok is not 0, failure is reported by setting *ok to false, and - success by setting *ok to true. + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. This function ignores leading and trailing whitespace. @@ -1334,8 +1334,8 @@ uint QLocale::toUInt(const QString &s, bool *ok) const If the conversion fails the function returns 0. - If \a ok is not 0, failure is reported by setting *ok to false, and - success by setting *ok to true. + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. This function ignores leading and trailing whitespace. @@ -1354,8 +1354,8 @@ qlonglong QLocale::toLongLong(const QString &s, bool *ok) const If the conversion fails the function returns 0. - If \a ok is not 0, failure is reported by setting *ok to false, and - success by setting *ok to true. + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. This function ignores leading and trailing whitespace. @@ -1371,8 +1371,11 @@ qulonglong QLocale::toULongLong(const QString &s, bool *ok) const Returns the float represented by the localized string \a s, or 0.0 if the conversion failed. - If \a ok is not 0, reports failure by setting - *ok to false and success by setting *ok to true. + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. + + This function does not fall back to the 'C' locale if the string + cannot be interpreted in this locale. This function ignores leading and trailing whitespace. @@ -1388,12 +1391,11 @@ float QLocale::toFloat(const QString &s, bool *ok) const Returns the double represented by the localized string \a s, or 0.0 if the conversion failed. - If \a ok is not 0, reports failure by setting - *ok to false and success by setting *ok to true. + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. - Unlike QString::toDouble(), this function does not use - the 'C' locale if the string cannot be interpreted in this - locale. + This function does not fall back to the 'C' locale if the string + cannot be interpreted in this locale. \snippet code/src_corelib_tools_qlocale.cpp 3 @@ -1415,8 +1417,8 @@ double QLocale::toDouble(const QString &s, bool *ok) const If the conversion fails the function returns 0. - If \a ok is not null, failure is reported by setting *ok to false, and - success by setting *ok to true. + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. This function ignores leading and trailing whitespace. @@ -1435,8 +1437,8 @@ short QLocale::toShort(const QStringRef &s, bool *ok) const If the conversion fails the function returns 0. - If \a ok is not null, failure is reported by setting *ok to false, and - success by setting *ok to true. + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. This function ignores leading and trailing whitespace. @@ -1455,8 +1457,8 @@ ushort QLocale::toUShort(const QStringRef &s, bool *ok) const If the conversion fails the function returns 0. - If \a ok is not null, failure is reported by setting *ok to false, and - success by setting *ok to true. + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. This function ignores leading and trailing whitespace. @@ -1475,8 +1477,8 @@ int QLocale::toInt(const QStringRef &s, bool *ok) const If the conversion fails the function returns 0. - If \a ok is not null, failure is reported by setting *ok to false, and - success by setting *ok to true. + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. This function ignores leading and trailing whitespace. @@ -1495,8 +1497,8 @@ uint QLocale::toUInt(const QStringRef &s, bool *ok) const If the conversion fails the function returns 0. - If \a ok is not null, failure is reported by setting *ok to false, and - success by setting *ok to true. + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. This function ignores leading and trailing whitespace. @@ -1517,8 +1519,8 @@ qlonglong QLocale::toLongLong(const QStringRef &s, bool *ok) const If the conversion fails the function returns 0. - If \a ok is not null, failure is reported by setting *ok to false, and - success by setting *ok to true. + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. This function ignores leading and trailing whitespace. @@ -1536,8 +1538,11 @@ qulonglong QLocale::toULongLong(const QStringRef &s, bool *ok) const Returns the float represented by the localized string \a s, or 0.0 if the conversion failed. - If \a ok is not null, reports failure by setting - *ok to false and success by setting *ok to true. + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. + + This function does not fall back to the 'C' locale if the string + cannot be interpreted in this locale. This function ignores leading and trailing whitespace. @@ -1555,12 +1560,11 @@ float QLocale::toFloat(const QStringRef &s, bool *ok) const Returns the double represented by the localized string \a s, or 0.0 if the conversion failed. - If \a ok is not null, reports failure by setting - *ok to false and success by setting *ok to true. + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. - Unlike QString::toDouble(), this function does not fall back to - the "C" locale if the string cannot be interpreted in this - locale. + This function does not fall back to the 'C' locale if the string + cannot be interpreted in this locale. \snippet code/src_corelib_tools_qlocale.cpp 3 @@ -1585,8 +1589,8 @@ double QLocale::toDouble(const QStringRef &s, bool *ok) const If the conversion fails, the function returns 0. - If \a ok is not null, failure is reported by setting *ok to false, and - success by setting *ok to true. + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. This function ignores leading and trailing whitespace. @@ -1605,8 +1609,8 @@ short QLocale::toShort(QStringView s, bool *ok) const If the conversion fails, the function returns 0. - If \a ok is not null, failure is reported by setting *ok to false, and - success by setting *ok to true. + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. This function ignores leading and trailing whitespace. @@ -1625,8 +1629,8 @@ ushort QLocale::toUShort(QStringView s, bool *ok) const If the conversion fails, the function returns 0. - If \a ok is not null, failure is reported by setting *ok to false, and - success by setting *ok to true. + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. This function ignores leading and trailing whitespace. @@ -1645,8 +1649,8 @@ int QLocale::toInt(QStringView s, bool *ok) const If the conversion fails, the function returns 0. - If \a ok is not null, failure is reported by setting *ok to false, and - success by setting *ok to true. + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. This function ignores leading and trailing whitespace. @@ -1665,8 +1669,8 @@ uint QLocale::toUInt(QStringView s, bool *ok) const If the conversion fails, the function returns 0. - If \a ok is not null, failure is reported by setting *ok to false, and - success by setting *ok to true. + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. This function ignores leading and trailing whitespace. @@ -1687,8 +1691,8 @@ qlonglong QLocale::toLongLong(QStringView s, bool *ok) const If the conversion fails, the function returns 0. - If \a ok is not null, failure is reported by setting *ok to false, and - success by setting *ok to true. + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. This function ignores leading and trailing whitespace. @@ -1706,8 +1710,8 @@ qulonglong QLocale::toULongLong(QStringView s, bool *ok) const Returns the float represented by the localized string \a s, or 0.0 if the conversion failed. - If \a ok is not null, reports failure by setting - *ok to false and success by setting *ok to true. + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. This function ignores leading and trailing whitespace. @@ -1725,8 +1729,8 @@ float QLocale::toFloat(QStringView s, bool *ok) const Returns the double represented by the localized string \a s, or 0.0 if the conversion failed. - If \a ok is not null, reports failure by setting - *ok to false and success by setting *ok to true. + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. Unlike QString::toDouble(), this function does not fall back to the "C" locale if the string cannot be interpreted in this diff --git a/src/corelib/tools/qsharedpointer.cpp b/src/corelib/tools/qsharedpointer.cpp index 22cf516b68..2d5fd2a00e 100644 --- a/src/corelib/tools/qsharedpointer.cpp +++ b/src/corelib/tools/qsharedpointer.cpp @@ -46,7 +46,7 @@ /*! \class QSharedPointer \inmodule QtCore - \brief The QSharedPointer class holds a strong reference to a shared pointer + \brief The QSharedPointer class holds a strong reference to a shared pointer. \since 4.5 \reentrant @@ -315,7 +315,7 @@ /*! \class QWeakPointer \inmodule QtCore - \brief The QWeakPointer class holds a weak reference to a shared pointer + \brief The QWeakPointer class holds a weak reference to a shared pointer. \since 4.5 \reentrant @@ -373,7 +373,7 @@ /*! \class QEnableSharedFromThis \inmodule QtCore - \brief A base class that allows obtaining a QSharedPointer for an object already managed by a shared pointer + \brief A base class that allows obtaining a QSharedPointer for an object already managed by a shared pointer. \since 5.4 You can inherit this class when you need to create a QSharedPointer diff --git a/src/corelib/tools/qstring.cpp b/src/corelib/tools/qstring.cpp index b6731cffcd..d3a6851e2c 100644 --- a/src/corelib/tools/qstring.cpp +++ b/src/corelib/tools/qstring.cpp @@ -7104,8 +7104,8 @@ QString QString::vasprintf(const char *cformat, va_list ap) base, which is 10 by default and must be between 2 and 36, or 0. Returns 0 if the conversion fails. - If a conversion error occurs, *\a{ok} is set to \c false; otherwise - *\a{ok} is set to \c true. + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. If \a base is 0, the C language convention is used: If the string begins with "0x", base 16 is used; if the string begins with "0", @@ -7146,8 +7146,8 @@ qlonglong QString::toIntegral_helper(const QChar *data, int len, bool *ok, int b base, which is 10 by default and must be between 2 and 36, or 0. Returns 0 if the conversion fails. - If a conversion error occurs, *\a{ok} is set to \c false; otherwise - *\a{ok} is set to \c true. + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. If \a base is 0, the C language convention is used: If the string begins with "0x", base 16 is used; if the string begins with "0", @@ -7190,8 +7190,8 @@ qulonglong QString::toIntegral_helper(const QChar *data, uint len, bool *ok, int base, which is 10 by default and must be between 2 and 36, or 0. Returns 0 if the conversion fails. - If a conversion error occurs, *\a{ok} is set to \c false; otherwise - *\a{ok} is set to \c true. + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. If \a base is 0, the C language convention is used: If the string begins with "0x", base 16 is used; if the string begins with "0", @@ -7221,8 +7221,8 @@ long QString::toLong(bool *ok, int base) const base, which is 10 by default and must be between 2 and 36, or 0. Returns 0 if the conversion fails. - If a conversion error occurs, *\a{ok} is set to \c false; otherwise - *\a{ok} is set to \c true. + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. If \a base is 0, the C language convention is used: If the string begins with "0x", base 16 is used; if the string begins with "0", @@ -7251,8 +7251,8 @@ ulong QString::toULong(bool *ok, int base) const base, which is 10 by default and must be between 2 and 36, or 0. Returns 0 if the conversion fails. - If a conversion error occurs, *\a{ok} is set to \c false; otherwise - *\a{ok} is set to \c true. + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. If \a base is 0, the C language convention is used: If the string begins with "0x", base 16 is used; if the string begins with "0", @@ -7280,8 +7280,8 @@ int QString::toInt(bool *ok, int base) const base, which is 10 by default and must be between 2 and 36, or 0. Returns 0 if the conversion fails. - If a conversion error occurs, *\a{ok} is set to \c false; otherwise - *\a{ok} is set to \c true. + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. If \a base is 0, the C language convention is used: If the string begins with "0x", base 16 is used; if the string begins with "0", @@ -7309,8 +7309,8 @@ uint QString::toUInt(bool *ok, int base) const base, which is 10 by default and must be between 2 and 36, or 0. Returns 0 if the conversion fails. - If a conversion error occurs, *\a{ok} is set to \c false; otherwise - *\a{ok} is set to \c true. + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. If \a base is 0, the C language convention is used: If the string begins with "0x", base 16 is used; if the string begins with "0", @@ -7338,8 +7338,8 @@ short QString::toShort(bool *ok, int base) const base, which is 10 by default and must be between 2 and 36, or 0. Returns 0 if the conversion fails. - If a conversion error occurs, *\a{ok} is set to \c false; otherwise - *\a{ok} is set to \c true. + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. If \a base is 0, the C language convention is used: If the string begins with "0x", base 16 is used; if the string begins with "0", @@ -7368,8 +7368,8 @@ ushort QString::toUShort(bool *ok, int base) const Returns 0.0 if the conversion fails. - If a conversion error occurs, \c{*}\a{ok} is set to \c false; - otherwise \c{*}\a{ok} is set to \c true. + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. \snippet qstring/main.cpp 66 @@ -7404,21 +7404,30 @@ double QString::toDouble(bool *ok) const /*! Returns the string converted to a \c float value. - If a conversion error occurs, *\a{ok} is set to \c false; otherwise - *\a{ok} is set to \c true. Returns 0.0 if the conversion fails. + Returns 0.0 if the conversion fails. - This function ignores leading and trailing whitespace. + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. + + \warning The QString content may only contain valid numerical characters + which includes the plus/minus sign, the characters g and e used in scientific + notation, and the decimal point. Including the unit or additional characters + leads to a conversion error. The string conversion will always happen in the 'C' locale. For locale dependent conversion use QLocale::toFloat() + For historical reasons, this function does not handle + thousands group separators. If you need to convert such numbers, + use QLocale::toFloat(). + Example: \snippet qstring/main.cpp 71 This function ignores leading and trailing whitespace. - \sa number(), toDouble(), toInt(), QLocale::toFloat() + \sa number(), toDouble(), toInt(), QLocale::toFloat(), trimmed() */ float QString::toFloat(bool *ok) const @@ -7611,13 +7620,12 @@ QString QString::number(qulonglong n, int base) QString QString::number(double n, char f, int prec) { QLocaleData::DoubleForm form = QLocaleData::DFDecimal; - uint flags = 0; + uint flags = QLocaleData::ZeroPadExponent; if (qIsUpper(f)) - flags = QLocaleData::CapitalEorX; - f = qToLower(f); + flags |= QLocaleData::CapitalEorX; - switch (f) { + switch (qToLower(f)) { case 'f': form = QLocaleData::DFDecimal; break; @@ -8676,14 +8684,13 @@ QString QString::arg(double a, int fieldWidth, char fmt, int prec, QChar fillCha unsigned flags = QLocaleData::NoFlags; if (fillChar == QLatin1Char('0')) - flags = QLocaleData::ZeroPadded; + flags |= QLocaleData::ZeroPadded; if (qIsUpper(fmt)) flags |= QLocaleData::CapitalEorX; - fmt = qToLower(fmt); QLocaleData::DoubleForm form = QLocaleData::DFDecimal; - switch (fmt) { + switch (qToLower(fmt)) { case 'f': form = QLocaleData::DFDecimal; break; @@ -8702,7 +8709,7 @@ QString QString::arg(double a, int fieldWidth, char fmt, int prec, QChar fillCha QString arg; if (d.occurrences > d.locale_occurrences) - arg = QLocaleData::c()->doubleToString(a, prec, form, fieldWidth, flags); + arg = QLocaleData::c()->doubleToString(a, prec, form, fieldWidth, flags | QLocaleData::ZeroPadExponent); QString locale_arg; if (d.locale_occurrences > 0) { @@ -11772,8 +11779,8 @@ QStringRef QStringRef::trimmed() const base, which is 10 by default and must be between 2 and 36, or 0. Returns 0 if the conversion fails. - If a conversion error occurs, *\a{ok} is set to \c false; otherwise - *\a{ok} is set to \c true. + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. If \a base is 0, the C language convention is used: If the string begins with "0x", base 16 is used; if the string begins with "0", @@ -11797,8 +11804,8 @@ qint64 QStringRef::toLongLong(bool *ok, int base) const base, which is 10 by default and must be between 2 and 36, or 0. Returns 0 if the conversion fails. - If a conversion error occurs, *\a{ok} is set to \c false; otherwise - *\a{ok} is set to \c true. + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. If \a base is 0, the C language convention is used: If the string begins with "0x", base 16 is used; if the string begins with "0", @@ -11824,8 +11831,8 @@ quint64 QStringRef::toULongLong(bool *ok, int base) const base, which is 10 by default and must be between 2 and 36, or 0. Returns 0 if the conversion fails. - If a conversion error occurs, *\a{ok} is set to \c false; otherwise - *\a{ok} is set to \c true. + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. If \a base is 0, the C language convention is used: If the string begins with "0x", base 16 is used; if the string begins with "0", @@ -11851,8 +11858,8 @@ long QStringRef::toLong(bool *ok, int base) const base, which is 10 by default and must be between 2 and 36, or 0. Returns 0 if the conversion fails. - If a conversion error occurs, *\a{ok} is set to \c false; otherwise - *\a{ok} is set to \c true. + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. If \a base is 0, the C language convention is used: If the string begins with "0x", base 16 is used; if the string begins with "0", @@ -11877,8 +11884,8 @@ ulong QStringRef::toULong(bool *ok, int base) const base, which is 10 by default and must be between 2 and 36, or 0. Returns 0 if the conversion fails. - If a conversion error occurs, *\a{ok} is set to \c false; otherwise - *\a{ok} is set to \c true. + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. If \a base is 0, the C language convention is used: If the string begins with "0x", base 16 is used; if the string begins with "0", @@ -11902,8 +11909,8 @@ int QStringRef::toInt(bool *ok, int base) const base, which is 10 by default and must be between 2 and 36, or 0. Returns 0 if the conversion fails. - If a conversion error occurs, *\a{ok} is set to \c false; otherwise - *\a{ok} is set to \c true. + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. If \a base is 0, the C language convention is used: If the string begins with "0x", base 16 is used; if the string begins with "0", @@ -11927,8 +11934,8 @@ uint QStringRef::toUInt(bool *ok, int base) const base, which is 10 by default and must be between 2 and 36, or 0. Returns 0 if the conversion fails. - If a conversion error occurs, *\a{ok} is set to \c false; otherwise - *\a{ok} is set to \c true. + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. If \a base is 0, the C language convention is used: If the string begins with "0x", base 16 is used; if the string begins with "0", @@ -11952,8 +11959,8 @@ short QStringRef::toShort(bool *ok, int base) const base, which is 10 by default and must be between 2 and 36, or 0. Returns 0 if the conversion fails. - If a conversion error occurs, *\a{ok} is set to \c false; otherwise - *\a{ok} is set to \c true. + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. If \a base is 0, the C language convention is used: If the string begins with "0x", base 16 is used; if the string begins with "0", @@ -11978,8 +11985,8 @@ ushort QStringRef::toUShort(bool *ok, int base) const Returns 0.0 if the conversion fails. - If a conversion error occurs, \c{*}\a{ok} is set to \c false; - otherwise \c{*}\a{ok} is set to \c true. + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. The string conversion will always happen in the 'C' locale. For locale dependent conversion use QLocale::toDouble() @@ -12001,8 +12008,10 @@ double QStringRef::toDouble(bool *ok) const /*! Returns the string converted to a \c float value. - If a conversion error occurs, *\a{ok} is set to \c false; otherwise - *\a{ok} is set to \c true. Returns 0.0 if the conversion fails. + Returns 0.0 if the conversion fails. + + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. The string conversion will always happen in the 'C' locale. For locale dependent conversion use QLocale::toFloat() diff --git a/src/corelib/tools/qstringiterator.qdoc b/src/corelib/tools/qstringiterator.qdoc index caec8803f3..9d7c54ce9f 100644 --- a/src/corelib/tools/qstringiterator.qdoc +++ b/src/corelib/tools/qstringiterator.qdoc @@ -3,9 +3,9 @@ ** Copyright (C) 2014 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Giuseppe D'Angelo ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the QtCore module of the Qt Toolkit. +** This file is part of the documentation of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL$ +** $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 @@ -14,25 +14,13 @@ ** 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. -** +** 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$ ** ****************************************************************************/ diff --git a/src/corelib/tools/qtimezoneprivate_android.cpp b/src/corelib/tools/qtimezoneprivate_android.cpp index c3f8c3e0d9..b60093617f 100644 --- a/src/corelib/tools/qtimezoneprivate_android.cpp +++ b/src/corelib/tools/qtimezoneprivate_android.cpp @@ -82,7 +82,24 @@ void QAndroidTimeZonePrivate::init(const QByteArray &ianaId) QJNIObjectPrivate jo_ianaId = QJNIObjectPrivate::fromString( QString::fromUtf8(ianaId) ); androidTimeZone = QJNIObjectPrivate::callStaticObjectMethod( "java.util.TimeZone", "getTimeZone", "(Ljava/lang/String;)Ljava/util/TimeZone;", static_cast(jo_ianaId.object()) ); - if (ianaId.isEmpty()) + // Painfully, JNI gives us back a default zone object if it doesn't + // recognize the name; so check for whether ianaId is a recognized name of + // the zone object we got and ignore the zone if not. + bool found = false; + // Try checking ianaId against getID(), getDisplayName(): + QJNIObjectPrivate jname = androidTimeZone.callObjectMethod("getID", "()Ljava/lang/String;"); + found = (jname.toString().toUtf8() == ianaId); + for (int style = 1; !found && style-- > 0;) { + for (int dst = 1; !found && dst-- > 0;) { + jname = androidTimeZone.callObjectMethod("getDisplayName", "(ZI;)Ljava/lang/String;", + bool(dst), style); + found = (jname.toString().toUtf8() == ianaId); + } + } + + if (!found) + m_id.clear(); + else if (ianaId.isEmpty()) m_id = systemTimeZoneId(); else m_id = ianaId; diff --git a/src/corelib/tools/qvector.qdoc b/src/corelib/tools/qvector.qdoc index 9a08b030f7..75b17a4207 100644 --- a/src/corelib/tools/qvector.qdoc +++ b/src/corelib/tools/qvector.qdoc @@ -3,9 +3,9 @@ ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the QtCore module of the Qt Toolkit. +** This file is part of the documentation of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL$ +** $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 @@ -14,25 +14,13 @@ ** 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. -** +** 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$ ** ****************************************************************************/ diff --git a/src/dbus/doc/snippets/code/doc_src_qdbusadaptors.cpp b/src/dbus/doc/snippets/code/doc_src_qdbusadaptors.cpp index 0f43cd73fb..0fc7a2b26c 100644 --- a/src/dbus/doc/snippets/code/doc_src_qdbusadaptors.cpp +++ b/src/dbus/doc/snippets/code/doc_src_qdbusadaptors.cpp @@ -48,218 +48,6 @@ ** ****************************************************************************/ -//! [0] -class MainApplicationAdaptor: public QDBusAbstractAdaptor -{ - Q_OBJECT - Q_CLASSINFO("D-Bus Interface", "org.kde.DBus.MainApplication") - Q_PROPERTY(QString caption READ caption WRITE setCaption) - Q_PROPERTY(QString organizationName READ organizationName) - Q_PROPERTY(QString organizationDomain READ organizationDomain) - -private: - QApplication *app; - -public: - MainApplicationAdaptor(QApplication *application) - : QDBusAbstractAdaptor(application), app(application) - { - connect(application, SIGNAL(aboutToQuit()), SIGNAL(aboutToQuit())); - connect(application, SIGNAL(focusChanged(QWidget*,QWidget*)), - SLOT(focusChangedSlot(QWidget*,QWidget*))); - } - - QString caption() - { - if (app->hasMainWindow()) - return app->mainWindow()->caption(); - return QString(""); // must not return a null QString - } - - void setCaption(const QString &newCaption) - { - if (app->hasMainWindow()) - app->mainWindow()->setCaption(newCaption); - } - - QString organizationName() - { - return app->organizationName(); - } - - QString organizationDomain() - { - return app->organizationDomain(); - } - -public slots: - Q_NOREPLY void quit() - { app->quit(); } - - void reparseConfiguration() - { app->reparseConfiguration(); } - - QString mainWindowObject() - { - if (app->hasMainWindow()) - return QString("/%1/mainwindow").arg(app->applicationName()); - return QString(); - } - - void setSessionManagement(bool enable) - { - if (enable) - app->enableSessionManagement(); - else - app->disableSessionManagement(); - } - -private slots: - void focusChangedSlot(QWidget *, QWidget *now) - { - if (now == app->mainWindow()) - emit mainWindowHasFocus(); - } - -signals: - void aboutToQuit(); - void mainWindowHasFocus(); -}; -//! [0] - - -//! [1] -interface org.kde.DBus.MainApplication -{ - property readwrite STRING caption - property read STRING organizationName - property read STRING organizationDomain - - method quit() annotation("org.freedesktop.DBus.Method.NoReply", "true") - method reparseConfiguration() - method mainWindowObject(out STRING) - method disableSessionManagement(in BOOLEAN enable) - - signal aboutToQuit() - signal mainWindowHasFocus() -} -//! [1] - - -//! [2] -int main(int argc, char **argv) -{ - // create the QApplication object - QApplication app(argc, argv); - - // create the MainApplication adaptor: - new MainApplicationAdaptor(app); - - // connect to D-Bus and register as an object: - QDBusConnection::sessionBus().registerObject("/MainApplication", &app); - - // add main window, etc. - [...] - - app.exec(); -} -//! [2] - - -//! [3] -class MainApplicationAdaptor: public QDBusAbstractAdaptor -{ - Q_OBJECT - Q_CLASSINFO("D-Bus Interface", "org.kde.DBus.MainApplication") -//! [3] - - -//! [4] - Q_PROPERTY(QString caption READ caption WRITE setCaption) - Q_PROPERTY(QString organizationName READ organizationName) - Q_PROPERTY(QString organizationDomain READ organizationDomain) -//! [4] - - -//! [5] -QString caption() -{ - if (app->hasMainWindow()) - return app->mainWindow()->caption(); - return QString(); -} - -void setCaption(const QString &newCaption) -{ - if (app->hasMainWindow()) - app->mainWindow()->setCaption(newCaption); -} - -QString organizationName() -{ - return app->organizationName(); -} - -QString organizationDomain() -{ - return app->organizationDomain(); -} -//! [5] - - -//! [6] -MyInterfaceAdaptor(QApplication *application) - : QDBusAbstractAdaptor(application), app(application) -{ - connect(application, SIGNAL(aboutToQuit()), SIGNAL(aboutToQuit()); - connect(application, SIGNAL(focusChanged(QWidget*,QWidget*)), - SLOT(focusChangedSlot(QWidget*,QWidget*))); -} -//! [6] - - -//! [7] -public slots: - Q_NOREPLY void quit() - { app->quit(); } - - void reparseConfiguration() - { app->reparseConfiguration(); } - - QString mainWindowObject() - { - if (app->hasMainWindow()) - return QString("/%1/mainwindow").arg(app->applicationName()); - return QString(); - } - - void setSessionManagement(bool enable) - { - if (enable) - app->enableSessionManagement(); - else - app->disableSessionManagement(); - } -//! [7] - - -//! [8] -signals: - void aboutToQuit(); - void mainWindowHasFocus(); -//! [8] - - -//! [9] -private slots: - void focusChangedSlot(QWidget *, QWidget *now) - { - if (now == app->mainWindow()) - emit mainWindowHasFocus(); - } -//! [9] - - //! [10] struct RequestData { diff --git a/src/dbus/doc/src/dbus-adaptors.qdoc b/src/dbus/doc/src/dbus-adaptors.qdoc index 0b0dacf819..9ebf0cedf2 100644 --- a/src/dbus/doc/src/dbus-adaptors.qdoc +++ b/src/dbus/doc/src/dbus-adaptors.qdoc @@ -68,132 +68,13 @@ \li \l{Declaring Slots in D-Bus Adaptors} \li \l{Declaring Signals in D-Bus Adaptors} \li \l{The Qt D-Bus Type System} - \li \l{D-Bus Adaptor Example} + \li In the \l{D-Bus Complex Ping Pong Example}, \c complexpong.h and + \c complexpong.cpp show an implementation of QDBusAbstractAdaptor. \endlist \sa QDBusAbstractAdaptor */ -/*! - \page qdbusadaptorexample.html - \title D-Bus Adaptor Example - - \previouspage The Qt D-Bus Type System - \contentspage Using Qt D-Bus Adaptors - - The following example code shows how a D-Bus interface can be implemented - using an adaptor. - - A sample usage of QDBusAbstractAdaptor is as follows: - \snippet code/doc_src_qdbusadaptors.cpp 0 - - The code above would create an interface that could be represented more or less in the following - canonical representation: - \snippet code/doc_src_qdbusadaptors.cpp 1 - - This adaptor could be used in the application's main function as follows - \snippet code/doc_src_qdbusadaptors.cpp 2 - - Break-down analysis: - \tableofcontents - - \section1 The Header - - The header of the example is: - \snippet code/doc_src_qdbusadaptors.cpp 3 - - The code does the following: - \list - \li it declares the adaptor MainApplicationAdaptor, which descends from QDBusAbstractAdaptor - \li it declares the Qt meta-object data using the Q_OBJECT macro - \li it declares the name of the D-Bus interface it implements. - \endlist - - \section1 The Properties - - The properties are declared as follows: - \snippet code/doc_src_qdbusadaptors.cpp 4 - - And are implemented as follows: - \snippet code/doc_src_qdbusadaptors.cpp 5 - - The code declares three properties: one of them is a read-write property called "caption" of - string type. The other two are read-only, also of the string type. - - The properties organizationName and organizationDomain are simple relays of the app object's - organizationName and organizationDomain properties. However, the caption property requires - verifying if the application has a main window associated with it: if there isn't any, the - caption property is empty. Note how it is possible to access data defined in other objects - through the getter/setter functions. - - \section1 The Constructor - - The constructor: - \snippet code/doc_src_qdbusadaptors.cpp 6 - - The constructor does the following: - \list - \li it initialises its base class (QDBusAbstractAdaptor) with the parent object it is related to. - \li it stores the app pointer in a member variable. Note that it would be possible to access the - same object using the QDBusAbstractAdaptor::object() function, but it would be necessary to - use \a static_cast<> to properly access the methods in QApplication that are not part of - QObject. - \li it connects the application's signal \a aboutToQuit to its own signal \a aboutToQuit. - \li it connects the application's signal \a focusChanged to a private slot to do some further - processing before emitting a D-Bus signal. - \endlist - - Note that there is no destructor in the example. An eventual destructor could be used to emit - one last signal before the object is destroyed, for instance. - - \section1 Slots/methods - - The public slots in the example (which will be exported as D-Bus methods) are the following: - \snippet code/doc_src_qdbusadaptors.cpp 7 - - This snippet of code defines 4 methods with different properties each: - \list 1 - \li \c quit: this method takes no parameters and is defined to be asynchronous. That is, callers - are expected to use "fire-and-forget" mechanism when calling this method, since it provides no - useful reply. This is represented in D-Bus by the use of the - org.freedesktop.DBus.Method.NoReply annotation. See \l Q_NOREPLY for more information on - asynchronous methods - - \li \c reparseConfiguration: this simple method, with no input or output arguments simply relays - the call to the application's reparseConfiguration member function. - - \li \c mainWindowObject: this method takes no input parameter, but returns one string output - argument, containing the path to the main window object (if the application has a main - window), or an empty string if it has no main window. Note that this method could have also - been written: void mainWindowObject(QString &path). - - \li \c setSessionManagement: this method takes one input argument (a boolean) and, depending on - its value, it calls one function or another in the application. - \endlist - - See also: \l Q_NOREPLY. - - \section1 Signals - - The signals in this example are defined as follows: - \snippet code/doc_src_qdbusadaptors.cpp 8 - - However, signal definition isn't enough: signals have to be emitted. One simple way of emitting - signals is to connect another signal to them, so that Qt's signal handling system chains them - automatically. This is what is done for the \a aboutToQuit signal. - - When this is the case, one can use the QDBusAbstractAdaptor::setAutoRelaySignals to - automatically connect every signal from the real object to the adaptor. - - When simple signal-to-signal connection isn't enough, one can use a private slot do do some - work. This is what was done for the mainWindowHasFocus signal: - \snippet code/doc_src_qdbusadaptors.cpp 9 - - This private slot (which will not be exported as a method via D-Bus) was connected to the - \c focusChanged signal in the adaptor's constructor. It is therefore able to shape the - application's signal into what the interface expects it to be. -*/ - /*! \page qdbusdeclaringslots.html \title Declaring Slots in D-Bus Adaptors @@ -230,8 +111,8 @@ synchronize with the caller should provide its own method of synchronization. Asynchronous slots are marked by the keyword \l Q_NOREPLY in the method - signature, before the \c void return type and the slot name. (See the - \c quit() slot in the \l{D-Bus Adaptor Example}). + signature, before the \c void return type and the slot name. The \c quit() + slot in the \l {D-Bus Complex Ping Pong Example} is an example of this. \section1 Input-Only Slots @@ -341,8 +222,8 @@ However, signals must still be emitted. The easiest way to emit an adaptor signal is to connect another signal to it, so that Qt's signals and slots mechanism automatically emits the adaptor signal, too. This can be done in - the adaptor's constructor, as has been done in the - \l{D-Bus Adaptor Example}{D-Bus Adaptor example}. + the adaptor's constructor, as you can see in the \l {D-Bus Complex Ping + Pong Example}. The QDBusAbstractAdaptor::setAutoRelaySignals() convenience function can also be used to make and break connections between signals in the real object and @@ -360,7 +241,6 @@ \previouspage Declaring Signals in D-Bus Adaptors \contentspage Using Qt D-Bus Adaptors - \nextpage D-Bus Adaptor Example D-Bus has an extensible type system based on a few primitives and composition of the primitives in arrays and structures. Qt D-Bus diff --git a/src/dbus/qdbusabstractinterface.cpp b/src/dbus/qdbusabstractinterface.cpp index 7ddf68daa0..148bd54147 100644 --- a/src/dbus/qdbusabstractinterface.cpp +++ b/src/dbus/qdbusabstractinterface.cpp @@ -305,7 +305,7 @@ int QDBusAbstractInterfaceBase::qt_metacall(QMetaObject::Call _c, int _id, void \inmodule QtDBus \since 4.2 - \brief The QDBusAbstractInterface class is the base class for all D-Bus interfaces in the Qt D-Bus binding, allowing access to remote interfaces + \brief The QDBusAbstractInterface class is the base class for all D-Bus interfaces in the Qt D-Bus binding, allowing access to remote interfaces. Generated-code classes also derive from QDBusAbstractInterface, all methods described here are also valid for generated-code diff --git a/src/dbus/qdbuspendingcall.cpp b/src/dbus/qdbuspendingcall.cpp index bd6eb9eca3..2a31dd950a 100644 --- a/src/dbus/qdbuspendingcall.cpp +++ b/src/dbus/qdbuspendingcall.cpp @@ -58,7 +58,7 @@ QT_BEGIN_NAMESPACE \ingroup shared \since 4.5 - \brief The QDBusPendingCall class refers to one pending asynchronous call + \brief The QDBusPendingCall class refers to one pending asynchronous call. A QDBusPendingCall object is a reference to a method call that was sent over D-Bus without waiting for a reply. QDBusPendingCall is an @@ -91,7 +91,7 @@ QT_BEGIN_NAMESPACE \since 4.5 \brief The QDBusPendingCallWatcher class provides a convenient way for - waiting for asynchronous replies + waiting for asynchronous replies. The QDBusPendingCallWatcher provides the finished() signal that will be emitted when a reply arrives. diff --git a/src/dbus/qdbuspendingreply.cpp b/src/dbus/qdbuspendingreply.cpp index c0baa4a005..fef6f36432 100644 --- a/src/dbus/qdbuspendingreply.cpp +++ b/src/dbus/qdbuspendingreply.cpp @@ -49,7 +49,7 @@ \inmodule QtDBus \since 4.5 - \brief The QDBusPendingReply class contains the reply to an asynchronous method call + \brief The QDBusPendingReply class contains the reply to an asynchronous method call. The QDBusPendingReply is a template class with up to 8 template parameters. Those parameters are the types that will be used to diff --git a/src/gui/itemmodels/qstandarditemmodel.cpp b/src/gui/itemmodels/qstandarditemmodel.cpp index f55e90c153..235bc5bd7d 100644 --- a/src/gui/itemmodels/qstandarditemmodel.cpp +++ b/src/gui/itemmodels/qstandarditemmodel.cpp @@ -142,6 +142,8 @@ void QStandardItemPrivate::setChild(int row, int column, QStandardItem *item, oldItem->d_func()->setModel(0); delete oldItem; children.replace(index, item); + if (item) + item->d_func()->lastKnownIndex = index; if (model && emitChanged) emit model->layoutChanged(); @@ -475,6 +477,8 @@ bool QStandardItemPrivate::insertRows(int row, const QList &item item->d_func()->parent = q; int index = childIndex(i + row, 0); children.replace(index, item); + if (item) + item->d_func()->lastKnownIndex = index; } if (model) model->d_func()->rowsInserted(q, row, count); @@ -512,6 +516,8 @@ bool QStandardItemPrivate::insertRows(int row, int count, const QListd_func()->lastKnownIndex = index; ++index; } } @@ -558,6 +564,8 @@ bool QStandardItemPrivate::insertColumns(int column, int count, const QListd_func()->lastKnownIndex = index; } } if (model) diff --git a/src/gui/itemmodels/qstandarditemmodel_p.h b/src/gui/itemmodels/qstandarditemmodel_p.h index d3ff2787a5..00e83f7b08 100644 --- a/src/gui/itemmodels/qstandarditemmodel_p.h +++ b/src/gui/itemmodels/qstandarditemmodel_p.h @@ -114,7 +114,7 @@ public: rows(0), columns(0), q_ptr(0), - lastIndexOf(2) + lastKnownIndex(-1) { } inline int childIndex(int row, int column) const { @@ -124,12 +124,40 @@ public: } return (row * columnCount()) + column; } - inline int childIndex(const QStandardItem *child) { - int start = qMax(0, lastIndexOf -2); - lastIndexOf = children.indexOf(const_cast(child), start); - if (lastIndexOf == -1 && start != 0) - lastIndexOf = children.lastIndexOf(const_cast(child), start); - return lastIndexOf; + inline int childIndex(const QStandardItem *child) const { + const int lastChild = children.size() - 1; + int &childsLastIndexInParent = child->d_func()->lastKnownIndex; + if (childsLastIndexInParent != -1 && childsLastIndexInParent <= lastChild) { + if (children.at(childsLastIndexInParent) == child) + return childsLastIndexInParent; + } else { + childsLastIndexInParent = lastChild / 2; + } + + // assuming the item is in the vicinity of the previous index, iterate forwards and + // backwards through the children + int backwardIter = childsLastIndexInParent - 1; + int forwardIter = childsLastIndexInParent; + Q_FOREVER { + if (forwardIter <= lastChild) { + if (children.at(forwardIter) == child) { + childsLastIndexInParent = forwardIter; + break; + } + ++forwardIter; + } else if (backwardIter < 0) { + childsLastIndexInParent = -1; + break; + } + if (backwardIter >= 0) { + if (children.at(backwardIter) == child) { + childsLastIndexInParent = backwardIter; + break; + } + --backwardIter; + } + } + return childsLastIndexInParent; } QPair position() const; void setChild(int row, int column, QStandardItem *item, @@ -170,7 +198,7 @@ public: QStandardItem *q_ptr; - int lastIndexOf; + mutable int lastKnownIndex; // this is a cached value }; class QStandardItemModelPrivate : public QAbstractItemModelPrivate diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp index 57123f4831..91348265cd 100644 --- a/src/gui/kernel/qguiapplication.cpp +++ b/src/gui/kernel/qguiapplication.cpp @@ -1300,10 +1300,18 @@ void QGuiApplicationPrivate::createPlatformIntegration() #if defined(Q_OS_UNIX) && !defined(Q_OS_DARWIN) QByteArray sessionType = qgetenv("XDG_SESSION_TYPE"); if (!sessionType.isEmpty()) { - if (sessionType == QByteArrayLiteral("x11") && !platformName.contains(QByteArrayLiteral("xcb"))) + if (sessionType == QByteArrayLiteral("x11") && !platformName.contains(QByteArrayLiteral("xcb"))) { platformName = QByteArrayLiteral("xcb"); - else if (sessionType == QByteArrayLiteral("wayland") && !platformName.contains(QByteArrayLiteral("wayland"))) - platformName = QByteArrayLiteral("wayland"); + } else if (sessionType == QByteArrayLiteral("wayland") && !platformName.contains(QByteArrayLiteral("wayland"))) { + QByteArray currentDesktop = qgetenv("XDG_CURRENT_DESKTOP").toLower(); + QByteArray sessionDesktop = qgetenv("XDG_SESSION_DESKTOP").toLower(); + if (currentDesktop.contains("gnome") || sessionDesktop.contains("gnome")) { + qInfo() << "Warning: Ignoring XDG_SESSION_TYPE=wayland on Gnome." + << "Use QT_QPA_PLATFORM=wayland to run on Wayland anyway."; + } else { + platformName = QByteArrayLiteral("wayland"); + } + } } #ifdef QT_QPA_DEFAULT_PLATFORM_NAME // Add it as fallback in case XDG_SESSION_TYPE is something wrong diff --git a/src/gui/kernel/qpixelformat.cpp b/src/gui/kernel/qpixelformat.cpp index c132a1418e..c28fe7ac63 100644 --- a/src/gui/kernel/qpixelformat.cpp +++ b/src/gui/kernel/qpixelformat.cpp @@ -46,7 +46,7 @@ QT_BEGIN_NAMESPACE \inmodule QtGui \since 5.4 \brief QPixelFormat is a class for describing different pixel - layouts in graphics buffers + layouts in graphics buffers. In Qt there is a often a need to represent the layout of the pixels in a graphics buffer. Internally QPixelFormat stores everything in a 64 bit diff --git a/src/gui/kernel/qrasterwindow.cpp b/src/gui/kernel/qrasterwindow.cpp index d06fee62cf..c88654e794 100644 --- a/src/gui/kernel/qrasterwindow.cpp +++ b/src/gui/kernel/qrasterwindow.cpp @@ -50,7 +50,7 @@ QT_BEGIN_NAMESPACE \class QRasterWindow \inmodule QtGui \since 5.4 - \brief QRasterWindow is a convenience class for using QPainter on a QWindow + \brief QRasterWindow is a convenience class for using QPainter on a QWindow. QRasterWindow is a QWindow with a raster-based, non-OpenGL surface. On top of the functionality offered by QWindow, QRasterWindow adds a virtual diff --git a/src/gui/kernel/qwindow.cpp b/src/gui/kernel/qwindow.cpp index 2258027979..75f63c046f 100644 --- a/src/gui/kernel/qwindow.cpp +++ b/src/gui/kernel/qwindow.cpp @@ -2840,7 +2840,7 @@ void QWindow::setVulkanInstance(QVulkanInstance *instance) } /*! - \return the associrated Vulkan instance or \c null if there is none. + \return the associated Vulkan instance or \c null if there is none. */ QVulkanInstance *QWindow::vulkanInstance() const { diff --git a/src/gui/opengl/qopenglfunctions_es2.cpp b/src/gui/opengl/qopenglfunctions_es2.cpp index 59e275dce1..dd2b3af80b 100644 --- a/src/gui/opengl/qopenglfunctions_es2.cpp +++ b/src/gui/opengl/qopenglfunctions_es2.cpp @@ -47,7 +47,7 @@ QT_BEGIN_NAMESPACE \inmodule QtGui \since 5.1 \wrapper - \brief The QOpenGLFunctions_ES2 class provides all functions for OpenGL ES 2 + \brief The QOpenGLFunctions_ES2 class provides all functions for OpenGL ES 2. This class is a wrapper for OpenGL ES 2 functions. See reference pages on \l {http://www.khronos.org/opengles/sdk/docs/man/}{khronos.org} for diff --git a/src/gui/opengl/qopenglpaintengine.cpp b/src/gui/opengl/qopenglpaintengine.cpp index fb7e6fce97..e390183893 100644 --- a/src/gui/opengl/qopenglpaintengine.cpp +++ b/src/gui/opengl/qopenglpaintengine.cpp @@ -864,20 +864,18 @@ void QOpenGL2PaintEngineExPrivate::fill(const QVectorPath& path) if (data) { cache = (QOpenGL2PEVectorPathCache *) data->data; - // Check if scale factor is exceeded for curved paths and generate curves if so... - if (path.isCurved()) { - qreal scaleFactor = cache->iscale / inverseScale; - if (scaleFactor < 0.5 || scaleFactor > 2.0) { + // Check if scale factor is exceeded and regenerate if so... + qreal scaleFactor = cache->iscale / inverseScale; + if (scaleFactor < 0.5 || scaleFactor > 2.0) { #ifdef QT_OPENGL_CACHE_AS_VBOS - glDeleteBuffers(1, &cache->vbo); - cache->vbo = 0; - Q_ASSERT(cache->ibo == 0); + glDeleteBuffers(1, &cache->vbo); + cache->vbo = 0; + Q_ASSERT(cache->ibo == 0); #else - free(cache->vertices); - Q_ASSERT(cache->indices == 0); + free(cache->vertices); + Q_ASSERT(cache->indices == 0); #endif - updateCache = true; - } + updateCache = true; } } else { cache = new QOpenGL2PEVectorPathCache; @@ -946,19 +944,17 @@ void QOpenGL2PaintEngineExPrivate::fill(const QVectorPath& path) if (data) { cache = (QOpenGL2PEVectorPathCache *) data->data; - // Check if scale factor is exceeded for curved paths and generate curves if so... - if (path.isCurved()) { - qreal scaleFactor = cache->iscale / inverseScale; - if (scaleFactor < 0.5 || scaleFactor > 2.0) { + // Check if scale factor is exceeded and regenerate if so... + qreal scaleFactor = cache->iscale / inverseScale; + if (scaleFactor < 0.5 || scaleFactor > 2.0) { #ifdef QT_OPENGL_CACHE_AS_VBOS - glDeleteBuffers(1, &cache->vbo); - glDeleteBuffers(1, &cache->ibo); + glDeleteBuffers(1, &cache->vbo); + glDeleteBuffers(1, &cache->ibo); #else - free(cache->vertices); - free(cache->indices); + free(cache->vertices); + free(cache->indices); #endif - updateCache = true; - } + updateCache = true; } } else { cache = new QOpenGL2PEVectorPathCache; diff --git a/src/gui/painting/qmatrix.cpp b/src/gui/painting/qmatrix.cpp index 681490e347..24b33243da 100644 --- a/src/gui/painting/qmatrix.cpp +++ b/src/gui/painting/qmatrix.cpp @@ -992,12 +992,12 @@ bool QMatrix::operator==(const QMatrix &m) const uint qHash(const QMatrix &key, uint seed) Q_DECL_NOTHROW { QtPrivate::QHashCombine hash; - seed = hash(key.m11(), seed); - seed = hash(key.m12(), seed); - seed = hash(key.m21(), seed); - seed = hash(key.m22(), seed); - seed = hash(key.dx(), seed); - seed = hash(key.dy(), seed); + seed = hash(seed, key.m11()); + seed = hash(seed, key.m12()); + seed = hash(seed, key.m21()); + seed = hash(seed, key.m22()); + seed = hash(seed, key.dx()); + seed = hash(seed, key.dy()); return seed; } diff --git a/src/gui/painting/qpagesize.cpp b/src/gui/painting/qpagesize.cpp index 9cbe6ef911..a1c9f6e417 100644 --- a/src/gui/painting/qpagesize.cpp +++ b/src/gui/painting/qpagesize.cpp @@ -908,7 +908,7 @@ QSize QPageSizePrivate::sizePixels(int resolution) const \class QPageSize \inmodule QtGui \since 5.3 - \brief The QPageSize class describes the size and name of a defined page size + \brief The QPageSize class describes the size and name of a defined page size. This class implements support for the set of standard page sizes as defined in the Adobe Postscript PPD Standard v4.3. It defines the standard set of diff --git a/src/gui/painting/qplatformbackingstore.cpp b/src/gui/painting/qplatformbackingstore.cpp index 09c23fdfa1..cc8d850689 100644 --- a/src/gui/painting/qplatformbackingstore.cpp +++ b/src/gui/painting/qplatformbackingstore.cpp @@ -344,7 +344,7 @@ void QPlatformBackingStore::composeAndFlush(QWindow *window, const QRegion ®i QWindowPrivate::get(window)->lastComposeTime.start(); QOpenGLFunctions *funcs = d_ptr->context->functions(); - funcs->glViewport(0, 0, window->width() * window->devicePixelRatio(), window->height() * window->devicePixelRatio()); + funcs->glViewport(0, 0, qRound(window->width() * window->devicePixelRatio()), qRound(window->height() * window->devicePixelRatio())); funcs->glClearColor(0, 0, 0, translucentBackground ? 0 : 1); funcs->glClear(GL_COLOR_BUFFER_BIT); diff --git a/src/gui/painting/qtransform.cpp b/src/gui/painting/qtransform.cpp index c5e296b293..040d33fc2a 100644 --- a/src/gui/painting/qtransform.cpp +++ b/src/gui/painting/qtransform.cpp @@ -798,15 +798,15 @@ bool QTransform::operator==(const QTransform &o) const uint qHash(const QTransform &key, uint seed) Q_DECL_NOTHROW { QtPrivate::QHashCombine hash; - seed = hash(key.m11(), seed); - seed = hash(key.m12(), seed); - seed = hash(key.m21(), seed); - seed = hash(key.m22(), seed); - seed = hash(key.dx(), seed); - seed = hash(key.dy(), seed); - seed = hash(key.m13(), seed); - seed = hash(key.m23(), seed); - seed = hash(key.m33(), seed); + seed = hash(seed, key.m11()); + seed = hash(seed, key.m12()); + seed = hash(seed, key.m21()); + seed = hash(seed, key.m22()); + seed = hash(seed, key.dx()); + seed = hash(seed, key.dy()); + seed = hash(seed, key.m13()); + seed = hash(seed, key.m23()); + seed = hash(seed, key.m33()); return seed; } diff --git a/src/gui/text/qplatformfontdatabase.cpp b/src/gui/text/qplatformfontdatabase.cpp index d89805d18e..a911014a19 100644 --- a/src/gui/text/qplatformfontdatabase.cpp +++ b/src/gui/text/qplatformfontdatabase.cpp @@ -264,7 +264,7 @@ bool QSupportedWritingSystems::supported(QFontDatabase::WritingSystem writingSys /*! \class QSupportedWritingSystems \brief The QSupportedWritingSystems class is used when registering fonts with the internal Qt - fontdatabase + fontdatabase. \ingroup painting \inmodule QtGui diff --git a/src/network/access/access.pri b/src/network/access/access.pri index 1d6a04a424..a129beda15 100644 --- a/src/network/access/access.pri +++ b/src/network/access/access.pri @@ -84,8 +84,7 @@ qtConfig(http) { access/qhttpnetworkrequest.cpp \ access/qhttpprotocolhandler.cpp \ access/qhttpthreaddelegate.cpp \ - access/qnetworkreplyhttpimpl.cpp \ - access/qspdyprotocolhandler.cpp + access/qnetworkreplyhttpimpl.cpp HEADERS += \ access/qabstractprotocolhandler_p.h \ @@ -99,6 +98,12 @@ qtConfig(http) { access/qhttpnetworkrequest_p.h \ access/qhttpprotocolhandler_p.h \ access/qhttpthreaddelegate_p.h \ - access/qnetworkreplyhttpimpl_p.h \ - access/qspdyprotocolhandler_p.h + access/qnetworkreplyhttpimpl_p.h + + qtConfig(ssl) { + SOURCES += \ + access/qspdyprotocolhandler.cpp + HEADERS += \ + access/qspdyprotocolhandler_p.h + } } diff --git a/src/network/access/qnetworkaccessmanager.cpp b/src/network/access/qnetworkaccessmanager.cpp index 35e79a69f2..76850837d0 100644 --- a/src/network/access/qnetworkaccessmanager.cpp +++ b/src/network/access/qnetworkaccessmanager.cpp @@ -166,7 +166,7 @@ static void ensureInitialized() /*! \class QNetworkAccessManager \brief The QNetworkAccessManager class allows the application to - send network requests and receive replies + send network requests and receive replies. \since 4.4 \ingroup network diff --git a/src/network/access/qnetworkcookiejar.cpp b/src/network/access/qnetworkcookiejar.cpp index 2ec4acf26c..072a7f249d 100644 --- a/src/network/access/qnetworkcookiejar.cpp +++ b/src/network/access/qnetworkcookiejar.cpp @@ -54,7 +54,7 @@ QT_BEGIN_NAMESPACE \since 4.4 \inmodule QtNetwork - \brief The QNetworkCookieJar class implements a simple jar of QNetworkCookie objects + \brief The QNetworkCookieJar class implements a simple jar of QNetworkCookie objects. Cookies are small bits of information that stateless protocols like HTTP use to maintain some persistent information across diff --git a/src/network/access/qnetworkreply.cpp b/src/network/access/qnetworkreply.cpp index 11d8f0e3f7..aca9cb1c08 100644 --- a/src/network/access/qnetworkreply.cpp +++ b/src/network/access/qnetworkreply.cpp @@ -61,7 +61,7 @@ QNetworkReplyPrivate::QNetworkReplyPrivate() \class QNetworkReply \since 4.4 \brief The QNetworkReply class contains the data and headers for a request - sent with QNetworkAccessManager + sent with QNetworkAccessManager. \reentrant \ingroup network diff --git a/src/network/doc/src/qtnetwork.qdoc b/src/network/doc/src/qtnetwork.qdoc index 7a95195da2..517e0a72cb 100644 --- a/src/network/doc/src/qtnetwork.qdoc +++ b/src/network/doc/src/qtnetwork.qdoc @@ -96,7 +96,7 @@ \title Qt Network C++ Classes \ingroup modules \qtvariable network - \brief Provides classes to make network programming easier and portable + \brief Provides classes to make network programming easier and portable. To include the definitions of the module's classes, use the following directive: diff --git a/src/network/kernel/qauthenticator.cpp b/src/network/kernel/qauthenticator.cpp index 11ea40dbce..34db5b4b31 100644 --- a/src/network/kernel/qauthenticator.cpp +++ b/src/network/kernel/qauthenticator.cpp @@ -1454,8 +1454,8 @@ static bool q_NTLM_SSPI_library_load() securityDLLHandle = LoadLibrary(L"secur32.dll"); if (securityDLLHandle != NULL) { INIT_SECURITY_INTERFACE pInitSecurityInterface = - (INIT_SECURITY_INTERFACE)GetProcAddress(securityDLLHandle, - "InitSecurityInterfaceW"); + reinterpret_cast( + reinterpret_cast(GetProcAddress(securityDLLHandle, "InitSecurityInterfaceW"))); if (pInitSecurityInterface != NULL) pSecurityFunctionTable = pInitSecurityInterface(); } diff --git a/src/network/socket/qnativesocketengine_win.cpp b/src/network/socket/qnativesocketengine_win.cpp index c303f01648..1b84b26d83 100644 --- a/src/network/socket/qnativesocketengine_win.cpp +++ b/src/network/socket/qnativesocketengine_win.cpp @@ -1232,6 +1232,8 @@ qint64 QNativeSocketEnginePrivate::nativeReceiveDatagram(char *data, qint64 maxL // it is ok the buffer was to small if bytesRead is larger than // maxLength then assume bytes read is really maxLenth ret = qint64(bytesRead) > maxLength ? maxLength : qint64(bytesRead); + if (options & QNativeSocketEngine::WantDatagramSender) + qt_socket_getPortAndAddress(socketDescriptor, &aa, &header->senderPort, &header->senderAddress); } else { WS_ERROR_DEBUG(err); switch (err) { diff --git a/src/network/ssl/qsslconfiguration.cpp b/src/network/ssl/qsslconfiguration.cpp index e03b89f58e..71c4f7090c 100644 --- a/src/network/ssl/qsslconfiguration.cpp +++ b/src/network/ssl/qsslconfiguration.cpp @@ -59,7 +59,7 @@ const char QSslConfiguration::NextProtocolHttp1_1[] = "http/1.1"; /*! \class QSslConfiguration - \brief The QSslConfiguration class holds the configuration and state of an SSL connection + \brief The QSslConfiguration class holds the configuration and state of an SSL connection. \since 4.4 \reentrant diff --git a/src/network/ssl/qsslsocket_openssl11.cpp b/src/network/ssl/qsslsocket_openssl11.cpp index 96626b6a0f..d028f5fc00 100644 --- a/src/network/ssl/qsslsocket_openssl11.cpp +++ b/src/network/ssl/qsslsocket_openssl11.cpp @@ -125,9 +125,12 @@ void QSslSocketPrivate::ensureCiphersAndCertsLoaded() #if defined(Q_OS_WIN) HINSTANCE hLib = LoadLibraryW(L"Crypt32"); if (hLib) { - ptrCertOpenSystemStoreW = (PtrCertOpenSystemStoreW)GetProcAddress(hLib, "CertOpenSystemStoreW"); - ptrCertFindCertificateInStore = (PtrCertFindCertificateInStore)GetProcAddress(hLib, "CertFindCertificateInStore"); - ptrCertCloseStore = (PtrCertCloseStore)GetProcAddress(hLib, "CertCloseStore"); + ptrCertOpenSystemStoreW = reinterpret_cast( + reinterpret_cast(GetProcAddress(hLib, "CertOpenSystemStoreW"))); + ptrCertFindCertificateInStore = reinterpret_cast( + reinterpret_cast(GetProcAddress(hLib, "CertFindCertificateInStore"))); + ptrCertCloseStore = reinterpret_cast( + reinterpret_cast(GetProcAddress(hLib, "CertCloseStore"))); if (!ptrCertOpenSystemStoreW || !ptrCertFindCertificateInStore || !ptrCertCloseStore) qCWarning(lcSsl, "could not resolve symbols in crypt32 library"); // should never happen } else { diff --git a/src/network/ssl/qsslsocket_opensslpre11.cpp b/src/network/ssl/qsslsocket_opensslpre11.cpp index 5782df65cc..062e03f4e6 100644 --- a/src/network/ssl/qsslsocket_opensslpre11.cpp +++ b/src/network/ssl/qsslsocket_opensslpre11.cpp @@ -254,9 +254,12 @@ void QSslSocketPrivate::ensureCiphersAndCertsLoaded() #if defined(Q_OS_WIN) HINSTANCE hLib = LoadLibraryW(L"Crypt32"); if (hLib) { - ptrCertOpenSystemStoreW = (PtrCertOpenSystemStoreW)GetProcAddress(hLib, "CertOpenSystemStoreW"); - ptrCertFindCertificateInStore = (PtrCertFindCertificateInStore)GetProcAddress(hLib, "CertFindCertificateInStore"); - ptrCertCloseStore = (PtrCertCloseStore)GetProcAddress(hLib, "CertCloseStore"); + ptrCertOpenSystemStoreW = reinterpret_cast( + reinterpret_cast(GetProcAddress(hLib, "CertOpenSystemStoreW"))); + ptrCertFindCertificateInStore = reinterpret_cast( + reinterpret_cast(GetProcAddress(hLib, "CertFindCertificateInStore"))); + ptrCertCloseStore = reinterpret_cast( + reinterpret_cast(GetProcAddress(hLib, "CertCloseStore"))); if (!ptrCertOpenSystemStoreW || !ptrCertFindCertificateInStore || !ptrCertCloseStore) qCWarning(lcSsl, "could not resolve symbols in crypt32 library"); // should never happen } else { diff --git a/src/platformheaders/nativecontexts/qeglnativecontext.qdoc b/src/platformheaders/nativecontexts/qeglnativecontext.qdoc index 22e763ec24..3779ea10c8 100644 --- a/src/platformheaders/nativecontexts/qeglnativecontext.qdoc +++ b/src/platformheaders/nativecontexts/qeglnativecontext.qdoc @@ -30,7 +30,7 @@ \inmodule QtPlatformHeaders \since 5.4 - \brief A class encapsulating an EGL context and display handle + \brief A class encapsulating an EGL context and display handle. \note There is no binary compatibility guarantee for this class, meaning that an application using it is only guaranteed to work with the Qt version it was diff --git a/src/platformheaders/nativecontexts/qwglnativecontext.qdoc b/src/platformheaders/nativecontexts/qwglnativecontext.qdoc index ccc5e2b1d0..20563c3906 100644 --- a/src/platformheaders/nativecontexts/qwglnativecontext.qdoc +++ b/src/platformheaders/nativecontexts/qwglnativecontext.qdoc @@ -30,7 +30,7 @@ \inmodule QtPlatformHeaders \since 5.4 - \brief A class encapsulating a WGL context on Windows with desktop OpenGL (opengl32.dll) + \brief A class encapsulating a WGL context on Windows with desktop OpenGL (opengl32.dll). \note There is no binary compatibility guarantee for this class, meaning that an application using it is only guaranteed to work with the Qt diff --git a/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase.cpp b/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase.cpp index aab1ab9889..8df8da1a38 100644 --- a/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase.cpp +++ b/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase.cpp @@ -1000,7 +1000,7 @@ static QChar *createFontFile(const QString &faceName) if (!faceName.isEmpty()) { const int nameLength = qMin(faceName.length(), LF_FACESIZE - 1); faceNamePtr = new QChar[nameLength + 1]; - memcpy(faceNamePtr, faceName.utf16(), sizeof(wchar_t) * nameLength); + memcpy(static_cast(faceNamePtr), faceName.utf16(), sizeof(wchar_t) * nameLength); faceNamePtr[nameLength] = 0; } return faceNamePtr; diff --git a/src/platformsupport/input/evdevmouse/qevdevmousehandler.cpp b/src/platformsupport/input/evdevmouse/qevdevmousehandler.cpp index 04372ae4d9..86a4cd0076 100644 --- a/src/platformsupport/input/evdevmouse/qevdevmousehandler.cpp +++ b/src/platformsupport/input/evdevmouse/qevdevmousehandler.cpp @@ -245,18 +245,12 @@ void QEvdevMouseHandler::readMouseData() m_y += data->value; posChanged = true; } else if (data->code == ABS_WHEEL) { // vertical scroll - // data->value: 1 == up, -1 == down - if (data->value == 1) - delta.setY(120); - else - delta.setY(-120); + // data->value: positive == up, negative == down + delta.setY(120 * data->value); emit handleWheelEvent(delta); } else if (data->code == ABS_THROTTLE) { // horizontal scroll - // data->value: 1 == right, -1 == left - if (data->value == 1) - delta.setX(-120); - else - delta.setX(120); + // data->value: positive == right, negative == left + delta.setX(-120 * data->value); emit handleWheelEvent(delta); } } else if (data->type == EV_KEY && data->code == BTN_TOUCH) { diff --git a/src/platformsupport/input/evdevtouch/qevdevtouchhandler.cpp b/src/platformsupport/input/evdevtouch/qevdevtouchhandler.cpp index 7b7649bc5c..f3cc160b3e 100644 --- a/src/platformsupport/input/evdevtouch/qevdevtouchhandler.cpp +++ b/src/platformsupport/input/evdevtouch/qevdevtouchhandler.cpp @@ -368,7 +368,7 @@ QEvdevTouchScreenHandler::~QEvdevTouchScreenHandler() bool QEvdevTouchScreenHandler::isFiltered() const { - return d->m_filtered; + return d && d->m_filtered; } QTouchDevice *QEvdevTouchScreenHandler::touchDevice() const diff --git a/src/platformsupport/platformsupport.pro b/src/platformsupport/platformsupport.pro index 7dbb6f6cae..6d4f1b93bd 100644 --- a/src/platformsupport/platformsupport.pro +++ b/src/platformsupport/platformsupport.pro @@ -16,7 +16,7 @@ qtConfig(evdev)|qtConfig(tslib)|qtConfig(libinput)|qtConfig(integrityhid) { input.depends += devicediscovery } -if(unix:!darwin)|qtConfig(xcb): \ +if(unix:!uikit)|qtConfig(xcb): \ SUBDIRS += services qtConfig(opengl): \ diff --git a/src/platformsupport/themes/genericunix/dbustray/qdbustrayicon.cpp b/src/platformsupport/themes/genericunix/dbustray/qdbustrayicon.cpp index 2153924ec8..e81d272d4f 100644 --- a/src/platformsupport/themes/genericunix/dbustray/qdbustrayicon.cpp +++ b/src/platformsupport/themes/genericunix/dbustray/qdbustrayicon.cpp @@ -90,12 +90,17 @@ static QString iconTempPath() static const QString KDEItemFormat = QStringLiteral("org.kde.StatusNotifierItem-%1-%2"); static const QString KDEWatcherService = QStringLiteral("org.kde.StatusNotifierWatcher"); -static const QString TempFileTemplate = iconTempPath() + QLatin1String("/qt-trayicon-XXXXXX.png"); static const QString XdgNotificationService = QStringLiteral("org.freedesktop.Notifications"); static const QString XdgNotificationPath = QStringLiteral("/org/freedesktop/Notifications"); static const QString DefaultAction = QStringLiteral("default"); static int instanceCount = 0; +static inline QString tempFileTemplate() +{ + static const QString TempFileTemplate = iconTempPath() + QLatin1String("/qt-trayicon-XXXXXX.png"); + return TempFileTemplate; +} + /*! \class QDBusTrayIcon \internal @@ -206,7 +211,7 @@ QTemporaryFile *QDBusTrayIcon::tempIcon(const QIcon &icon) if (!necessary) return nullptr; qreal dpr = qGuiApp->devicePixelRatio(); - QTemporaryFile *ret = new QTemporaryFile(TempFileTemplate, this); + QTemporaryFile *ret = new QTemporaryFile(tempFileTemplate(), this); ret->open(); icon.pixmap(QSize(22 * dpr, 22 * dpr)).save(ret); ret->close(); diff --git a/src/platformsupport/themes/themes.pro b/src/platformsupport/themes/themes.pro index 44f94fafc8..668a843473 100644 --- a/src/platformsupport/themes/themes.pro +++ b/src/platformsupport/themes/themes.pro @@ -6,7 +6,7 @@ CONFIG += static internal_module DEFINES += QT_NO_CAST_FROM_ASCII -if(unix:!darwin)|qtConfig(xcb): \ +if(unix:!uikit)|qtConfig(xcb): \ include($$PWD/genericunix/genericunix.pri) HEADERS += \ diff --git a/src/plugins/imageformats/ico/ico.json b/src/plugins/imageformats/ico/ico.json index 14093ee471..304e2f1c02 100644 --- a/src/plugins/imageformats/ico/ico.json +++ b/src/plugins/imageformats/ico/ico.json @@ -1,4 +1,4 @@ { "Keys": [ "ico", "cur" ], - "MimeTypes": [ "image/vnd.microsoft.icon" ] + "MimeTypes": [ "image/vnd.microsoft.icon", "image/vnd.microsoft.icon" ] } diff --git a/src/plugins/platforms/cocoa/qcocoaglcontext.mm b/src/plugins/platforms/cocoa/qcocoaglcontext.mm index 2493181bc5..348a9b0c24 100644 --- a/src/plugins/platforms/cocoa/qcocoaglcontext.mm +++ b/src/plugins/platforms/cocoa/qcocoaglcontext.mm @@ -117,6 +117,9 @@ static void updateFormatFromContext(QSurfaceFormat *format) format->setProfile(QSurfaceFormat::CompatibilityProfile); } + // NSOpenGLContext is not re-entrant (https://openradar.appspot.com/37064579) +static QMutex s_contextMutex; + QCocoaGLContext::QCocoaGLContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share, const QVariant &nativeHandle) : m_context(nil), @@ -248,6 +251,7 @@ void QCocoaGLContext::swapBuffers(QPlatformSurface *surface) QWindow *window = static_cast(surface)->window(); setActiveWindow(window); + QMutexLocker locker(&s_contextMutex); [m_context flushBuffer]; } @@ -400,6 +404,7 @@ QFunctionPointer QCocoaGLContext::getProcAddress(const char *procName) void QCocoaGLContext::update() { + QMutexLocker locker(&s_contextMutex); [m_context update]; } diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index 022242130b..9e168835f1 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -503,7 +503,10 @@ NSUInteger QCocoaWindow::windowStyleMask(Qt::WindowFlags flags) { const Qt::WindowType type = static_cast(int(flags & Qt::WindowType_Mask)); const bool frameless = (flags & Qt::FramelessWindowHint) || windowIsPopupType(type); - const bool resizeable = !(flags & Qt::CustomizeWindowHint); // Remove zoom button by disabling resize + + // Remove zoom button by disabling resize for CustomizeWindowHint windows, except for + // Qt::Tool windows (e.g. dock windows) which should always be resizeable. + const bool resizeable = !(flags & Qt::CustomizeWindowHint) || (type == Qt::Tool); // Select base window type. Note that the value of NSBorderlessWindowMask is 0. NSUInteger styleMask = (frameless || !resizeable) ? NSBorderlessWindowMask : NSResizableWindowMask; @@ -517,6 +520,8 @@ NSUInteger QCocoaWindow::windowStyleMask(Qt::WindowFlags flags) styleMask |= NSClosableWindowMask; if (flags & Qt::WindowMinimizeButtonHint) styleMask |= NSMiniaturizableWindowMask; + if (flags & Qt::WindowMaximizeButtonHint) + styleMask |= NSResizableWindowMask; } else { styleMask |= NSClosableWindowMask | NSTitledWindowMask; diff --git a/src/plugins/platforms/cocoa/qnsview_dragging.mm b/src/plugins/platforms/cocoa/qnsview_dragging.mm index 01df0e9337..e61329f169 100644 --- a/src/plugins/platforms/cocoa/qnsview_dragging.mm +++ b/src/plugins/platforms/cocoa/qnsview_dragging.mm @@ -165,7 +165,11 @@ static QPoint mapWindowCoordinates(QWindow *source, QWindow *target, QPoint poin [nativeCursor set]; // Make sure the cursor is updated correctly if the mouse does not move and window is under cursor - // by creating a fake move event + // by creating a fake move event, unless on 10.14 and later where doing so will trigger a security + // warning dialog. FIXME: Find a way to update the cursor without fake mouse events. + if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::MacOSMojave) + return; + if (m_updatingDrag) return; diff --git a/src/plugins/platforms/cocoa/qnswindowdelegate.mm b/src/plugins/platforms/cocoa/qnswindowdelegate.mm index 6079a35d05..1c21879a89 100644 --- a/src/plugins/platforms/cocoa/qnswindowdelegate.mm +++ b/src/plugins/platforms/cocoa/qnswindowdelegate.mm @@ -72,25 +72,38 @@ static QRegExp whitespaceRegex = QRegExp(QStringLiteral("\\s*")); /*! Overridden to ensure that the zoomed state always results in a maximized window, which would otherwise not be the case for borderless windows. + + We also keep the window on the same screen as before; something AppKit + sometimes fails to do using its built in logic. */ - (NSRect)windowWillUseStandardFrame:(NSWindow *)window defaultFrame:(NSRect)proposedFrame { Q_UNUSED(proposedFrame); Q_ASSERT(window == m_cocoaWindow->nativeWindow()); - - // We compute the maximized state based on the maximum size, and - // the current position of the window. This may result in the window - // geometry falling outside of the current screen's available geometry, - // e.g. when there is not maximize size set, but this is okey, AppKit - // will then shift and possibly clip the geometry for us. const QWindow *w = m_cocoaWindow->window(); - QRect maximizedRect = QRect(w->framePosition(), w->maximumSize()); - // QWindow::maximumSize() refers to the client size, - // but AppKit expects the full frame size. - maximizedRect.adjust(0, 0, 0, w->frameMargins().top()); + // maximumSize() refers to the client size, but AppKit expects the full frame size + QSizeF maximumSize = w->maximumSize() + QSize(0, w->frameMargins().top()); - return QCocoaScreen::mapToNative(maximizedRect); + // The window should never be larger than the current screen geometry + const QRectF screenGeometry = m_cocoaWindow->screen()->geometry(); + maximumSize = maximumSize.boundedTo(screenGeometry.size()); + + // Use the current frame position for the initial maximized frame, + // so that the window stays put and just expand, in case its maximum + // size is within the screen bounds. + QRectF maximizedFrame = QRectF(w->framePosition(), maximumSize); + + // But constrain the frame to the screen bounds in case the frame + // extends beyond the screen bounds as a result of starting out + // with the current frame position. + maximizedFrame.translate(QPoint( + qMax(screenGeometry.left() - maximizedFrame.left(), 0.0) + + qMin(screenGeometry.right() - maximizedFrame.right(), 0.0), + qMax(screenGeometry.top() - maximizedFrame.top(), 0.0) + + qMin(screenGeometry.bottom() - maximizedFrame.bottom(), 0.0))); + + return QCocoaScreen::mapToNative(maximizedFrame); } - (BOOL)window:(NSWindow *)window shouldPopUpDocumentPathMenu:(NSMenu *)menu diff --git a/src/plugins/platforms/ios/kernel.pro b/src/plugins/platforms/ios/kernel.pro index 6eb9f2c534..71257d09f7 100644 --- a/src/plugins/platforms/ios/kernel.pro +++ b/src/plugins/platforms/ios/kernel.pro @@ -5,8 +5,6 @@ TARGET = qios # application's main() when the plugin is a shared library. qtConfig(shared): CONFIG += static -CONFIG += no_app_extension_api_only - QT += \ core-private gui-private \ clipboard_support-private fontdatabase_support-private graphics_support-private diff --git a/src/plugins/platforms/ios/qiosapplicationstate.mm b/src/plugins/platforms/ios/qiosapplicationstate.mm index cc76d198f5..bf4e9cc900 100644 --- a/src/plugins/platforms/ios/qiosapplicationstate.mm +++ b/src/plugins/platforms/ios/qiosapplicationstate.mm @@ -86,7 +86,7 @@ static void qRegisterApplicationStateNotifications() QLatin1String("Extension loaded, assuming state is active")); } else { // Initialize correct startup state, which may not be the Qt default (inactive) - UIApplicationState startupState = [UIApplication sharedApplication].applicationState; + UIApplicationState startupState = qt_apple_sharedApplication().applicationState; QIOSApplicationState::handleApplicationStateChanged(startupState, QLatin1String("Application loaded")); } } @@ -95,7 +95,7 @@ Q_CONSTRUCTOR_FUNCTION(qRegisterApplicationStateNotifications) QIOSApplicationState::QIOSApplicationState() { if (!qt_apple_isApplicationExtension()) { - UIApplicationState startupState = [UIApplication sharedApplication].applicationState; + UIApplicationState startupState = qt_apple_sharedApplication().applicationState; QIOSApplicationState::handleApplicationStateChanged(startupState, QLatin1String("Application launched")); } } diff --git a/src/plugins/platforms/ios/qiosfiledialog.mm b/src/plugins/platforms/ios/qiosfiledialog.mm index 5987bc1540..e8a3f5b30e 100644 --- a/src/plugins/platforms/ios/qiosfiledialog.mm +++ b/src/plugins/platforms/ios/qiosfiledialog.mm @@ -43,6 +43,8 @@ #include #include +#include + #include "qiosfiledialog.h" #include "qiosintegration.h" #include "qiosoptionalplugininterface.h" @@ -94,7 +96,7 @@ bool QIOSFileDialog::showImagePickerDialog(QWindow *parent) } UIWindow *window = parent ? reinterpret_cast(parent->winId()).window - : [UIApplication sharedApplication].keyWindow; + : qt_apple_sharedApplication().keyWindow; [window.rootViewController presentViewController:m_viewController animated:YES completion:nil]; return true; diff --git a/src/plugins/platforms/ios/qiosglobal.mm b/src/plugins/platforms/ios/qiosglobal.mm index f27b2242df..a523d1be45 100644 --- a/src/plugins/platforms/ios/qiosglobal.mm +++ b/src/plugins/platforms/ios/qiosglobal.mm @@ -42,6 +42,8 @@ #include "qiosviewcontroller.h" #include "qiosscreen.h" +#include + QT_BEGIN_NAMESPACE Q_LOGGING_CATEGORY(lcQpaApplication, "qt.qpa.application"); @@ -50,13 +52,16 @@ Q_LOGGING_CATEGORY(lcQpaWindow, "qt.qpa.window"); bool isQtApplication() { + if (qt_apple_isApplicationExtension()) + return false; + // Returns \c true if the plugin is in full control of the whole application. This means // that we control the application delegate and the top view controller, and can take // actions that impacts all parts of the application. The opposite means that we are // embedded inside a native iOS application, and should be more focused on playing along // with native UIControls, and less inclined to change structures that lies outside the // scope of our QWindows/UIViews. - static bool isQt = ([[UIApplication sharedApplication].delegate isKindOfClass:[QIOSApplicationDelegate class]]); + static bool isQt = ([qt_apple_sharedApplication().delegate isKindOfClass:[QIOSApplicationDelegate class]]); return isQt; } @@ -152,8 +157,13 @@ QT_END_NAMESPACE + (id)currentFirstResponder { + if (qt_apple_isApplicationExtension()) { + qWarning() << "can't get first responder in application extensions!"; + return nil; + } + QtFirstResponderEvent *event = [[[QtFirstResponderEvent alloc] init] autorelease]; - [[UIApplication sharedApplication] sendAction:@selector(qt_findFirstResponder:event:) to:nil from:nil forEvent:event]; + [qt_apple_sharedApplication() sendAction:@selector(qt_findFirstResponder:event:) to:nil from:nil forEvent:event]; return event.firstResponder; } diff --git a/src/plugins/platforms/ios/qiosinputcontext.mm b/src/plugins/platforms/ios/qiosinputcontext.mm index 3e22634071..d2229df133 100644 --- a/src/plugins/platforms/ios/qiosinputcontext.mm +++ b/src/plugins/platforms/ios/qiosinputcontext.mm @@ -49,6 +49,8 @@ #include "qioswindow.h" #include "quiview.h" +#include + #include #include @@ -535,6 +537,11 @@ void QIOSInputContext::scroll(int y) if (!rootView) return; + if (qt_apple_isApplicationExtension()) { + qWarning() << "can't scroll root view in application extension"; + return; + } + CATransform3D translationTransform = CATransform3DMakeTranslation(0.0, -y, 0.0); if (CATransform3DEqualToTransform(translationTransform, rootView.layer.sublayerTransform)) return; @@ -573,7 +580,7 @@ void QIOSInputContext::scroll(int y) // Raise all known windows to above the status-bar if we're scrolling the screen, // while keeping the relative window level between the windows the same. - NSArray *applicationWindows = [[UIApplication sharedApplication] windows]; + NSArray *applicationWindows = [qt_apple_sharedApplication() windows]; static QHash originalWindowLevels; for (UIWindow *window in applicationWindows) { if (keyboardScrollIsActive && !originalWindowLevels.contains(window)) diff --git a/src/plugins/platforms/ios/qiosintegration.mm b/src/plugins/platforms/ios/qiosintegration.mm index eae0530fbe..9a5a0ab499 100644 --- a/src/plugins/platforms/ios/qiosintegration.mm +++ b/src/plugins/platforms/ios/qiosintegration.mm @@ -86,7 +86,7 @@ QIOSIntegration::QIOSIntegration() , m_accessibility(0) , m_optionalPlugins(new QFactoryLoader(QIosOptionalPluginInterface_iid, QLatin1String("/platforms/darwin"))) { - if (Q_UNLIKELY(![UIApplication sharedApplication])) { + if (Q_UNLIKELY(!qt_apple_isApplicationExtension() && !qt_apple_sharedApplication())) { qFatal("Error: You are creating QApplication before calling UIApplicationMain.\n" \ "If you are writing a native iOS application, and only want to use Qt for\n" \ "parts of the application, a good place to create QApplication is from within\n" \ diff --git a/src/plugins/platforms/ios/qiosmessagedialog.mm b/src/plugins/platforms/ios/qiosmessagedialog.mm index 9d05b792c2..a7de9b473a 100644 --- a/src/plugins/platforms/ios/qiosmessagedialog.mm +++ b/src/plugins/platforms/ios/qiosmessagedialog.mm @@ -43,6 +43,8 @@ #include #include +#include + #include "qiosglobal.h" #include "quiview.h" #include "qiosmessagedialog.h" @@ -126,7 +128,7 @@ bool QIOSMessageDialog::show(Qt::WindowFlags windowFlags, Qt::WindowModality win [m_alertController addAction:createAction(NoButton)]; } - UIWindow *window = parent ? reinterpret_cast(parent->winId()).window : [UIApplication sharedApplication].keyWindow; + UIWindow *window = parent ? reinterpret_cast(parent->winId()).window : qt_apple_sharedApplication().keyWindow; [window.rootViewController presentViewController:m_alertController animated:YES completion:nil]; return true; } diff --git a/src/plugins/platforms/ios/qiosscreen.mm b/src/plugins/platforms/ios/qiosscreen.mm index 96679eaccd..f1121a102b 100644 --- a/src/plugins/platforms/ios/qiosscreen.mm +++ b/src/plugins/platforms/ios/qiosscreen.mm @@ -46,6 +46,8 @@ #include "qiosviewcontroller.h" #include "quiview.h" +#include + #include #include @@ -269,17 +271,19 @@ QIOSScreen::QIOSScreen(UIScreen *screen) m_physicalDpi = 96; } - for (UIWindow *existingWindow in [[UIApplication sharedApplication] windows]) { - if (existingWindow.screen == m_uiScreen) { - m_uiWindow = [m_uiWindow retain]; - break; + if (!qt_apple_isApplicationExtension()) { + for (UIWindow *existingWindow in qt_apple_sharedApplication().windows) { + if (existingWindow.screen == m_uiScreen) { + m_uiWindow = [m_uiWindow retain]; + break; + } } - } - if (!m_uiWindow) { - // Create a window and associated view-controller that we can use - m_uiWindow = [[QUIWindow alloc] initWithFrame:[m_uiScreen bounds]]; - m_uiWindow.rootViewController = [[[QIOSViewController alloc] initWithQIOSScreen:this] autorelease]; + if (!m_uiWindow) { + // Create a window and associated view-controller that we can use + m_uiWindow = [[QUIWindow alloc] initWithFrame:[m_uiScreen bounds]]; + m_uiWindow.rootViewController = [[[QIOSViewController alloc] initWithQIOSScreen:this] autorelease]; + } } updateProperties(); @@ -325,17 +329,20 @@ void QIOSScreen::updateProperties() #ifndef Q_OS_TVOS if (m_uiScreen == [UIScreen mainScreen]) { - Qt::ScreenOrientation statusBarOrientation = toQtScreenOrientation(UIDeviceOrientation([UIApplication sharedApplication].statusBarOrientation)); - QIOSViewController *qtViewController = [m_uiWindow.rootViewController isKindOfClass:[QIOSViewController class]] ? static_cast(m_uiWindow.rootViewController) : nil; if (qtViewController.lockedOrientation) { + Q_ASSERT(!qt_apple_isApplicationExtension()); + // Setting the statusbar orientation (content orientation) on will affect the screen geometry, // which is not what we want. We want to reflect the screen geometry based on the locked orientation, // and adjust the available geometry based on the repositioned status bar for the current status // bar orientation. + Qt::ScreenOrientation statusBarOrientation = toQtScreenOrientation( + UIDeviceOrientation(qt_apple_sharedApplication().statusBarOrientation)); + Qt::ScreenOrientation lockedOrientation = toQtScreenOrientation(UIDeviceOrientation(qtViewController.lockedOrientation)); QTransform transform = transformBetween(lockedOrientation, statusBarOrientation, m_geometry).inverted(); @@ -489,8 +496,8 @@ Qt::ScreenOrientation QIOSScreen::orientation() const // the orientation the application was started up in (which may not match // the physical orientation of the device, but typically does unless the // application has been locked to a subset of the available orientations). - if (deviceOrientation == UIDeviceOrientationUnknown) - deviceOrientation = UIDeviceOrientation([UIApplication sharedApplication].statusBarOrientation); + if (deviceOrientation == UIDeviceOrientationUnknown && !qt_apple_isApplicationExtension()) + deviceOrientation = UIDeviceOrientation(qt_apple_sharedApplication().statusBarOrientation); // If the device reports face up or face down orientations, we can't map // them to Qt orientations, so we pretend we're in the same orientation diff --git a/src/plugins/platforms/ios/qiosservices.mm b/src/plugins/platforms/ios/qiosservices.mm index 3c44e1d7d6..7222bf6793 100644 --- a/src/plugins/platforms/ios/qiosservices.mm +++ b/src/plugins/platforms/ios/qiosservices.mm @@ -40,6 +40,9 @@ #include "qiosservices.h" #include +#include +#include + #include #import @@ -48,6 +51,11 @@ QT_BEGIN_NAMESPACE bool QIOSServices::openUrl(const QUrl &url) { + if (qt_apple_isApplicationExtension()) { + qWarning() << "openUrl not implement for application extensions yet"; + return false; + } + if (url == m_handlingUrl) return false; @@ -55,12 +63,25 @@ bool QIOSServices::openUrl(const QUrl &url) return openDocument(url); NSURL *nsUrl = url.toNSURL(); - UIApplication *application = [UIApplication sharedApplication]; + UIApplication *application = qt_apple_sharedApplication(); if (![application canOpenURL:nsUrl]) return false; - [application openURL:nsUrl options:@{} completionHandler:nil]; + static SEL openUrlSelector = @selector(openURL:options:completionHandler:); + NSInvocation *invocation = [NSInvocation invocationWithMethodSignature: + [UIApplication instanceMethodSignatureForSelector:openUrlSelector]]; + invocation.target = application; + invocation.selector = openUrlSelector; + + static auto kEmptyDictionary = @{}; + // Indices 0 and 1 are self and _cmd + [invocation setArgument:&nsUrl atIndex:2]; + [invocation setArgument:&kEmptyDictionary atIndex:3]; + // Fourth argument is nil, so left unset + + [invocation invoke]; + return true; } diff --git a/src/plugins/platforms/ios/qiostextinputoverlay.mm b/src/plugins/platforms/ios/qiostextinputoverlay.mm index ff696f5b7f..e5419b1766 100644 --- a/src/plugins/platforms/ios/qiostextinputoverlay.mm +++ b/src/plugins/platforms/ios/qiostextinputoverlay.mm @@ -46,6 +46,7 @@ #include #include +#include #include "qiosglobal.h" #include "qiostextinputoverlay.h" @@ -462,7 +463,7 @@ static void executeBlockWithoutAnimation(Block block) if (enabled) { _focusView = [reinterpret_cast(qApp->focusWindow()->winId()) retain]; - _desktopView = [[UIApplication sharedApplication].keyWindow.rootViewController.view retain]; + _desktopView = [qt_apple_sharedApplication().keyWindow.rootViewController.view retain]; Q_ASSERT(_focusView && _desktopView && _desktopView.superview); [_desktopView addGestureRecognizer:self]; } else { @@ -978,6 +979,11 @@ QIOSTextInputOverlay::QIOSTextInputOverlay() , m_selectionRecognizer(nullptr) , m_openMenuOnTapRecognizer(nullptr) { + if (qt_apple_isApplicationExtension()) { + qWarning() << "text input overlays disabled in application extensions"; + return; + } + connect(qApp, &QGuiApplication::focusObjectChanged, this, &QIOSTextInputOverlay::updateFocusObject); } diff --git a/src/plugins/platforms/ios/qiostheme.mm b/src/plugins/platforms/ios/qiostheme.mm index 91980d3f35..5534264a60 100644 --- a/src/plugins/platforms/ios/qiostheme.mm +++ b/src/plugins/platforms/ios/qiostheme.mm @@ -41,6 +41,7 @@ #include #include +#include #include @@ -103,7 +104,7 @@ bool QIOSTheme::usePlatformNativeDialog(QPlatformTheme::DialogType type) const switch (type) { case FileDialog: case MessageDialog: - return true; + return !qt_apple_isApplicationExtension(); default: return false; } diff --git a/src/plugins/platforms/ios/qiosviewcontroller.mm b/src/plugins/platforms/ios/qiosviewcontroller.mm index f254a8692d..ce2aa96ca5 100644 --- a/src/plugins/platforms/ios/qiosviewcontroller.mm +++ b/src/plugins/platforms/ios/qiosviewcontroller.mm @@ -41,6 +41,7 @@ #import "qiosviewcontroller.h" #include +#include #include #include @@ -305,15 +306,17 @@ { [super viewDidLoad]; + Q_ASSERT(!qt_apple_isApplicationExtension()); + #ifndef Q_OS_TVOS NSNotificationCenter *center = [NSNotificationCenter defaultCenter]; [center addObserver:self selector:@selector(willChangeStatusBarFrame:) name:UIApplicationWillChangeStatusBarFrameNotification - object:[UIApplication sharedApplication]]; + object:qt_apple_sharedApplication()]; [center addObserver:self selector:@selector(didChangeStatusBarOrientation:) name:UIApplicationDidChangeStatusBarOrientationNotification - object:[UIApplication sharedApplication]]; + object:qt_apple_sharedApplication()]; #endif } @@ -453,7 +456,6 @@ focusWindow = qt_window_private(focusWindow)->topLevelWindow(); #ifndef Q_OS_TVOS - UIApplication *uiApplication = [UIApplication sharedApplication]; // -------------- Status bar style and visbility --------------- @@ -477,6 +479,8 @@ // -------------- Content orientation --------------- + UIApplication *uiApplication = qt_apple_sharedApplication(); + static BOOL kAnimateContentOrientationChanges = YES; Qt::ScreenOrientation contentOrientation = focusWindow->contentOrientation(); diff --git a/src/plugins/platforms/qnx/qqnxeglwindow.h b/src/plugins/platforms/qnx/qqnxeglwindow.h index 3a3840f13c..d8cfd730ac 100644 --- a/src/plugins/platforms/qnx/qqnxeglwindow.h +++ b/src/plugins/platforms/qnx/qqnxeglwindow.h @@ -60,6 +60,8 @@ public: void setGeometry(const QRect &rect) override; + QSurfaceFormat format() const override { return m_format; } + protected: int pixelFormat() const override; void resetBuffers() override; diff --git a/src/plugins/platforms/windows/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp index 80f3203289..980a9fe9ab 100644 --- a/src/plugins/platforms/windows/qwindowscontext.cpp +++ b/src/plugins/platforms/windows/qwindowscontext.cpp @@ -1430,7 +1430,7 @@ bool QWindowsContext::filterNativeEvent(MSG *msg, LRESULT *result) bool QWindowsContext::filterNativeEvent(QWindow *window, MSG *msg, LRESULT *result) { long filterResult = 0; - if (QWindowSystemInterface::handleNativeEvent(window, nativeEventType(), &msg, &filterResult)) { + if (QWindowSystemInterface::handleNativeEvent(window, nativeEventType(), msg, &filterResult)) { *result = LRESULT(filterResult); return true; } diff --git a/src/plugins/platforms/windows/qwindowsglcontext.cpp b/src/plugins/platforms/windows/qwindowsglcontext.cpp index 6358778914..2409d70ec9 100644 --- a/src/plugins/platforms/windows/qwindowsglcontext.cpp +++ b/src/plugins/platforms/windows/qwindowsglcontext.cpp @@ -153,9 +153,11 @@ QT_BEGIN_NAMESPACE QWindowsOpengl32DLL QOpenGLStaticContext::opengl32; -FARPROC QWindowsOpengl32DLL::resolve(const char *name) +QFunctionPointer QWindowsOpengl32DLL::resolve(const char *name) { - return m_lib ? ::GetProcAddress(m_lib, name) : nullptr; + return m_lib + ? reinterpret_cast(::GetProcAddress(m_lib, name)) + : nullptr; } bool QWindowsOpengl32DLL::init(bool softwareRendering) @@ -977,12 +979,18 @@ QOpenGLStaticContext::QOpenGLStaticContext() : extensionNames(QOpenGLStaticContext::getGlString(GL_EXTENSIONS)), extensions(0), defaultFormat(QWindowsOpenGLContextFormat::current()), - wglGetPixelFormatAttribIVARB((WglGetPixelFormatAttribIVARB)QOpenGLStaticContext::opengl32.wglGetProcAddress("wglGetPixelFormatAttribivARB")), - wglChoosePixelFormatARB((WglChoosePixelFormatARB)QOpenGLStaticContext::opengl32.wglGetProcAddress("wglChoosePixelFormatARB")), - wglCreateContextAttribsARB((WglCreateContextAttribsARB)QOpenGLStaticContext::opengl32.wglGetProcAddress("wglCreateContextAttribsARB")), - wglSwapInternalExt((WglSwapInternalExt)QOpenGLStaticContext::opengl32.wglGetProcAddress("wglSwapIntervalEXT")), - wglGetSwapInternalExt((WglGetSwapInternalExt)QOpenGLStaticContext::opengl32.wglGetProcAddress("wglGetSwapIntervalEXT")), - wglGetExtensionsStringARB((WglGetExtensionsStringARB)QOpenGLStaticContext::opengl32.wglGetProcAddress("wglGetExtensionsStringARB")) + wglGetPixelFormatAttribIVARB(reinterpret_cast( + reinterpret_cast(QOpenGLStaticContext::opengl32.wglGetProcAddress("wglGetPixelFormatAttribivARB")))), + wglChoosePixelFormatARB(reinterpret_cast( + reinterpret_cast(QOpenGLStaticContext::opengl32.wglGetProcAddress("wglChoosePixelFormatARB")))), + wglCreateContextAttribsARB(reinterpret_cast( + reinterpret_cast(QOpenGLStaticContext::opengl32.wglGetProcAddress("wglCreateContextAttribsARB")))), + wglSwapInternalExt(reinterpret_cast( + reinterpret_cast(QOpenGLStaticContext::opengl32.wglGetProcAddress("wglSwapIntervalEXT")))), + wglGetSwapInternalExt(reinterpret_cast( + reinterpret_cast(QOpenGLStaticContext::opengl32.wglGetProcAddress("wglGetSwapIntervalEXT")))), + wglGetExtensionsStringARB(reinterpret_cast( + reinterpret_cast(QOpenGLStaticContext::opengl32.wglGetProcAddress("wglGetExtensionsStringARB")))) { if (extensionNames.startsWith(SAMPLE_BUFFER_EXTENSION " ") || extensionNames.indexOf(" " SAMPLE_BUFFER_EXTENSION " ") != -1) @@ -1231,7 +1239,8 @@ bool QWindowsGLContext::updateObtainedParams(HDC hdc, int *obtainedSwapInterval) hasRobustness = exts && strstr(exts, "GL_ARB_robustness"); } else { typedef const GLubyte * (APIENTRY *glGetStringi_t)(GLenum, GLuint); - glGetStringi_t glGetStringi = (glGetStringi_t) QOpenGLStaticContext::opengl32.wglGetProcAddress("glGetStringi"); + glGetStringi_t glGetStringi = reinterpret_cast( + reinterpret_cast(QOpenGLStaticContext::opengl32.wglGetProcAddress("glGetStringi"))); if (glGetStringi) { GLint n = 0; QOpenGLStaticContext::opengl32.glGetIntegerv(GL_NUM_EXTENSIONS, &n); @@ -1244,8 +1253,10 @@ bool QWindowsGLContext::updateObtainedParams(HDC hdc, int *obtainedSwapInterval) } } } - if (hasRobustness) - m_getGraphicsResetStatus = (GLenum (APIENTRY *)()) QOpenGLStaticContext::opengl32.wglGetProcAddress("glGetGraphicsResetStatusARB"); + if (hasRobustness) { + m_getGraphicsResetStatus = reinterpret_cast( + reinterpret_cast(QOpenGLStaticContext::opengl32.wglGetProcAddress("glGetGraphicsResetStatusARB"))); + } QOpenGLStaticContext::opengl32.wglMakeCurrent(prevSurface, prevContext); return true; @@ -1369,16 +1380,17 @@ QFunctionPointer QWindowsGLContext::getProcAddress(const char *procName) // Even though we use QFunctionPointer, it does not mean the function can be called. // It will need to be cast to the proper function type with the correct calling // convention. QFunctionPointer is nothing more than a glorified void* here. - PROC procAddress = QOpenGLStaticContext::opengl32.wglGetProcAddress(procName); + QFunctionPointer procAddress = reinterpret_cast(QOpenGLStaticContext::opengl32.wglGetProcAddress(procName)); // We support AllGLFunctionsQueryable, which means this function must be able to // return a function pointer even for functions that are in GL.h and exported // normally from opengl32.dll. wglGetProcAddress() is not guaranteed to work for such // functions, however in QT_OPENGL_DYNAMIC builds QOpenGLFunctions will just blindly // call into here for _any_ OpenGL function. - if (!procAddress || procAddress == reinterpret_cast(0x1) || procAddress == reinterpret_cast(0x2) - || procAddress == reinterpret_cast(0x3) || procAddress == reinterpret_cast(-1)) + if (procAddress == nullptr || reinterpret_cast(procAddress) < 4u + || procAddress == reinterpret_cast(-1)) { procAddress = QOpenGLStaticContext::opengl32.resolve(procName); + } if (QWindowsContext::verbose > 1) qCDebug(lcQpaGl) << __FUNCTION__ << procName << QOpenGLStaticContext::opengl32.wglGetCurrentContext() << "returns" << procAddress; diff --git a/src/plugins/platforms/windows/qwindowsglcontext.h b/src/plugins/platforms/windows/qwindowsglcontext.h index 2e89711740..8c96a8dd0c 100644 --- a/src/plugins/platforms/windows/qwindowsglcontext.h +++ b/src/plugins/platforms/windows/qwindowsglcontext.h @@ -122,7 +122,7 @@ struct QWindowsOpengl32DLL void (APIENTRY * glGetIntegerv)(GLenum pname, GLint* params); const GLubyte * (APIENTRY * glGetString)(GLenum name); - FARPROC resolve(const char *name); + QFunctionPointer resolve(const char *name); private: HMODULE m_lib; bool m_nonOpengl32; @@ -217,6 +217,8 @@ public: void *nativeContext() const override { return m_renderingContext; } private: + typedef GLenum (APIENTRY *GlGetGraphicsResetStatusArbType)(); + inline void releaseDCs(); bool updateObtainedParams(HDC hdc, int *obtainedSwapInterval = 0); @@ -230,7 +232,7 @@ private: bool m_extensionsUsed; int m_swapInterval; bool m_ownsContext; - GLenum (APIENTRY * m_getGraphicsResetStatus)(); + GlGetGraphicsResetStatusArbType m_getGraphicsResetStatus; bool m_lost; }; #endif diff --git a/src/plugins/platforms/windows/qwindowsinputcontext.cpp b/src/plugins/platforms/windows/qwindowsinputcontext.cpp index 9f4dea915e..30da0da1de 100644 --- a/src/plugins/platforms/windows/qwindowsinputcontext.cpp +++ b/src/plugins/platforms/windows/qwindowsinputcontext.cpp @@ -163,19 +163,22 @@ Q_CORE_EXPORT QLocale qt_localeFromLCID(LCID id); // from qlocale_win.cpp */ -HIMC QWindowsInputContext::m_defaultContext = 0; - QWindowsInputContext::QWindowsInputContext() : m_WM_MSIME_MOUSE(RegisterWindowMessage(L"MSIMEMouseOperation")), m_languageId(currentInputLanguageId()), m_locale(qt_localeFromLCID(m_languageId)) { + const quint32 bmpData = 0; + m_transparentBitmap = CreateBitmap(2, 2, 1, 1, &bmpData); + connect(QGuiApplication::inputMethod(), &QInputMethod::cursorRectangleChanged, this, &QWindowsInputContext::cursorRectChanged); } QWindowsInputContext::~QWindowsInputContext() { + if (m_transparentBitmap) + DeleteObject(m_transparentBitmap); } bool QWindowsInputContext::hasCapability(Capability capability) const @@ -242,6 +245,43 @@ bool QWindowsInputContext::isInputPanelVisible() const return hwnd && ::IsWindowEnabled(hwnd) && ::IsWindowVisible(hwnd); } +void QWindowsInputContext::showInputPanel() +{ + if (!inputMethodAccepted()) + return; + + QWindow *window = QGuiApplication::focusWindow(); + if (!window) + return; + + QWindowsWindow *platformWindow = QWindowsWindow::windowsWindowOf(window); + if (!platformWindow) + return; + + // Create an invisible 2x2 caret, which will be kept at the microfocus position. + // It is important for triggering the on-screen keyboard in touch-screen devices, + // for some Chinese input methods, and for Magnifier's "follow keyboard" feature. + if (!m_caretCreated && m_transparentBitmap) + m_caretCreated = CreateCaret(platformWindow->handle(), m_transparentBitmap, 0, 0); + + // For some reason, the on-screen keyboard is only triggered on the Surface + // with Windows 10 if the Windows IME is (re)enabled _after_ the caret is shown. + if (m_caretCreated) { + cursorRectChanged(); + ShowCaret(platformWindow->handle()); + setWindowsImeEnabled(platformWindow, false); + setWindowsImeEnabled(platformWindow, true); + } +} + +void QWindowsInputContext::hideInputPanel() +{ + if (m_caretCreated) { + DestroyCaret(); + m_caretCreated = false; + } +} + void QWindowsInputContext::updateEnabled() { if (!QGuiApplication::focusObject()) @@ -256,18 +296,14 @@ void QWindowsInputContext::updateEnabled() void QWindowsInputContext::setWindowsImeEnabled(QWindowsWindow *platformWindow, bool enabled) { - if (!platformWindow || platformWindow->testFlag(QWindowsWindow::InputMethodDisabled) == !enabled) + if (!platformWindow) return; if (enabled) { - // Re-enable Windows IME by associating default context saved on first disabling. - ImmAssociateContext(platformWindow->handle(), QWindowsInputContext::m_defaultContext); - platformWindow->clearFlag(QWindowsWindow::InputMethodDisabled); + // Re-enable Windows IME by associating default context. + ImmAssociateContextEx(platformWindow->handle(), 0, IACE_DEFAULT); } else { - // Disable Windows IME by associating 0 context. Store context first time. - const HIMC oldImC = ImmAssociateContext(platformWindow->handle(), 0); - platformWindow->setFlag(QWindowsWindow::InputMethodDisabled); - if (!QWindowsInputContext::m_defaultContext && oldImC) - QWindowsInputContext::m_defaultContext = oldImC; + // Disable Windows IME by associating 0 context. + ImmAssociateContext(platformWindow->handle(), 0); } } @@ -284,15 +320,25 @@ void QWindowsInputContext::update(Qt::InputMethodQueries queries) void QWindowsInputContext::cursorRectChanged() { - if (!m_compositionContext.hwnd) + QWindow *window = QGuiApplication::focusWindow(); + if (!window) return; + + qreal factor = QHighDpiScaling::factor(window); + const QInputMethod *inputMethod = QGuiApplication::inputMethod(); const QRectF cursorRectangleF = inputMethod->cursorRectangle(); if (!cursorRectangleF.isValid()) return; + const QRect cursorRectangle = - QRectF(cursorRectangleF.topLeft() * m_compositionContext.factor, - cursorRectangleF.size() * m_compositionContext.factor).toRect(); + QRectF(cursorRectangleF.topLeft() * factor, cursorRectangleF.size() * factor).toRect(); + + if (m_caretCreated) + SetCaretPos(cursorRectangle.x(), cursorRectangle.y()); + + if (!m_compositionContext.hwnd) + return; qCDebug(lcQpaInputMethods) << __FUNCTION__<< cursorRectangle; @@ -316,9 +362,6 @@ void QWindowsInputContext::cursorRectChanged() candf.rcArea.right = cursorRectangle.x() + cursorRectangle.width(); candf.rcArea.bottom = cursorRectangle.y() + cursorRectangle.height(); - if (m_compositionContext.haveCaret) - SetCaretPos(cursorRectangle.x(), cursorRectangle.y()); - ImmSetCompositionWindow(himc, &cf); ImmSetCandidateWindow(himc, &candf); ImmReleaseContext(m_compositionContext.hwnd, himc); @@ -410,7 +453,7 @@ bool QWindowsInputContext::startComposition(HWND hwnd) qCDebug(lcQpaInputMethods) << __FUNCTION__ << fo << window << "language=" << m_languageId; if (!fo || QWindowsWindow::handleOf(window) != hwnd) return false; - initContext(hwnd, QHighDpiScaling::factor(window), fo); + initContext(hwnd, fo); startContextComposition(); return true; } @@ -550,18 +593,13 @@ bool QWindowsInputContext::endComposition(HWND hwnd) return true; } -void QWindowsInputContext::initContext(HWND hwnd, qreal factor, QObject *focusObject) +void QWindowsInputContext::initContext(HWND hwnd, QObject *focusObject) { if (m_compositionContext.hwnd) doneContext(); m_compositionContext.hwnd = hwnd; m_compositionContext.focusObject = focusObject; - m_compositionContext.factor = factor; - // Create a hidden caret which is kept at the microfocus - // position in update(). This is important for some - // Chinese input methods. - m_compositionContext.haveCaret = CreateCaret(hwnd, 0, 1, 1); - HideCaret(hwnd); + update(Qt::ImQueryAll); m_compositionContext.isComposing = false; m_compositionContext.position = 0; @@ -571,12 +609,10 @@ void QWindowsInputContext::doneContext() { if (!m_compositionContext.hwnd) return; - if (m_compositionContext.haveCaret) - DestroyCaret(); m_compositionContext.hwnd = 0; m_compositionContext.composition.clear(); m_compositionContext.position = 0; - m_compositionContext.isComposing = m_compositionContext.haveCaret = false; + m_compositionContext.isComposing = false; m_compositionContext.focusObject = 0; } diff --git a/src/plugins/platforms/windows/qwindowsinputcontext.h b/src/plugins/platforms/windows/qwindowsinputcontext.h index 35105d15ff..8668efbb15 100644 --- a/src/plugins/platforms/windows/qwindowsinputcontext.h +++ b/src/plugins/platforms/windows/qwindowsinputcontext.h @@ -58,12 +58,10 @@ class QWindowsInputContext : public QPlatformInputContext struct CompositionContext { HWND hwnd = 0; - bool haveCaret = false; QString composition; int position = 0; bool isComposing = false; QPointer focusObject; - qreal factor = 1; }; public: explicit QWindowsInputContext(); @@ -81,6 +79,8 @@ public: QRectF keyboardRect() const override; bool isInputPanelVisible() const override; + void showInputPanel() override; + void hideInputPanel() override; bool startComposition(HWND hwnd); bool composition(HWND hwnd, LPARAM lParam); @@ -96,7 +96,7 @@ private slots: void cursorRectChanged(); private: - void initContext(HWND hwnd, qreal factor, QObject *focusObject); + void initContext(HWND hwnd, QObject *focusObject); void doneContext(); void startContextComposition(); void endContextComposition(); @@ -104,7 +104,8 @@ private: HWND getVirtualKeyboardWindowHandle() const; const DWORD m_WM_MSIME_MOUSE; - static HIMC m_defaultContext; + bool m_caretCreated = false; + HBITMAP m_transparentBitmap; CompositionContext m_compositionContext; bool m_endCompositionRecursionGuard = false; LCID m_languageId; diff --git a/src/plugins/platforms/windows/qwindowsopengltester.cpp b/src/plugins/platforms/windows/qwindowsopengltester.cpp index a90a44c4e1..c4ee820211 100644 --- a/src/plugins/platforms/windows/qwindowsopengltester.cpp +++ b/src/plugins/platforms/windows/qwindowsopengltester.cpp @@ -283,16 +283,21 @@ QWindowsOpenGLTester::Renderers QWindowsOpenGLTester::supportedRenderers() bool QWindowsOpenGLTester::testDesktopGL() { #if !defined(QT_NO_OPENGL) + typedef HGLRC (WINAPI *CreateContextType)(HDC); + typedef BOOL (WINAPI *DeleteContextType)(HGLRC); + typedef BOOL (WINAPI *MakeCurrentType)(HDC, HGLRC); + typedef PROC (WINAPI *WglGetProcAddressType)(LPCSTR); + HMODULE lib = 0; HWND wnd = 0; HDC dc = 0; HGLRC context = 0; LPCTSTR className = L"qtopengltest"; - HGLRC (WINAPI * CreateContext)(HDC dc) = 0; - BOOL (WINAPI * DeleteContext)(HGLRC context) = 0; - BOOL (WINAPI * MakeCurrent)(HDC dc, HGLRC context) = 0; - PROC (WINAPI * WGL_GetProcAddress)(LPCSTR name) = 0; + CreateContextType CreateContext = nullptr; + DeleteContextType DeleteContext = nullptr; + MakeCurrentType MakeCurrent = nullptr; + WglGetProcAddressType WGL_GetProcAddress = nullptr; bool result = false; @@ -300,16 +305,20 @@ bool QWindowsOpenGLTester::testDesktopGL() // This will typically fail on systems that do not have a real OpenGL driver. lib = LoadLibraryA("opengl32.dll"); if (lib) { - CreateContext = reinterpret_cast(::GetProcAddress(lib, "wglCreateContext")); + CreateContext = reinterpret_cast( + reinterpret_cast(::GetProcAddress(lib, "wglCreateContext"))); if (!CreateContext) goto cleanup; - DeleteContext = reinterpret_cast(::GetProcAddress(lib, "wglDeleteContext")); + DeleteContext = reinterpret_cast( + reinterpret_cast(::GetProcAddress(lib, "wglDeleteContext"))); if (!DeleteContext) goto cleanup; - MakeCurrent = reinterpret_cast(::GetProcAddress(lib, "wglMakeCurrent")); + MakeCurrent = reinterpret_cast( + reinterpret_cast(::GetProcAddress(lib, "wglMakeCurrent"))); if (!MakeCurrent) goto cleanup; - WGL_GetProcAddress = reinterpret_cast(::GetProcAddress(lib, "wglGetProcAddress")); + WGL_GetProcAddress = reinterpret_cast( + reinterpret_cast(::GetProcAddress(lib, "wglGetProcAddress"))); if (!WGL_GetProcAddress) goto cleanup; @@ -356,7 +365,8 @@ bool QWindowsOpenGLTester::testDesktopGL() // Check the version. If we got 1.x then it's all hopeless and we can stop right here. typedef const GLubyte * (APIENTRY * GetString_t)(GLenum name); - GetString_t GetString = reinterpret_cast(::GetProcAddress(lib, "glGetString")); + GetString_t GetString = reinterpret_cast( + reinterpret_cast(::GetProcAddress(lib, "glGetString"))); if (GetString) { if (const char *versionStr = reinterpret_cast(GetString(GL_VERSION))) { const QByteArray version(versionStr); diff --git a/src/plugins/platforms/windows/qwindowswindow.h b/src/plugins/platforms/windows/qwindowswindow.h index 02e986fd90..5ff25eb474 100644 --- a/src/plugins/platforms/windows/qwindowswindow.h +++ b/src/plugins/platforms/windows/qwindowswindow.h @@ -215,12 +215,11 @@ public: WithinCreate = 0x20000, WithinMaximize = 0x40000, MaximizeToFullScreen = 0x80000, - InputMethodDisabled = 0x100000, - Compositing = 0x200000, - HasBorderInFullScreen = 0x400000, - WithinDpiChanged = 0x800000, - VulkanSurface = 0x1000000, - ResizeMoveActive = 0x2000000 + Compositing = 0x100000, + HasBorderInFullScreen = 0x200000, + WithinDpiChanged = 0x400000, + VulkanSurface = 0x800000, + ResizeMoveActive = 0x1000000 }; QWindowsWindow(QWindow *window, const QWindowsWindowData &data); diff --git a/src/plugins/platforms/xcb/qxcbbackingstore.cpp b/src/plugins/platforms/xcb/qxcbbackingstore.cpp index 8cfcc49f9a..b81cb8efa1 100644 --- a/src/plugins/platforms/xcb/qxcbbackingstore.cpp +++ b/src/plugins/platforms/xcb/qxcbbackingstore.cpp @@ -95,6 +95,9 @@ public: void put(xcb_drawable_t dst, const QRegion ®ion, const QPoint &offset); void preparePaint(const QRegion ®ion); + static bool createSystemVShmSegment(QXcbConnection *c, size_t segmentSize = 1, + xcb_shm_segment_info_t *shm_info = nullptr); + private: void createShmSegment(size_t segmentSize); void destroyShmSegment(size_t segmentSize); @@ -325,15 +328,16 @@ void QXcbBackingStoreImage::createShmSegment(size_t segmentSize) #ifdef XCB_USE_SHM_FD if (connection()->hasShmFd()) { if (Q_UNLIKELY(segmentSize > std::numeric_limits::max())) { - qWarning("QXcbShmImage: xcb_shm_create_segment() can't be called for size %zu, maximum allowed size is %u", - segmentSize, std::numeric_limits::max()); + qCWarning(lcQpaXcb, "xcb_shm_create_segment() can't be called for size %zu, maximum" + "allowed size is %u", segmentSize, std::numeric_limits::max()); return; } + const auto seg = xcb_generate_id(xcb_connection()); auto reply = Q_XCB_REPLY(xcb_shm_create_segment, xcb_connection(), seg, segmentSize, false); if (!reply) { - qWarning("QXcbShmImage: xcb_shm_create_segment() failed for size %zu", segmentSize); + qCWarning(lcQpaXcb, "xcb_shm_create_segment() failed for size %zu", segmentSize); return; } @@ -342,13 +346,13 @@ void QXcbBackingStoreImage::createShmSegment(size_t segmentSize) for (int i = 0; i < reply->nfd; i++) close(fds[i]); - qWarning("QXcbShmImage: failed to get file descriptor for shm segment of size %zu", segmentSize); + qCWarning(lcQpaXcb, "failed to get file descriptor for shm segment of size %zu", segmentSize); return; } void *addr = mmap(nullptr, segmentSize, PROT_READ|PROT_WRITE, MAP_SHARED, fds[0], 0); if (addr == MAP_FAILED) { - qWarning("QXcbShmImage: failed to mmap segment from X server (%d: %s) for size %zu", + qCWarning(lcQpaXcb, "failed to mmap segment from X server (%d: %s) for size %zu", errno, strerror(errno), segmentSize); close(fds[0]); xcb_shm_detach(xcb_connection(), seg); @@ -358,49 +362,56 @@ void QXcbBackingStoreImage::createShmSegment(size_t segmentSize) close(fds[0]); m_shm_info.shmseg = seg; m_shm_info.shmaddr = static_cast(addr); - m_segmentSize = segmentSize; } else #endif { - const int id = shmget(IPC_PRIVATE, segmentSize, IPC_CREAT | 0600); - if (id == -1) { - qWarning("QXcbShmImage: shmget() failed (%d: %s) for size %zu", - errno, strerror(errno), segmentSize); - return; - } - - void *addr = shmat(id, 0, 0); - if (addr == (void *)-1) { - qWarning("QXcbShmImage: shmat() failed (%d: %s) for id %d", - errno, strerror(errno), id); - return; - } - - if (shmctl(id, IPC_RMID, 0) == -1) - qWarning("QXcbBackingStore: Error while marking the shared memory segment to be destroyed"); - - const auto seg = xcb_generate_id(xcb_connection()); - auto cookie = xcb_shm_attach_checked(xcb_connection(), seg, id, false); - auto *error = xcb_request_check(xcb_connection(), cookie); - if (error) { - connection()->printXcbError("QXcbShmImage: xcb_shm_attach() failed with error", error); - free(error); - if (shmdt(addr) == -1) { - qWarning("QXcbShmImage: shmdt() failed (%d: %s) for %p", - errno, strerror(errno), addr); - } - return; - } - - m_shm_info.shmseg = seg; - m_shm_info.shmid = id; // unused - m_shm_info.shmaddr = static_cast(addr); - - m_segmentSize = segmentSize; + if (createSystemVShmSegment(connection(), segmentSize, &m_shm_info)) + m_segmentSize = segmentSize; } } +bool QXcbBackingStoreImage::createSystemVShmSegment(QXcbConnection *c, size_t segmentSize, + xcb_shm_segment_info_t *shmInfo) +{ + const int id = shmget(IPC_PRIVATE, segmentSize, IPC_CREAT | 0600); + if (id == -1) { + qCWarning(lcQpaXcb, "shmget() failed (%d: %s) for size %zu", errno, strerror(errno), segmentSize); + return false; + } + + void *addr = shmat(id, 0, 0); + if (addr == (void *)-1) { + qCWarning(lcQpaXcb, "shmat() failed (%d: %s) for id %d", errno, strerror(errno), id); + return false; + } + + if (shmctl(id, IPC_RMID, 0) == -1) + qCWarning(lcQpaXcb, "Error while marking the shared memory segment to be destroyed"); + + const auto seg = xcb_generate_id(c->xcb_connection()); + auto cookie = xcb_shm_attach_checked(c->xcb_connection(), seg, id, false); + auto *error = xcb_request_check(c->xcb_connection(), cookie); + if (error) { + c->printXcbError("xcb_shm_attach() failed with error", error); + free(error); + if (shmdt(addr) == -1) + qCWarning(lcQpaXcb, "shmdt() failed (%d: %s) for %p", errno, strerror(errno), addr); + return false; + } else if (!shmInfo) { // this was a test run, free the allocated test segment + xcb_shm_detach(c->xcb_connection(), seg); + auto shmaddr = static_cast(addr); + if (shmdt(shmaddr) == -1) + qCWarning(lcQpaXcb, "shmdt() failed (%d: %s) for %p", errno, strerror(errno), shmaddr); + } + if (shmInfo) { + shmInfo->shmseg = seg; + shmInfo->shmid = id; // unused + shmInfo->shmaddr = static_cast(addr); + } + return true; +} + void QXcbBackingStoreImage::destroyShmSegment(size_t segmentSize) { #ifndef XCB_USE_SHM_FD @@ -409,21 +420,21 @@ void QXcbBackingStoreImage::destroyShmSegment(size_t segmentSize) auto cookie = xcb_shm_detach_checked(xcb_connection(), m_shm_info.shmseg); xcb_generic_error_t *error = xcb_request_check(xcb_connection(), cookie); if (error) - connection()->printXcbError("QXcbShmImage: xcb_shm_detach() failed with error", error); + connection()->printXcbError("xcb_shm_detach() failed with error", error); m_shm_info.shmseg = 0; #ifdef XCB_USE_SHM_FD if (connection()->hasShmFd()) { if (munmap(m_shm_info.shmaddr, segmentSize) == -1) { - qWarning("QXcbShmImage: munmap() failed (%d: %s) for %p with size %zu", - errno, strerror(errno), m_shm_info.shmaddr, segmentSize); + qCWarning(lcQpaXcb, "munmap() failed (%d: %s) for %p with size %zu", + errno, strerror(errno), m_shm_info.shmaddr, segmentSize); } } else #endif { if (shmdt(m_shm_info.shmaddr) == -1) { - qWarning("QXcbShmImage: shmdt() failed (%d: %s) for %p", - errno, strerror(errno), m_shm_info.shmaddr); + qCWarning(lcQpaXcb, "shmdt() failed (%d: %s) for %p", + errno, strerror(errno), m_shm_info.shmaddr); } m_shm_info.shmid = 0; // unused } @@ -718,6 +729,12 @@ void QXcbBackingStoreImage::preparePaint(const QRegion ®ion) m_pendingFlush |= region; } +bool QXcbBackingStore::createSystemVShmSegment(QXcbConnection *c, size_t segmentSize, void *shmInfo) +{ + auto info = reinterpret_cast(shmInfo); + return QXcbBackingStoreImage::createSystemVShmSegment(c, segmentSize, info); +} + QXcbBackingStore::QXcbBackingStore(QWindow *window) : QPlatformBackingStore(window) { @@ -757,7 +774,7 @@ void QXcbBackingStore::beginPaint(const QRegion ®ion) void QXcbBackingStore::endPaint() { if (Q_UNLIKELY(m_paintRegions.isEmpty())) { - qWarning("%s: paint regions empty!", Q_FUNC_INFO); + qCWarning(lcQpaXcb, "%s: paint regions empty!", Q_FUNC_INFO); return; } @@ -811,7 +828,7 @@ void QXcbBackingStore::flush(QWindow *window, const QRegion ®ion, const QPoin QXcbWindow *platformWindow = static_cast(window->handle()); if (!platformWindow) { - qWarning("QXcbBackingStore::flush: QWindow has no platform window (QTBUG-32681)"); + qCWarning(lcQpaXcb, "%s QWindow has no platform window, see QTBUG-32681", Q_FUNC_INFO); return; } diff --git a/src/plugins/platforms/xcb/qxcbbackingstore.h b/src/plugins/platforms/xcb/qxcbbackingstore.h index 747626c213..734de1f7d7 100644 --- a/src/plugins/platforms/xcb/qxcbbackingstore.h +++ b/src/plugins/platforms/xcb/qxcbbackingstore.h @@ -74,6 +74,9 @@ public: void beginPaint(const QRegion &) override; void endPaint() override; + static bool createSystemVShmSegment(QXcbConnection *c, size_t segmentSize = 1, + void *shmInfo = nullptr); + private: QXcbBackingStoreImage *m_image = nullptr; QStack m_paintRegions; diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp index 4ffeb4ff77..0e45b1efaf 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection.cpp @@ -56,6 +56,7 @@ #include "qxcbglintegrationfactory.h" #include "qxcbglintegration.h" #include "qxcbcursor.h" +#include "qxcbbackingstore.h" #include #include @@ -591,7 +592,8 @@ QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, bool canGra initializeAllAtoms(); initializeXSync(); - initializeShm(); + if (!qEnvironmentVariableIsSet("QT_XCB_NO_MITSHM")) + initializeShm(); if (!qEnvironmentVariableIsSet("QT_XCB_NO_XRANDR")) initializeXRandr(); if (!has_randr_extension) @@ -979,7 +981,7 @@ void QXcbConnection::printXcbError(const char *message, xcb_generic_error_t *err uint clamped_error_code = qMin(error->error_code, (sizeof(xcb_errors) / sizeof(xcb_errors[0])) - 1); uint clamped_major_code = qMin(error->major_code, (sizeof(xcb_protocol_request_codes) / sizeof(xcb_protocol_request_codes[0])) - 1); - qWarning("%s: %d (%s), sequence: %d, resource id: %d, major code: %d (%s), minor code: %d", + qCWarning(lcQpaXcb, "%s: %d (%s), sequence: %d, resource id: %d, major code: %d (%s), minor code: %d", message, int(error->error_code), xcb_errors[clamped_error_code], int(error->sequence), int(error->resource_id), @@ -1661,7 +1663,7 @@ bool QXcbConnection::compressEvent(xcb_generic_event_t *event, int currentIndex, if (!hasXInput2()) return false; - // compress XI_Motion, but not from tablet devices + // compress XI_Motion if (isXIType(event, m_xiOpCode, XCB_INPUT_MOTION)) { #if QT_CONFIG(tabletevent) auto *xdev = reinterpret_cast(event); @@ -2074,20 +2076,34 @@ void QXcbConnection::initializeShm() { const xcb_query_extension_reply_t *reply = xcb_get_extension_data(m_connection, &xcb_shm_id); if (!reply || !reply->present) { - qWarning("QXcbConnection: MIT-SHM extension is not present on the X server."); + qCDebug(lcQpaXcb, "MIT-SHM extension is not present on the X server"); return; } - has_shm = true; auto shm_query = Q_XCB_REPLY(xcb_shm_query_version, m_connection); - if (!shm_query) { - qWarning("QXcbConnection: Failed to request MIT-SHM version"); - return; + if (shm_query) { + has_shm_fd = (shm_query->major_version == 1 && shm_query->minor_version >= 2) || + shm_query->major_version > 1; + } else { + qCWarning(lcQpaXcb, "QXcbConnection: Failed to request MIT-SHM version"); } - has_shm_fd = (shm_query->major_version == 1 && shm_query->minor_version >= 2) || - shm_query->major_version > 1; + qCDebug(lcQpaXcb) << "Has MIT-SHM :" << has_shm; + qCDebug(lcQpaXcb) << "Has MIT-SHM FD :" << has_shm_fd; + + // Temporary disable warnings (unless running in debug mode). + auto logging = const_cast(&lcQpaXcb()); + bool wasEnabled = logging->isEnabled(QtMsgType::QtWarningMsg); + if (!logging->isEnabled(QtMsgType::QtDebugMsg)) + logging->setEnabled(QtMsgType::QtWarningMsg, false); + if (!QXcbBackingStore::createSystemVShmSegment(this)) { + qCDebug(lcQpaXcb, "failed to create System V shared memory segment (remote " + "X11 connection?), disabling SHM"); + has_shm = has_shm_fd = false; + } + if (wasEnabled) + logging->setEnabled(QtMsgType::QtWarningMsg, true); } void QXcbConnection::initializeXFixes() diff --git a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp index 475afa65db..7ed61bff4e 100644 --- a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp @@ -1017,6 +1017,7 @@ void QXcbConnection::xi2HandleScrollEvent(void *event, ScrollingDevice &scrollin std::swap(angleDelta.rx(), angleDelta.ry()); std::swap(rawDelta.rx(), rawDelta.ry()); } + qCDebug(lcQpaXInputEvents) << "scroll wheel @ window pos" << local << "delta px" << rawDelta << "angle" << angleDelta; QWindowSystemInterface::handleWheelEvent(platformWindow->window(), xiDeviceEvent->time, local, global, rawDelta, angleDelta, modifiers); } } @@ -1041,6 +1042,7 @@ void QXcbConnection::xi2HandleScrollEvent(void *event, ScrollingDevice &scrollin Qt::KeyboardModifiers modifiers = keyboard()->translateModifiers(xiDeviceEvent->mods.effective); if (modifiers & Qt::AltModifier) std::swap(angleDelta.rx(), angleDelta.ry()); + qCDebug(lcQpaXInputEvents) << "scroll wheel (button" << xiDeviceEvent->detail << ") @ window pos" << local << "delta angle" << angleDelta; QWindowSystemInterface::handleWheelEvent(platformWindow->window(), xiDeviceEvent->time, local, global, QPoint(), angleDelta, modifiers); } } diff --git a/src/plugins/platforms/xcb/qxcbkeyboard.cpp b/src/plugins/platforms/xcb/qxcbkeyboard.cpp index d9cddef2d2..3ad16d78d9 100644 --- a/src/plugins/platforms/xcb/qxcbkeyboard.cpp +++ b/src/plugins/platforms/xcb/qxcbkeyboard.cpp @@ -136,6 +136,13 @@ static const unsigned int KeyTbl[] = { XKB_KEY_KP_Decimal, Qt::Key_Period, XKB_KEY_KP_Divide, Qt::Key_Slash, + // special non-XF86 function keys + + XKB_KEY_Undo, Qt::Key_Undo, + XKB_KEY_Redo, Qt::Key_Redo, + XKB_KEY_Find, Qt::Key_Find, + XKB_KEY_Cancel, Qt::Key_Cancel, + // International input method support keys // International & multi-key character composition diff --git a/src/plugins/platforms/xcb/qxcbscreen.cpp b/src/plugins/platforms/xcb/qxcbscreen.cpp index 3b440bbb71..dd7e054301 100644 --- a/src/plugins/platforms/xcb/qxcbscreen.cpp +++ b/src/plugins/platforms/xcb/qxcbscreen.cpp @@ -744,12 +744,7 @@ void QXcbScreen::updateGeometry(const QRect &geometry, uint8_t rotation) m_sizeMillimeters = sizeInMillimeters(geometry.size(), virtualDpi()); qreal dpi = geometry.width() / physicalSize().width() * qreal(25.4); - qreal rawFactor = dpi/96; - int roundedFactor = qFloor(rawFactor); - // Round up for .8 and higher. This favors "small UI" over "large UI". - if (rawFactor - roundedFactor >= 0.8) - roundedFactor = qCeil(rawFactor); - m_pixelDensity = qMax(1, roundedFactor); + m_pixelDensity = qMax(1, qRound(dpi/96)); m_geometry = geometry; m_availableGeometry = geometry & m_virtualDesktop->workArea(); QWindowSystemInterface::handleScreenGeometryChange(QPlatformScreen::screen(), m_geometry, m_availableGeometry); diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index 3c2d4edc4d..9192f1d9e4 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -2200,15 +2200,15 @@ void QXcbWindow::handleEnterNotifyEvent(int event_x, int event_y, int root_x, in quint8 mode, quint8 detail, xcb_timestamp_t timestamp) { connection()->setTime(timestamp); -#if QT_CONFIG(xcb_xinput) - // Updates scroll valuators, as user might have done some scrolling outside our X client. - connection()->xi2UpdateScrollingDevices(); -#endif const QPoint global = QPoint(root_x, root_y); if (ignoreEnterEvent(mode, detail, connection()) || connection()->mousePressWindow()) return; +#if QT_CONFIG(xcb_xinput) + // Updates scroll valuators, as user might have done some scrolling outside our X client. + connection()->xi2UpdateScrollingDevices(); +#endif const QPoint local(event_x, event_y); QWindowSystemInterface::handleEnterEvent(window(), local, global); diff --git a/src/plugins/sqldrivers/ibase/qsql_ibase.cpp b/src/plugins/sqldrivers/ibase/qsql_ibase.cpp index 484dad6e1d..ead08dbce8 100644 --- a/src/plugins/sqldrivers/ibase/qsql_ibase.cpp +++ b/src/plugins/sqldrivers/ibase/qsql_ibase.cpp @@ -1845,9 +1845,11 @@ bool QIBaseDriver::subscribeToNotification(const QString &name) eBuffer->bufferLength, eBuffer->eventBuffer, #if defined (FB_API_VER) && FB_API_VER >= 20 - reinterpret_cast(qEventCallback), + reinterpret_cast(reinterpret_cast + (&qEventCallback)), #else - reinterpret_cast(qEventCallback), + reinterpret_cast(reinterpret_cast + (&qEventCallback)), #endif eBuffer->resultBuffer); @@ -1925,9 +1927,11 @@ void QIBaseDriver::qHandleEventNotification(void *updatedResultBuffer) eBuffer->bufferLength, eBuffer->eventBuffer, #if defined (FB_API_VER) && FB_API_VER >= 20 - reinterpret_cast(qEventCallback), + reinterpret_cast(reinterpret_cast + (&qEventCallback)), #else - reinterpret_cast(qEventCallback), + reinterpret_cast(reinterpret_cast + (&qEventCallback)), #endif eBuffer->resultBuffer); if (Q_UNLIKELY(status[0] == 1 && status[1])) { diff --git a/src/plugins/styles/mac/qmacstyle_mac.mm b/src/plugins/styles/mac/qmacstyle_mac.mm index bb5f25e4d7..60fe547807 100644 --- a/src/plugins/styles/mac/qmacstyle_mac.mm +++ b/src/plugins/styles/mac/qmacstyle_mac.mm @@ -238,24 +238,6 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QVerticalSplitView); } @end -#if !QT_CONFIG(appstore_compliant) - -// This API was requested to Apple in rdar #36197888. -// We know it's safe to use up to macOS 10.13.3. -// See drawComplexControl(CC_ComboBox) for its usage. - -@interface NSComboBoxCell (QtButtonCell) -@property (readonly) NSButtonCell *qt_buttonCell; -@end - -@implementation NSComboBoxCell (QtButtonCell) -- (NSButtonCell *)qt_buttonCell { - return self->_buttonCell; -} -@end - -#endif - QT_BEGIN_NAMESPACE // The following constants are used for adjusting the size @@ -5205,11 +5187,14 @@ void QMacStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex auto *cb = static_cast(cc); const auto frameRect = cw.adjustedControlFrame(combo->rect); cb.frame = frameRect.toCGRect(); -#if !QT_CONFIG(appstore_compliant) - static_cast(cc.cell).qt_buttonCell.highlighted = isPressed; -#else - // TODO Render to pixmap and darken the button manually -#endif + + // This API was requested to Apple in rdar #36197888. We know it's safe to use up to macOS 10.13.3 + if (NSButtonCell *cell = static_cast([cc.cell qt_valueForPrivateKey:@"_buttonCell"])) { + cell.highlighted = isPressed; + } else { + // TODO Render to pixmap and darken the button manually + } + d->drawNSViewInRect(cb, frameRect, p, ^(CGContextRef __unused ctx, const CGRect &r) { // FIXME This is usually drawn in the control's superview, but we wouldn't get inactive look in this case [cb.cell drawWithFrame:r inView:cb]; diff --git a/src/plugins/styles/windowsvista/qwindowsxpstyle.cpp b/src/plugins/styles/windowsvista/qwindowsxpstyle.cpp index e690a424ac..4b583e13d3 100644 --- a/src/plugins/styles/windowsvista/qwindowsxpstyle.cpp +++ b/src/plugins/styles/windowsvista/qwindowsxpstyle.cpp @@ -944,7 +944,7 @@ bool QWindowsXPStylePrivate::drawBackgroundThruNativeBuffer(XPThemeData &themeDa if (!isCached) { // SHORTCUT: If the part's state has no data, cache it for NOOP later if (!stateHasData) { - memset(&data, 0, sizeof(data)); + memset(static_cast(&data), 0, sizeof(data)); data.dataValid = true; alphaCache.insert(key, data); return true; @@ -1051,7 +1051,7 @@ bool QWindowsXPStylePrivate::drawBackgroundThruNativeBuffer(XPThemeData &themeDa // Add to theme part cache if (!isCached) { - memset(&data, 0, sizeof(data)); + memset(static_cast(&data), 0, sizeof(data)); data.dataValid = true; data.partIsTransparent = partIsTransparent; data.alphaType = alphaType; diff --git a/src/src.pro b/src/src.pro index 1f7c5d99c1..1c76a2e46f 100644 --- a/src/src.pro +++ b/src/src.pro @@ -53,6 +53,10 @@ src_tools_qdbuscpp2xml.target = sub-qdbuscpp2xml force_bootstrap: src_tools_qdbuscpp2xml.depends = src_tools_bootstrap_dbus else: src_tools_qdbuscpp2xml.depends = src_dbus +src_tools_androiddeployqt.subdir = tools/androiddeployqt +src_tools_androiddeployqt.target = sub-androiddeployqt +src_tools_androiddeployqt.depends = src_corelib + src_tools_qvkgen.subdir = tools/qvkgen src_tools_qvkgen.target = sub-qvkgen force_bootstrap: src_tools_qvkgen.depends = src_tools_bootstrap @@ -183,6 +187,12 @@ qtConfig(dbus) { src_platformsupport.depends += src_dbus src_tools_qdbusxml2cpp src_plugins.depends += src_dbus src_tools_qdbusxml2cpp src_tools_qdbuscpp2xml } + +android { + SUBDIRS += src_tools_androiddeployqt + TOOLS += src_tools_androiddeployqt +} + qtConfig(concurrent): SUBDIRS += src_concurrent qtConfig(gui) { qtConfig(harfbuzz):!qtConfig(system-harfbuzz) { diff --git a/src/testlib/qabstractitemmodeltester.cpp b/src/testlib/qabstractitemmodeltester.cpp index e970be2c8d..fc6f696ecd 100644 --- a/src/testlib/qabstractitemmodeltester.cpp +++ b/src/testlib/qabstractitemmodeltester.cpp @@ -322,9 +322,10 @@ void QAbstractItemModelTesterPrivate::nonDestructiveBasicTest() Qt::ItemFlags flags = model->flags(QModelIndex()); MODELTESTER_VERIFY(flags == Qt::ItemIsDropEnabled || flags == 0); model->hasChildren(QModelIndex()); - model->hasIndex(0, 0); + const bool hasRow = model->hasIndex(0, 0); QVariant cache; - model->match(QModelIndex(), -1, cache); + if (hasRow) + model->match(model->index(0, 0), -1, cache); model->mimeTypes(); MODELTESTER_VERIFY(!model->parent(QModelIndex()).isValid()); MODELTESTER_VERIFY(model->rowCount() >= 0); @@ -712,8 +713,17 @@ void QAbstractItemModelTesterPrivate::rowsAboutToBeRemoved(const QModelIndex &pa Changing c; c.parent = parent; c.oldSize = model->rowCount(parent); - c.last = model->data(model->index(start - 1, 0, parent)); - c.next = model->data(model->index(end + 1, 0, parent)); + if (start > 0) { + const QModelIndex startIndex = model->index(start - 1, 0, parent); + MODELTESTER_VERIFY(startIndex.isValid()); + c.last = model->data(startIndex); + } + if (end < c.oldSize - 1) { + const QModelIndex endIndex = model->index(end + 1, 0, parent); + MODELTESTER_VERIFY(endIndex.isValid()); + c.next = model->data(endIndex); + } + remove.push(c); } @@ -732,8 +742,10 @@ void QAbstractItemModelTesterPrivate::rowsRemoved(const QModelIndex &parent, int Changing c = remove.pop(); MODELTESTER_COMPARE(parent, c.parent); MODELTESTER_COMPARE(model->rowCount(parent), c.oldSize - (end - start + 1)); - MODELTESTER_COMPARE(model->data(model->index(start - 1, 0, c.parent)), c.last); - MODELTESTER_COMPARE(model->data(model->index(start, 0, c.parent)), c.next); + if (start > 0) + MODELTESTER_COMPARE(model->data(model->index(start - 1, 0, c.parent)), c.last); + if (end < c.oldSize - 1) + MODELTESTER_COMPARE(model->data(model->index(start, 0, c.parent)), c.next); } void QAbstractItemModelTesterPrivate::dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight) diff --git a/src/testlib/qabstractitemmodeltester.h b/src/testlib/qabstractitemmodeltester.h index 07bc170a7a..757074c6ae 100644 --- a/src/testlib/qabstractitemmodeltester.h +++ b/src/testlib/qabstractitemmodeltester.h @@ -42,6 +42,8 @@ #include #include +#include +#include #ifdef QT_GUI_LIB #include diff --git a/src/testlib/qtestcase.cpp b/src/testlib/qtestcase.cpp index 469c423109..7a74afce91 100644 --- a/src/testlib/qtestcase.cpp +++ b/src/testlib/qtestcase.cpp @@ -1634,8 +1634,10 @@ DebugSymbolResolver::DebugSymbolResolver(HANDLE process) bool success = false; m_dbgHelpLib = LoadLibraryW(L"dbghelp.dll"); if (m_dbgHelpLib) { - SymInitializeType symInitialize = (SymInitializeType)(GetProcAddress(m_dbgHelpLib, "SymInitialize")); - m_symFromAddr = (SymFromAddrType)(GetProcAddress(m_dbgHelpLib, "SymFromAddr")); + SymInitializeType symInitialize = reinterpret_cast( + reinterpret_cast(GetProcAddress(m_dbgHelpLib, "SymInitialize"))); + m_symFromAddr = reinterpret_cast( + reinterpret_cast(GetProcAddress(m_dbgHelpLib, "SymFromAddr"))); success = symInitialize && m_symFromAddr && symInitialize(process, NULL, TRUE); } if (!success) @@ -2166,8 +2168,9 @@ QString QTest::qFindTestData(const QString& base, const char *file, int line, co srcdir.setFile(QFile::decodeName(builddir) + QLatin1String("/") + srcdir.filePath()); } - QString candidate = QString::fromLatin1("%1/%2").arg(srcdir.canonicalFilePath(), base); - if (QFileInfo::exists(candidate)) { + const QString canonicalPath = srcdir.canonicalFilePath(); + QString candidate = QString::fromLatin1("%1/%2").arg(canonicalPath, base); + if (!canonicalPath.isEmpty() && QFileInfo::exists(candidate)) { found = candidate; } else if (QTestLog::verboseLevel() >= 2) { diff --git a/src/tools/androiddeployqt/androiddeployqt.pro b/src/tools/androiddeployqt/androiddeployqt.pro new file mode 100644 index 0000000000..2d0f5b41d1 --- /dev/null +++ b/src/tools/androiddeployqt/androiddeployqt.pro @@ -0,0 +1,14 @@ +option(host_build) +CONFIG += console + +SOURCES += \ + main.cpp + +# Required for declarations of popen/pclose on Windows +windows: QMAKE_CXXFLAGS += -U__STRICT_ANSI__ + +DEFINES += QT_NO_CAST_FROM_ASCII QT_NO_CAST_TO_ASCII +DEFINES += QT_NO_FOREACH + +load(qt_app) + diff --git a/src/tools/androiddeployqt/main.cpp b/src/tools/androiddeployqt/main.cpp new file mode 100644 index 0000000000..ebd9480808 --- /dev/null +++ b/src/tools/androiddeployqt/main.cpp @@ -0,0 +1,2912 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the tools applications 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +static const bool mustReadOutputAnyway = true; // pclose seems to return the wrong error code unless we read the output + +void deleteRecursively(const QString &dirName) +{ + QDir dir(dirName); + if (!dir.exists()) + return; + + const QFileInfoList entries = dir.entryInfoList(QDir::NoDotAndDotDot | QDir::Files | QDir::Dirs); + for (const QFileInfo &entry : entries) { + if (entry.isDir()) + deleteRecursively(entry.absoluteFilePath()); + else + QFile::remove(entry.absoluteFilePath()); + } + + QDir().rmdir(dirName); +} + +FILE *openProcess(const QString &command) +{ +#if defined(Q_OS_WIN32) + QString processedCommand = QLatin1Char('\"') + command + QLatin1Char('\"'); +#else + QString processedCommand = command; +#endif + + return popen(processedCommand.toLocal8Bit().constData(), "r"); +} + +struct QtDependency +{ + QtDependency(QString rpath, QString apath) : relativePath(rpath), absolutePath(apath) {} + + bool operator==(const QtDependency &other) const + { + return relativePath == other.relativePath && absolutePath == other.absolutePath; + } + + QString relativePath; + QString absolutePath; +}; + +struct Options +{ + Options() + : helpRequested(false) + , verbose(false) + , timing(false) + , generateAssetsFileList(true) + , build(true) + , gradle(false) + , deploymentMechanism(Bundled) + , releasePackage(false) + , digestAlg(QLatin1String("SHA1")) + , sigAlg(QLatin1String("SHA1withRSA")) + , internalSf(false) + , sectionsOnly(false) + , protectedAuthenticationPath(false) + , jarSigner(false) + , gdbServer(Auto) + , installApk(false) + , uninstallApk(false) + {} + + enum DeploymentMechanism + { + Bundled, + Ministro + }; + + enum TriState { + Auto, + False, + True + }; + + bool helpRequested; + bool verbose; + bool timing; + bool generateAssetsFileList; + bool build; + bool gradle; + QTime timer; + + // External tools + QString sdkPath; + QString sdkBuildToolsVersion; + QString ndkPath; + QString antTool; + QString jdkPath; + + // Build paths + QString qtInstallDirectory; + QString androidSourceDirectory; + QString outputDirectory; + QString inputFileName; + QString applicationBinary; + QString rootPath; + QStringList qmlImportPaths; + + // lib c++ path + QString stdCppPath; + QString stdCppName = QStringLiteral("gnustl_shared"); + + // Build information + QString androidPlatform; + QString architecture; + QString toolchainVersion; + QString toolchainPrefix; + QString toolPrefix; + QString ndkHost; + + // Package information + DeploymentMechanism deploymentMechanism; + QString packageName; + QStringList extraLibs; + QStringList extraPlugins; + + // Signing information + bool releasePackage; + QString keyStore; + QString keyStorePassword; + QString keyStoreAlias; + QString storeType; + QString keyPass; + QString sigFile; + QString signedJar; + QString digestAlg; + QString sigAlg; + QString tsaUrl; + QString tsaCert; + bool internalSf; + bool sectionsOnly; + bool protectedAuthenticationPath; + bool jarSigner; + + // Gdbserver + TriState gdbServer; + + // Installation information + bool installApk; + bool uninstallApk; + QString installLocation; + + // Collected information + typedef QPair BundledFile; + QList bundledFiles; + QList qtDependencies; + QStringList localLibs; + QStringList localJars; + QStringList initClasses; + QStringList permissions; + QStringList features; +}; + +// Copy-pasted from qmake/library/ioutil.cpp +inline static bool hasSpecialChars(const QString &arg, const uchar (&iqm)[16]) +{ + for (int x = arg.length() - 1; x >= 0; --x) { + ushort c = arg.unicode()[x].unicode(); + if ((c < sizeof(iqm) * 8) && (iqm[c / 8] & (1 << (c & 7)))) + return true; + } + return false; +} + +static QString shellQuoteUnix(const QString &arg) +{ + // Chars that should be quoted (TM). This includes: + static const uchar iqm[] = { + 0xff, 0xff, 0xff, 0xff, 0xdf, 0x07, 0x00, 0xd8, + 0x00, 0x00, 0x00, 0x38, 0x01, 0x00, 0x00, 0x78 + }; // 0-32 \'"$`<>|;&(){}*?#!~[] + + if (!arg.length()) + return QString::fromLatin1("\"\""); + + QString ret(arg); + if (hasSpecialChars(ret, iqm)) { + ret.replace(QLatin1Char('\''), QLatin1String("'\\''")); + ret.prepend(QLatin1Char('\'')); + ret.append(QLatin1Char('\'')); + } + return ret; +} + +static QString shellQuoteWin(const QString &arg) +{ + // Chars that should be quoted (TM). This includes: + // - control chars & space + // - the shell meta chars "&()<>^| + // - the potential separators ,;= + static const uchar iqm[] = { + 0xff, 0xff, 0xff, 0xff, 0x45, 0x13, 0x00, 0x78, + 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x10 + }; + + if (!arg.length()) + return QString::fromLatin1("\"\""); + + QString ret(arg); + if (hasSpecialChars(ret, iqm)) { + // Quotes are escaped and their preceding backslashes are doubled. + // It's impossible to escape anything inside a quoted string on cmd + // level, so the outer quoting must be "suspended". + ret.replace(QRegExp(QLatin1String("(\\\\*)\"")), QLatin1String("\"\\1\\1\\^\"\"")); + // The argument must not end with a \ since this would be interpreted + // as escaping the quote -- rather put the \ behind the quote: e.g. + // rather use "foo"\ than "foo\" + int i = ret.length(); + while (i > 0 && ret.at(i - 1) == QLatin1Char('\\')) + --i; + ret.insert(i, QLatin1Char('"')); + ret.prepend(QLatin1Char('"')); + } + return ret; +} + +static QString shellQuote(const QString &arg) +{ + if (QDir::separator() == QLatin1Char('\\')) + return shellQuoteWin(arg); + else + return shellQuoteUnix(arg); +} + + +void deleteMissingFiles(const Options &options, const QDir &srcDir, const QDir &dstDir) +{ + if (options.verbose) + fprintf(stdout, "Delete missing files %s %s\n", qPrintable(srcDir.absolutePath()), qPrintable(dstDir.absolutePath())); + + const QFileInfoList srcEntries = srcDir.entryInfoList(QDir::NoDotAndDotDot | QDir::Files | QDir::Dirs); + const QFileInfoList dstEntries = dstDir.entryInfoList(QDir::NoDotAndDotDot | QDir::Files | QDir::Dirs); + for (const QFileInfo &dst : dstEntries) { + bool found = false; + for (const QFileInfo &src : srcEntries) + if (dst.fileName() == src.fileName()) { + if (dst.isDir()) + deleteMissingFiles(options, src.absoluteFilePath(), dst.absoluteFilePath()); + found = true; + break; + } + + if (!found) { + if (options.verbose) + fprintf(stdout, "%s not found in %s, removing it.\n", qPrintable(dst.fileName()), qPrintable(srcDir.absolutePath())); + + if (dst.isDir()) + deleteRecursively(dst.absolutePath()); + else + QFile::remove(dst.absoluteFilePath()); + } + } + fflush(stdout); +} + + +Options parseOptions() +{ + Options options; + + QStringList arguments = QCoreApplication::arguments(); + for (int i=0; i= arguments.size()) { + options.helpRequested = true; + } else { + options.releasePackage = true; + options.keyStore = arguments.at(++i); + options.keyStoreAlias = arguments.at(++i); + } + } else if (argument.compare(QLatin1String("--storepass"), Qt::CaseInsensitive) == 0) { + if (i + 1 == arguments.size()) + options.helpRequested = true; + else + options.keyStorePassword = arguments.at(++i); + } else if (argument.compare(QLatin1String("--storetype"), Qt::CaseInsensitive) == 0) { + if (i + 1 == arguments.size()) + options.helpRequested = true; + else + options.storeType = arguments.at(++i); + } else if (argument.compare(QLatin1String("--keypass"), Qt::CaseInsensitive) == 0) { + if (i + 1 == arguments.size()) + options.helpRequested = true; + else + options.keyPass = arguments.at(++i); + } else if (argument.compare(QLatin1String("--sigfile"), Qt::CaseInsensitive) == 0) { + if (i + 1 == arguments.size()) + options.helpRequested = true; + else + options.sigFile = arguments.at(++i); + } else if (argument.compare(QLatin1String("--digestalg"), Qt::CaseInsensitive) == 0) { + if (i + 1 == arguments.size()) + options.helpRequested = true; + else + options.digestAlg = arguments.at(++i); + } else if (argument.compare(QLatin1String("--sigalg"), Qt::CaseInsensitive) == 0) { + if (i + 1 == arguments.size()) + options.helpRequested = true; + else + options.sigAlg = arguments.at(++i); + } else if (argument.compare(QLatin1String("--tsa"), Qt::CaseInsensitive) == 0) { + if (i + 1 == arguments.size()) + options.helpRequested = true; + else + options.tsaUrl = arguments.at(++i); + } else if (argument.compare(QLatin1String("--tsacert"), Qt::CaseInsensitive) == 0) { + if (i + 1 == arguments.size()) + options.helpRequested = true; + else + options.tsaCert = arguments.at(++i); + } else if (argument.compare(QLatin1String("--internalsf"), Qt::CaseInsensitive) == 0) { + options.internalSf = true; + } else if (argument.compare(QLatin1String("--sectionsonly"), Qt::CaseInsensitive) == 0) { + options.sectionsOnly = true; + } else if (argument.compare(QLatin1String("--protected"), Qt::CaseInsensitive) == 0) { + options.protectedAuthenticationPath = true; + } else if (argument.compare(QLatin1String("--jarsigner"), Qt::CaseInsensitive) == 0) { + options.jarSigner = true; + } else if (argument.compare(QLatin1String("--no-generated-assets-cache"), Qt::CaseInsensitive) == 0) { + options.generateAssetsFileList = false; + } + } + + if (options.inputFileName.isEmpty()) + options.inputFileName = QString::fromLatin1("android-lib%1.so-deployment-settings.json").arg(QDir::current().dirName()); + + options.timing = qEnvironmentVariableIsSet("ANDROIDDEPLOYQT_TIMING_OUTPUT"); + + if (!QDir::current().mkpath(options.outputDirectory)) { + fprintf(stderr, "Invalid output directory: %s\n", qPrintable(options.outputDirectory)); + options.outputDirectory.clear(); + } else { + options.outputDirectory = QFileInfo(options.outputDirectory).canonicalFilePath(); + if (!options.outputDirectory.endsWith(QLatin1Char('/'))) + options.outputDirectory += QLatin1Char('/'); + } + + return options; +} + +void printHelp() +{// "012345678901234567890123456789012345678901234567890123456789012345678901" + fprintf(stderr, "Syntax: %s --output [options]\n" + "\n" + " Creates an Android package in the build directory and\n" + " builds it into an .apk file.\n\n" + " Optional arguments:\n" + " --input : Reads for options generated by\n" + " qmake. A default file name based on the current working\n" + " directory will be used if nothing else is specified.\n" + " --deployment : Supported deployment mechanisms:\n" + " bundled (default): Include Qt files in stand-alone package.\n" + " ministro: Use the Ministro service to manage Qt files.\n" + " --no-build: Do not build the package, it is useful to just install\n" + " a package previously built.\n" + " --install: Installs apk to device/emulator. By default this step is\n" + " not taken. If the application has previously been installed on\n" + " the device, it will be uninstalled first.\n" + " --reinstall: Installs apk to device/emulator. By default this step\n" + " is not taken. If the application has previously been installed on\n" + " the device, it will be overwritten, but its data will be left\n" + " intact.\n" + " --device [device ID]: Use specified device for deployment. Default\n" + " is the device selected by default by adb.\n" + " --android-platform : Builds against the given android\n" + " platform. By default, the highest available version will be\n" + " used.\n" + " --gradle. Use gradle instead of ant to create and install the apk.\n" + " --ant : If unspecified, ant from the PATH will be\n" + " used.\n" + " --release: Builds a package ready for release. By default, the\n" + " package will be signed with a debug key.\n" + " --sign : Signs the package with the\n" + " specified keystore, alias and store password. Also implies the\n" + " --release option.\n" + " Optional arguments for use with signing:\n" + " --storepass : Keystore password.\n" + " --storetype : Keystore type.\n" + " --keypass : Password for private key (if different\n" + " from keystore password.)\n" + " --sigfile : Name of .SF/.DSA file.\n" + " --digestalg : Name of digest algorithm. Default is\n" + " \"SHA1\".\n" + " --sigalg : Name of signature algorithm. Default is\n" + " \"SHA1withRSA\".\n" + " --tsa : Location of the Time Stamping Authority.\n" + " --tsacert : Public key certificate for TSA.\n" + " --internalsf: Include the .SF file inside the signature block.\n" + " --sectionsonly: Don't compute hash of entire manifest.\n" + " --protected: Keystore has protected authentication path.\n" + " --jarsigner: Force jarsigner usage, otherwise apksigner will be\n" + " used if available.\n" + " --gdbserver: Adds the gdbserver to the package. By default the gdbserver\n" + " is bundled for debug pacakges.\n" + " --no-gdbserver: Prevents the gdbserver from being added to the package\n" + " By default the gdbserver is bundled for debug pacakges.\n" + " --jdk : Used to find the jarsigner tool when used\n" + " in combination with the --release argument. By default,\n" + " an attempt is made to detect the tool using the JAVA_HOME and\n" + " PATH environment variables, in that order.\n" + " --qml-import-paths: Specify additional search paths for QML\n" + " imports.\n" + " --verbose: Prints out information during processing.\n" + " --no-generated-assets-cache: Do not pregenerate the entry list for\n" + " the assets file engine.\n" + " --help: Displays this information.\n\n", + qPrintable(QCoreApplication::arguments().at(0)) + ); +} + +// Since strings compared will all start with the same letters, +// sorting by length and then alphabetically within each length +// gives the natural order. +bool quasiLexicographicalReverseLessThan(const QFileInfo &fi1, const QFileInfo &fi2) +{ + QString s1 = fi1.baseName(); + QString s2 = fi2.baseName(); + + if (s1.length() == s2.length()) + return s1 > s2; + else + return s1.length() > s2.length(); +} + +// Files which contain templates that need to be overwritten by build data should be overwritten every +// time. +bool alwaysOverwritableFile(const QString &fileName) +{ + return (fileName.endsWith(QLatin1String("/res/values/libs.xml")) + || fileName.endsWith(QLatin1String("/AndroidManifest.xml")) + || fileName.endsWith(QLatin1String("/res/values/strings.xml")) + || fileName.endsWith(QLatin1String("/src/org/qtproject/qt5/android/bindings/QtActivity.java"))); +} + +bool copyFileIfNewer(const QString &sourceFileName, + const QString &destinationFileName, + bool verbose, + bool forceOverwrite = false) +{ + if (QFile::exists(destinationFileName)) { + QFileInfo destinationFileInfo(destinationFileName); + QFileInfo sourceFileInfo(sourceFileName); + + if (!forceOverwrite + && sourceFileInfo.lastModified() <= destinationFileInfo.lastModified() + && !alwaysOverwritableFile(destinationFileName)) { + if (verbose) + fprintf(stdout, " -- Skipping file %s. Same or newer file already in place.\n", qPrintable(sourceFileName)); + return true; + } else { + if (!QFile(destinationFileName).remove()) { + fprintf(stderr, "Can't remove old file: %s\n", qPrintable(destinationFileName)); + return false; + } + } + } + + if (!QDir().mkpath(QFileInfo(destinationFileName).path())) { + fprintf(stderr, "Cannot make output directory for %s.\n", qPrintable(destinationFileName)); + return false; + } + + if (!QFile::exists(destinationFileName) && !QFile::copy(sourceFileName, destinationFileName)) { + fprintf(stderr, "Failed to copy %s to %s.\n", qPrintable(sourceFileName), qPrintable(destinationFileName)); + return false; + } else if (verbose) { + fprintf(stdout, " -- Copied %s\n", qPrintable(destinationFileName)); + fflush(stdout); + } + + return true; +} + +QString cleanPackageName(QString packageName) +{ + QRegExp legalChars(QLatin1String("[a-zA-Z0-9_\\.]")); + + for (int i = 0; i < packageName.length(); ++i) { + if (!legalChars.exactMatch(packageName.mid(i, 1))) + packageName[i] = QLatin1Char('_'); + } + + static QStringList keywords; + if (keywords.isEmpty()) { + keywords << QLatin1String("abstract") << QLatin1String("continue") << QLatin1String("for") + << QLatin1String("new") << QLatin1String("switch") << QLatin1String("assert") + << QLatin1String("default") << QLatin1String("if") << QLatin1String("package") + << QLatin1String("synchronized") << QLatin1String("boolean") << QLatin1String("do") + << QLatin1String("goto") << QLatin1String("private") << QLatin1String("this") + << QLatin1String("break") << QLatin1String("double") << QLatin1String("implements") + << QLatin1String("protected") << QLatin1String("throw") << QLatin1String("byte") + << QLatin1String("else") << QLatin1String("import") << QLatin1String("public") + << QLatin1String("throws") << QLatin1String("case") << QLatin1String("enum") + << QLatin1String("instanceof") << QLatin1String("return") << QLatin1String("transient") + << QLatin1String("catch") << QLatin1String("extends") << QLatin1String("int") + << QLatin1String("short") << QLatin1String("try") << QLatin1String("char") + << QLatin1String("final") << QLatin1String("interface") << QLatin1String("static") + << QLatin1String("void") << QLatin1String("class") << QLatin1String("finally") + << QLatin1String("long") << QLatin1String("strictfp") << QLatin1String("volatile") + << QLatin1String("const") << QLatin1String("float") << QLatin1String("native") + << QLatin1String("super") << QLatin1String("while"); + } + + // No keywords + int index = -1; + while (index < packageName.length()) { + int next = packageName.indexOf(QLatin1Char('.'), index + 1); + if (next == -1) + next = packageName.length(); + QString word = packageName.mid(index + 1, next - index - 1); + if (!word.isEmpty()) { + QChar c = word[0]; + if ((c >= QChar(QLatin1Char('0')) && c<= QChar(QLatin1Char('9'))) + || c == QLatin1Char('_')) { + packageName.insert(index + 1, QLatin1Char('a')); + index = next + 1; + continue; + } + } + if (keywords.contains(word)) { + packageName.insert(next, QLatin1String("_")); + index = next + 1; + } else { + index = next; + } + } + + return packageName; +} + +QString detectLatestAndroidPlatform(const QString &sdkPath) +{ + QDir dir(sdkPath + QLatin1String("/platforms")); + if (!dir.exists()) { + fprintf(stderr, "Directory %s does not exist\n", qPrintable(dir.absolutePath())); + return QString(); + } + + QFileInfoList fileInfos = dir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot); + if (fileInfos.isEmpty()) { + fprintf(stderr, "No platforms found in %s", qPrintable(dir.absolutePath())); + return QString(); + } + + std::sort(fileInfos.begin(), fileInfos.end(), quasiLexicographicalReverseLessThan); + + QFileInfo latestPlatform = fileInfos.first(); + return latestPlatform.baseName(); +} + +QString packageNameFromAndroidManifest(const QString &androidManifestPath) +{ + QFile androidManifestXml(androidManifestPath); + if (androidManifestXml.open(QIODevice::ReadOnly)) { + QXmlStreamReader reader(&androidManifestXml); + while (!reader.atEnd()) { + reader.readNext(); + if (reader.isStartElement() && reader.name() == QLatin1String("manifest")) + return cleanPackageName( + reader.attributes().value(QLatin1String("package")).toString()); + } + } + return QString(); +} + +bool readInputFile(Options *options) +{ + QFile file(options->inputFileName); + if (!file.open(QIODevice::ReadOnly)) { + fprintf(stderr, "Cannot read from input file: %s\n", qPrintable(options->inputFileName)); + return false; + } + + QJsonDocument jsonDocument = QJsonDocument::fromJson(file.readAll()); + if (jsonDocument.isNull()) { + fprintf(stderr, "Invalid json file: %s\n", qPrintable(options->inputFileName)); + return false; + } + + QJsonObject jsonObject = jsonDocument.object(); + + { + QJsonValue sdkPath = jsonObject.value(QLatin1String("sdk")); + if (sdkPath.isUndefined()) { + fprintf(stderr, "No SDK path in json file %s\n", qPrintable(options->inputFileName)); + return false; + } + + options->sdkPath = sdkPath.toString(); + + if (options->androidPlatform.isEmpty()) { + options->androidPlatform = detectLatestAndroidPlatform(options->sdkPath); + if (options->androidPlatform.isEmpty()) + return false; + } else { + if (!QDir(options->sdkPath + QLatin1String("/platforms/") + options->androidPlatform).exists()) { + fprintf(stderr, "Warning: Android platform '%s' does not exist in SDK.\n", + qPrintable(options->androidPlatform)); + } + } + } + + { + + const QJsonValue value = jsonObject.value(QStringLiteral("sdkBuildToolsRevision")); + if (!value.isUndefined()) + options->sdkBuildToolsVersion = value.toString(); + } + + { + const QJsonValue qtInstallDirectory = jsonObject.value(QStringLiteral("qt")); + if (qtInstallDirectory.isUndefined()) { + fprintf(stderr, "No Qt directory in json file %s\n", qPrintable(options->inputFileName)); + return false; + } + options->qtInstallDirectory = qtInstallDirectory.toString(); + } + + { + const QJsonValue androidSourcesDirectory = jsonObject.value(QStringLiteral("android-package-source-directory")); + if (!androidSourcesDirectory.isUndefined()) + options->androidSourceDirectory = androidSourcesDirectory.toString(); + } + + { + const QJsonValue applicationBinary = jsonObject.value(QStringLiteral("application-binary")); + if (applicationBinary.isUndefined()) { + fprintf(stderr, "No application binary defined in json file.\n"); + return false; + } + options->applicationBinary = applicationBinary.toString(); + + if (!QFile::exists(options->applicationBinary)) { + fprintf(stderr, "Cannot find application binary %s.\n", qPrintable(options->applicationBinary)); + return false; + } + } + + { + const QJsonValue deploymentDependencies = jsonObject.value(QStringLiteral("deployment-dependencies")); + if (!deploymentDependencies.isUndefined()) { + QString deploymentDependenciesString = deploymentDependencies.toString(); + const auto dependencies = deploymentDependenciesString.splitRef(QLatin1Char(',')); + for (const QStringRef &dependency : dependencies) { + QString path = options->qtInstallDirectory + QLatin1Char('/') + dependency; + if (QFileInfo(path).isDir()) { + QDirIterator iterator(path, QDirIterator::Subdirectories); + while (iterator.hasNext()) { + iterator.next(); + if (iterator.fileInfo().isFile()) { + QString subPath = iterator.filePath(); + options->qtDependencies.append(QtDependency(subPath.mid(options->qtInstallDirectory.length() + 1), + subPath)); + } + } + } else { + options->qtDependencies.append(QtDependency(dependency.toString(), path)); + } + } + } + } + + + { + const QJsonValue targetArchitecture = jsonObject.value(QStringLiteral("target-architecture")); + if (targetArchitecture.isUndefined()) { + fprintf(stderr, "No target architecture defined in json file.\n"); + return false; + } + options->architecture = targetArchitecture.toString(); + } + + { + const QJsonValue ndk = jsonObject.value(QStringLiteral("ndk")); + if (ndk.isUndefined()) { + fprintf(stderr, "No NDK path defined in json file.\n"); + return false; + } + options->ndkPath = ndk.toString(); + } + + { + const QJsonValue toolchainPrefix = jsonObject.value(QStringLiteral("toolchain-prefix")); + if (toolchainPrefix.isUndefined()) { + fprintf(stderr, "No toolchain prefix defined in json file.\n"); + return false; + } + options->toolchainPrefix = toolchainPrefix.toString(); + } + + { + const QJsonValue toolPrefix = jsonObject.value(QStringLiteral("tool-prefix")); + if (toolPrefix.isUndefined()) { + fprintf(stderr, "Warning: No tool prefix defined in json file.\n"); + options->toolPrefix = options->toolchainPrefix; + } else { + options->toolPrefix = toolPrefix.toString(); + } + } + + { + const QJsonValue toolchainVersion = jsonObject.value(QStringLiteral("toolchain-version")); + if (toolchainVersion.isUndefined()) { + fprintf(stderr, "No toolchain version defined in json file.\n"); + return false; + } + options->toolchainVersion = toolchainVersion.toString(); + } + + { + const QJsonValue ndkHost = jsonObject.value(QStringLiteral("ndk-host")); + if (ndkHost.isUndefined()) { + fprintf(stderr, "No NDK host defined in json file.\n"); + return false; + } + options->ndkHost = ndkHost.toString(); + } + + options->packageName = packageNameFromAndroidManifest(options->androidSourceDirectory + QLatin1String("/AndroidManifest.xml")); + if (options->packageName.isEmpty()) + options->packageName = cleanPackageName(QString::fromLatin1("org.qtproject.example.%1").arg(QFileInfo(options->applicationBinary).baseName().mid(sizeof("lib") - 1))); + + { + const QJsonValue extraLibs = jsonObject.value(QStringLiteral("android-extra-libs")); + if (!extraLibs.isUndefined()) + options->extraLibs = extraLibs.toString().split(QLatin1Char(','), QString::SkipEmptyParts); + } + + { + const QJsonValue extraPlugins = jsonObject.value(QStringLiteral("android-extra-plugins")); + if (!extraPlugins.isUndefined()) + options->extraPlugins = extraPlugins.toString().split(QLatin1Char(',')); + } + + { + const QJsonValue stdcppPath = jsonObject.value(QStringLiteral("stdcpp-path")); + if (!stdcppPath.isUndefined()) { + options->stdCppPath = stdcppPath.toString(); + auto name = QFileInfo(options->stdCppPath).baseName(); + if (!name.startsWith(QLatin1String("lib"))) { + fprintf(stderr, "Invalid STD C++ library name.\n"); + return false; + } + options->stdCppName = name.mid(3); + } + } + + { + const QJsonValue qmlRootPath = jsonObject.value(QStringLiteral("qml-root-path")); + if (!qmlRootPath.isUndefined()) + options->rootPath = qmlRootPath.toString(); + } + + { + const QJsonValue qmlImportPaths = jsonObject.value(QStringLiteral("qml-import-paths")); + if (!qmlImportPaths.isUndefined()) + options->qmlImportPaths = qmlImportPaths.toString().split(QLatin1Char(',')); + } + return true; +} + +bool copyFiles(const QDir &sourceDirectory, const QDir &destinationDirectory, bool verbose, bool forceOverwrite = false) +{ + const QFileInfoList entries = sourceDirectory.entryInfoList(QDir::NoDotAndDotDot | QDir::Files | QDir::Dirs); + for (const QFileInfo &entry : entries) { + if (entry.isDir()) { + QDir dir(entry.absoluteFilePath()); + if (!destinationDirectory.mkpath(dir.dirName())) { + fprintf(stderr, "Cannot make directory %s in %s\n", qPrintable(dir.dirName()), qPrintable(destinationDirectory.path())); + return false; + } + + if (!copyFiles(dir, QDir(destinationDirectory.path() + QLatin1String("/") + dir.dirName()), verbose, forceOverwrite)) + return false; + } else { + QString destination = destinationDirectory.absoluteFilePath(entry.fileName()); + if (!copyFileIfNewer(entry.absoluteFilePath(), destination, verbose, forceOverwrite)) + return false; + } + } + + return true; +} + +void cleanTopFolders(const Options &options, const QDir &srcDir, const QString &dstDir) +{ + const auto dirs = srcDir.entryInfoList(QDir::NoDotAndDotDot | QDir::Dirs); + for (const QFileInfo &dir : dirs) { + if (dir.fileName() != QLatin1String("libs")) + deleteMissingFiles(options, dir.absoluteFilePath(), dstDir + dir.fileName()); + } +} + +void cleanAndroidFiles(const Options &options) +{ + if (!options.androidSourceDirectory.isEmpty()) + cleanTopFolders(options, options.androidSourceDirectory, options.outputDirectory); + + cleanTopFolders(options, options.qtInstallDirectory + QLatin1String("/src/android/templates"), options.outputDirectory); +} + +bool copyAndroidTemplate(const Options &options, const QString &androidTemplate, const QString &outDirPrefix = QString()) +{ + QDir sourceDirectory(options.qtInstallDirectory + androidTemplate); + if (!sourceDirectory.exists()) { + fprintf(stderr, "Cannot find template directory %s\n", qPrintable(sourceDirectory.absolutePath())); + return false; + } + + QString outDir = options.outputDirectory + outDirPrefix; + + if (!QDir::current().mkpath(outDir)) { + fprintf(stderr, "Cannot create output directory %s\n", qPrintable(options.outputDirectory)); + return false; + } + + return copyFiles(sourceDirectory, QDir(outDir), options.verbose); +} + +bool copyGradleTemplate(const Options &options) +{ + QDir sourceDirectory(options.qtInstallDirectory + QLatin1String("/src/3rdparty/gradle")); + if (!sourceDirectory.exists()) { + fprintf(stderr, "Cannot find template directory %s\n", qPrintable(sourceDirectory.absolutePath())); + return false; + } + + QString outDir(options.outputDirectory); + if (!QDir::current().mkpath(outDir)) { + fprintf(stderr, "Cannot create output directory %s\n", qPrintable(options.outputDirectory)); + return false; + } + + return copyFiles(sourceDirectory, QDir(outDir), options.verbose); +} + +bool copyAndroidTemplate(const Options &options) +{ + if (options.verbose) + fprintf(stdout, "Copying Android package template.\n"); + + if (options.gradle && !copyGradleTemplate(options)) + return false; + + if (!copyAndroidTemplate(options, QLatin1String("/src/android/templates"))) + return false; + + if (options.gradle) + return true; + + return copyAndroidTemplate(options, QLatin1String("/src/android/java")); +} + +bool copyAndroidSources(const Options &options) +{ + if (options.androidSourceDirectory.isEmpty()) + return true; + + if (options.verbose) + fprintf(stdout, "Copying Android sources from project.\n"); + + QDir sourceDirectory(options.androidSourceDirectory); + if (!sourceDirectory.exists()) { + fprintf(stderr, "Cannot find android sources in %s", qPrintable(options.androidSourceDirectory)); + return false; + } + + return copyFiles(sourceDirectory, QDir(options.outputDirectory), options.verbose, true); +} + +bool copyAndroidExtraLibs(const Options &options) +{ + if (options.extraLibs.isEmpty()) + return true; + + if (options.verbose) + fprintf(stdout, "Copying %d external libraries to package.\n", options.extraLibs.size()); + + for (const QString &extraLib : options.extraLibs) { + QFileInfo extraLibInfo(extraLib); + if (!extraLibInfo.exists()) { + fprintf(stderr, "External library %s does not exist!\n", qPrintable(extraLib)); + return false; + } + + if (!extraLibInfo.fileName().startsWith(QLatin1String("lib")) || extraLibInfo.suffix() != QLatin1String("so")) { + fprintf(stderr, "The file name of external library %s must begin with \"lib\" and end with the suffix \".so\".\n", + qPrintable(extraLib)); + return false; + } + + QString destinationFile(options.outputDirectory + + QLatin1String("/libs/") + + options.architecture + + QLatin1Char('/') + + extraLibInfo.fileName()); + + if (!copyFileIfNewer(extraLib, destinationFile, options.verbose)) + return false; + } + + return true; +} + +QStringList allFilesInside(const QDir& current, const QDir& rootDir) +{ + QStringList result; + const auto dirs = current.entryList(QDir::Dirs|QDir::NoDotAndDotDot); + const auto files = current.entryList(QDir::Files); + result.reserve(dirs.size() + files.size()); + for (const QString &dir : dirs) { + result += allFilesInside(QDir(current.filePath(dir)), rootDir); + } + for (const QString &file : files) { + result += rootDir.relativeFilePath(current.filePath(file)); + } + return result; +} + +bool copyAndroidExtraResources(const Options &options) +{ + if (options.extraPlugins.isEmpty()) + return true; + + if (options.verbose) + fprintf(stdout, "Copying %d external resources to package.\n", options.extraPlugins.size()); + + for (const QString &extraResource : options.extraPlugins) { + QFileInfo extraResourceInfo(extraResource); + if (!extraResourceInfo.exists() || !extraResourceInfo.isDir()) { + fprintf(stderr, "External resource %s does not exist or not a correct directory!\n", qPrintable(extraResource)); + return false; + } + + QDir resourceDir(extraResource); + QString assetsDir = options.outputDirectory + QStringLiteral("/assets/") + resourceDir.dirName() + QLatin1Char('/'); + QString libsDir = options.outputDirectory + QStringLiteral("/libs/") + options.architecture + QLatin1Char('/'); + + const QStringList files = allFilesInside(resourceDir, resourceDir); + for (const QString &resourceFile : files) { + QString originFile(resourceDir.filePath(resourceFile)); + QString destinationFile; + if (!resourceFile.endsWith(QLatin1String(".so"))) { + destinationFile = assetsDir + resourceFile; + } else { + destinationFile = libsDir + QStringLiteral("/lib") + QString(resourceDir.dirName() + QLatin1Char('/') + resourceFile).replace(QLatin1Char('/'), QLatin1Char('_')); + } + + if (!copyFileIfNewer(originFile, destinationFile, options.verbose)) + return false; + } + } + + return true; +} + +bool updateFile(const QString &fileName, const QHash &replacements) +{ + QFile inputFile(fileName); + if (!inputFile.open(QIODevice::ReadOnly)) { + fprintf(stderr, "Cannot open %s for reading.\n", qPrintable(fileName)); + return false; + } + + // All the files we are doing substitutes in are quite small. If this + // ever changes, this code should be updated to be more conservative. + QByteArray contents = inputFile.readAll(); + + bool hasReplacements = false; + QHash::const_iterator it; + for (it = replacements.constBegin(); it != replacements.constEnd(); ++it) { + if (it.key() == it.value()) + continue; // Nothing to actually replace + + forever { + int index = contents.indexOf(it.key().toUtf8()); + if (index >= 0) { + contents.replace(index, it.key().length(), it.value().toUtf8()); + hasReplacements = true; + } else { + break; + } + } + } + + if (hasReplacements) { + inputFile.close(); + + if (!inputFile.open(QIODevice::WriteOnly)) { + fprintf(stderr, "Cannot open %s for writing.\n", qPrintable(fileName)); + return false; + } + + inputFile.write(contents); + } + + return true; + +} + +bool updateLibsXml(const Options &options) +{ + if (options.verbose) + fprintf(stdout, " -- res/values/libs.xml\n"); + + QString fileName = options.outputDirectory + QLatin1String("/res/values/libs.xml"); + if (!QFile::exists(fileName)) { + fprintf(stderr, "Cannot find %s in prepared packaged. This file is required.\n", qPrintable(fileName)); + return false; + } + + QString libsPath = QLatin1String("libs/") + options.architecture + QLatin1Char('/'); + + QString qtLibs = QLatin1String("") + options.stdCppName + QLatin1String("\n"); + QString bundledInLibs; + QString bundledInAssets; + for (const Options::BundledFile &bundledFile : options.bundledFiles) { + if (bundledFile.second.startsWith(QLatin1String("lib/"))) { + QString s = bundledFile.second.mid(sizeof("lib/lib") - 1); + s.chop(sizeof(".so") - 1); + qtLibs += QString::fromLatin1("%1\n").arg(s); + } else if (bundledFile.first.startsWith(libsPath)) { + QString s = bundledFile.first.mid(libsPath.length()); + bundledInLibs += QString::fromLatin1("%1:%2\n") + .arg(s).arg(bundledFile.second); + } else if (bundledFile.first.startsWith(QLatin1String("assets/"))) { + QString s = bundledFile.first.mid(sizeof("assets/") - 1); + bundledInAssets += QString::fromLatin1("%1:%2\n") + .arg(s).arg(bundledFile.second); + } + } + + if (!options.extraPlugins.isEmpty()) { + for (const QString &extraRes : options.extraPlugins) { + QDir resourceDir(extraRes); + const QStringList files = allFilesInside(resourceDir, resourceDir); + for (const QString &file : files) { + QString destinationPath = resourceDir.dirName() + QLatin1Char('/') + file; + if (!file.endsWith(QLatin1String(".so"))) { + bundledInAssets += QStringLiteral("%1:%1\n") + .arg(destinationPath); + } else { + bundledInLibs += QStringLiteral("lib%1:%2\n") + .arg(QString(destinationPath).replace(QLatin1Char('/'), QLatin1Char('_'))) + .arg(destinationPath); + } + } + } + } + + QHash replacements; + replacements[QLatin1String("")] = qtLibs; + + if (options.deploymentMechanism == Options::Bundled) { + replacements[QLatin1String("")] = bundledInLibs; + replacements[QLatin1String("")] = bundledInAssets; + } + + QString extraLibs; + if (!options.extraLibs.isEmpty()) { + for (const QString extraLib : options.extraLibs) { + QFileInfo extraLibInfo(extraLib); + QString name = extraLibInfo.fileName().mid(sizeof("lib") - 1); + name.chop(sizeof(".so") - 1); + + extraLibs += QLatin1String("") + name + QLatin1String("\n"); + } + } + replacements[QLatin1String("")] = extraLibs; + + if (!updateFile(fileName, replacements)) + return false; + + return true; +} + +bool updateStringsXml(const Options &options) +{ + if (options.verbose) + fprintf(stdout, " -- res/values/strings.xml\n"); + + QHash replacements; + replacements[QStringLiteral("")] = QFileInfo(options.applicationBinary).baseName().mid(sizeof("lib") - 1); + + QString fileName = options.outputDirectory + QLatin1String("/res/values/strings.xml"); + if (!QFile::exists(fileName)) { + if (options.verbose) + fprintf(stdout, " -- Create strings.xml since it's missing.\n"); + QFile file(fileName); + if (!file.open(QIODevice::WriteOnly)) { + fprintf(stderr, "Can't open %s for writing.\n", qPrintable(fileName)); + return false; + } + file.write(QByteArray("") + .append(QFileInfo(options.applicationBinary).baseName().mid(sizeof("lib") - 1).toLatin1()) + .append("\n")); + return true; + } + + if (!updateFile(fileName, replacements)) + return false; + + if (options.gradle) + return true; + + // ant can't (easily) build multiple res folders, + // so we need to replace the "" placeholder + // from the main res folder + QFile stringsXml(fileName); + if (!stringsXml.open(QIODevice::ReadOnly)) { + fprintf(stderr, "Cannot open %s for reading.\n", qPrintable(fileName)); + return false; + } + + QXmlStreamReader reader(&stringsXml); + while (!reader.atEnd()) { + reader.readNext(); + if (reader.isStartElement() && + reader.name() == QLatin1String("string") && + reader.attributes().hasAttribute(QLatin1String("name")) && + reader.attributes().value(QLatin1String("name")) == QLatin1String("app_name")) { + return true; + } + } + + replacements.clear(); + replacements[QStringLiteral("")] = QString::fromLatin1("%1\n") + .arg(QFileInfo(options.applicationBinary).baseName().mid(sizeof("lib") - 1)); + + if (!updateFile(fileName, replacements)) + return false; + + return true; +} + +bool updateAndroidManifest(Options &options) +{ + if (options.verbose) + fprintf(stdout, " -- AndroidManifest.xml \n"); + + QStringList localLibs = options.localLibs; + + // If .pro file overrides dependency detection, we need to see which platform plugin they picked + if (localLibs.isEmpty()) { + QString plugin; + for (const QtDependency &qtDependency : qAsConst(options.qtDependencies)) { + if (qtDependency.relativePath.endsWith(QLatin1String("libqtforandroid.so")) + || qtDependency.relativePath.endsWith(QLatin1String("libqtforandroidGL.so"))) { + if (!plugin.isEmpty() && plugin != qtDependency.relativePath) { + fprintf(stderr, "Both platform plugins libqtforandroid.so and libqtforandroidGL.so included in package. Please include only one.\n"); + return false; + } + + plugin = qtDependency.relativePath; + } + } + + if (plugin.isEmpty()) { + fprintf(stderr, "No platform plugin, neither libqtforandroid.so or libqtforandroidGL.so, included in package. Please include one.\n"); + return false; + } + + localLibs.append(plugin); + if (options.verbose) + fprintf(stdout, " -- Using platform plugin %s\n", qPrintable(plugin)); + } + + bool usesGL = false; + for (const QtDependency &qtDependency : qAsConst(options.qtDependencies)) { + if (qtDependency.relativePath.endsWith(QLatin1String("libQt5OpenGL.so")) + || qtDependency.relativePath.endsWith(QLatin1String("libQt5Quick.so"))) { + usesGL = true; + break; + } + } + + options.localJars.removeDuplicates(); + options.initClasses.removeDuplicates(); + + QHash replacements; + replacements[QLatin1String("-- %%INSERT_APP_NAME%% --")] = QFileInfo(options.applicationBinary).baseName().mid(sizeof("lib") - 1); + replacements[QLatin1String("-- %%INSERT_APP_LIB_NAME%% --")] = QFileInfo(options.applicationBinary).baseName().mid(sizeof("lib") - 1); + replacements[QLatin1String("-- %%INSERT_LOCAL_LIBS%% --")] = localLibs.join(QLatin1Char(':')); + replacements[QLatin1String("-- %%INSERT_LOCAL_JARS%% --")] = options.localJars.join(QLatin1Char(':')); + replacements[QLatin1String("-- %%INSERT_INIT_CLASSES%% --")] = options.initClasses.join(QLatin1Char(':')); + replacements[QLatin1String("package=\"org.qtproject.example\"")] = QString::fromLatin1("package=\"%1\"").arg(options.packageName); + replacements[QLatin1String("-- %%BUNDLE_LOCAL_QT_LIBS%% --")] + = (options.deploymentMechanism == Options::Bundled) ? QString::fromLatin1("1") : QString::fromLatin1("0"); + replacements[QLatin1String("-- %%USE_LOCAL_QT_LIBS%% --")] + = (options.deploymentMechanism != Options::Ministro) ? QString::fromLatin1("1") : QString::fromLatin1("0"); + + QString permissions; + for (const QString &permission : qAsConst(options.permissions)) + permissions += QString::fromLatin1(" \n").arg(permission); + replacements[QLatin1String("")] = permissions; + + QString features; + for (const QString &feature : qAsConst(options.features)) + features += QStringLiteral(" \n").arg(feature); + if (usesGL) + features += QStringLiteral(" "); + + replacements[QLatin1String("")] = features; + + QString androidManifestPath = options.outputDirectory + QLatin1String("/AndroidManifest.xml"); + if (!updateFile(androidManifestPath, replacements)) + return false; + + // read the package, min & target sdk API levels from manifest file. + bool checkOldAndroidLabelString = false; + QFile androidManifestXml(androidManifestPath); + if (androidManifestXml.exists()) { + if (!androidManifestXml.open(QIODevice::ReadOnly)) { + fprintf(stderr, "Cannot open %s for reading.\n", qPrintable(androidManifestPath)); + return false; + } + + QXmlStreamReader reader(&androidManifestXml); + while (!reader.atEnd()) { + reader.readNext(); + + if (reader.isStartElement()) { + if (reader.name() == QLatin1String("manifest")) { + if (!reader.attributes().hasAttribute(QLatin1String("package"))) { + fprintf(stderr, "Invalid android manifest file: %s\n", qPrintable(androidManifestPath)); + return false; + } + options.packageName = reader.attributes().value(QLatin1String("package")).toString(); + } else if (reader.name() == QLatin1String("uses-sdk")) { + if (reader.attributes().hasAttribute(QLatin1String("android:minSdkVersion"))) + if (reader.attributes().value(QLatin1String("android:minSdkVersion")).toInt() < 16) { + fprintf(stderr, "Invalid minSdkVersion version, minSdkVersion must be >= 16\n"); + return false; + } + } else if ((reader.name() == QLatin1String("application") || + reader.name() == QLatin1String("activity")) && + reader.attributes().hasAttribute(QLatin1String("android:label")) && + reader.attributes().value(QLatin1String("android:label")) == QLatin1String("@string/app_name")) { + checkOldAndroidLabelString = true; + } + } + } + + if (reader.hasError()) { + fprintf(stderr, "Error in %s: %s\n", qPrintable(androidManifestPath), qPrintable(reader.errorString())); + return false; + } + } else { + fprintf(stderr, "No android manifest file"); + return false; + } + + if (checkOldAndroidLabelString) + updateStringsXml(options); + + return true; +} + +bool updateAndroidFiles(Options &options) +{ + if (options.verbose) + fprintf(stdout, "Updating Android package files with project settings.\n"); + + if (!updateLibsXml(options)) + return false; + + if (!updateAndroidManifest(options)) + return false; + + return true; +} + +QList findFilesRecursively(const Options &options, const QFileInfo &info, const QString &rootPath) +{ + if (!info.exists()) + return QList(); + + if (info.isDir()) { + QList ret; + + QDir dir(info.filePath()); + const QStringList entries = dir.entryList(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot); + + for (const QString &entry : entries) { + QString s = info.absoluteFilePath() + QLatin1Char('/') + entry; + ret += findFilesRecursively(options, s, rootPath); + } + + return ret; + } else { + return QList() << QtDependency(info.absoluteFilePath().mid(rootPath.length()), info.absoluteFilePath()); + } +} + +QList findFilesRecursively(const Options &options, const QString &fileName) +{ + QFileInfo info(options.qtInstallDirectory + QLatin1Char('/') + fileName); + return findFilesRecursively(options, info, options.qtInstallDirectory + QLatin1Char('/')); +} + +bool readAndroidDependencyXml(Options *options, + const QString &moduleName, + QSet *usedDependencies, + QSet *remainingDependencies) +{ + QString androidDependencyName = options->qtInstallDirectory + QString::fromLatin1("/lib/%1-android-dependencies.xml").arg(moduleName); + + QFile androidDependencyFile(androidDependencyName); + if (androidDependencyFile.exists()) { + if (options->verbose) + fprintf(stdout, "Reading Android dependencies for %s\n", qPrintable(moduleName)); + + if (!androidDependencyFile.open(QIODevice::ReadOnly)) { + fprintf(stderr, "Cannot open %s for reading.\n", qPrintable(androidDependencyName)); + return false; + } + + QXmlStreamReader reader(&androidDependencyFile); + while (!reader.atEnd()) { + reader.readNext(); + + if (reader.isStartElement()) { + if (reader.name() == QLatin1String("bundled")) { + if (!reader.attributes().hasAttribute(QLatin1String("file"))) { + fprintf(stderr, "Invalid android dependency file: %s\n", qPrintable(androidDependencyName)); + return false; + } + + QString file = reader.attributes().value(QLatin1String("file")).toString(); + + // Special case, since this is handled by qmlimportscanner instead + if (!options->rootPath.isEmpty() && (file == QLatin1String("qml") || file == QLatin1String("qml/"))) + continue; + + const QList fileNames = findFilesRecursively(*options, file); + for (const QtDependency &fileName : fileNames) { + if (usedDependencies->contains(fileName.absolutePath)) + continue; + + usedDependencies->insert(fileName.absolutePath); + + if (options->verbose) + fprintf(stdout, "Appending dependency from xml: %s\n", qPrintable(fileName.relativePath)); + + options->qtDependencies.append(fileName); + } + } else if (reader.name() == QLatin1String("jar")) { + int bundling = reader.attributes().value(QLatin1String("bundling")).toInt(); + QString fileName = reader.attributes().value(QLatin1String("file")).toString(); + if (bundling == (options->deploymentMechanism == Options::Bundled)) { + QtDependency dependency(fileName, options->qtInstallDirectory + QLatin1Char('/') + fileName); + if (!usedDependencies->contains(dependency.absolutePath)) { + options->qtDependencies.append(dependency); + usedDependencies->insert(dependency.absolutePath); + } + } + + if (!fileName.isEmpty()) + options->localJars.append(fileName); + + if (reader.attributes().hasAttribute(QLatin1String("initClass"))) { + options->initClasses.append(reader.attributes().value(QLatin1String("initClass")).toString()); + } + } else if (reader.name() == QLatin1String("lib")) { + QString fileName = reader.attributes().value(QLatin1String("file")).toString(); + if (reader.attributes().hasAttribute(QLatin1String("replaces"))) { + QString replaces = reader.attributes().value(QLatin1String("replaces")).toString(); + for (int i=0; ilocalLibs.size(); ++i) { + if (options->localLibs.at(i) == replaces) { + options->localLibs[i] = fileName; + break; + } + } + } else if (!fileName.isEmpty()) { + options->localLibs.append(fileName); + } + if (fileName.endsWith(QLatin1String(".so"))) { + remainingDependencies->insert(fileName); + } + } else if (reader.name() == QLatin1String("permission")) { + QString name = reader.attributes().value(QLatin1String("name")).toString(); + options->permissions.append(name); + } else if (reader.name() == QLatin1String("feature")) { + QString name = reader.attributes().value(QLatin1String("name")).toString(); + options->features.append(name); + } + } + } + + if (reader.hasError()) { + fprintf(stderr, "Error in %s: %s\n", qPrintable(androidDependencyName), qPrintable(reader.errorString())); + return false; + } + } else if (options->verbose) { + fprintf(stdout, "No android dependencies for %s\n", qPrintable(moduleName)); + } + + return true; +} + +QStringList getQtLibsFromElf(const Options &options, const QString &fileName) +{ + QString readElf = options.ndkPath + + QLatin1String("/toolchains/") + + options.toolchainPrefix + + QLatin1Char('-') + + options.toolchainVersion + + QLatin1String("/prebuilt/") + + options.ndkHost + + QLatin1String("/bin/") + + options.toolPrefix + + QLatin1String("-readelf"); +#if defined(Q_OS_WIN32) + readElf += QLatin1String(".exe"); +#endif + + if (!QFile::exists(readElf)) { + fprintf(stderr, "Command does not exist: %s\n", qPrintable(readElf)); + return QStringList(); + } + + readElf = QString::fromLatin1("%1 -d -W %2").arg(shellQuote(readElf)).arg(shellQuote(fileName)); + + FILE *readElfCommand = openProcess(readElf); + if (readElfCommand == 0) { + fprintf(stderr, "Cannot execute command %s", qPrintable(readElf)); + return QStringList(); + } + + QStringList ret; + + char buffer[512]; + while (fgets(buffer, sizeof(buffer), readElfCommand) != 0) { + QByteArray line = QByteArray::fromRawData(buffer, qstrlen(buffer)); + if (line.contains("(NEEDED)") && line.contains("Shared library:") ) { + const int pos = line.lastIndexOf('[') + 1; + QString libraryName = QLatin1String("lib/") + QString::fromLatin1(line.mid(pos, line.length() - pos - 2)); + if (QFile::exists(options.qtInstallDirectory + QLatin1Char('/') + libraryName)) { + ret += libraryName; + } + + } + } + + pclose(readElfCommand); + + return ret; +} + +bool readDependenciesFromElf(Options *options, + const QString &fileName, + QSet *usedDependencies, + QSet *remainingDependencies) +{ + // Get dependencies on libraries in $QTDIR/lib + const QStringList dependencies = getQtLibsFromElf(*options, fileName); + + if (options->verbose) { + fprintf(stdout, "Reading dependencies from %s\n", qPrintable(fileName)); + for (const QString &dep : dependencies) + fprintf(stdout, " %s\n", qPrintable(dep)); + } + // Recursively add dependencies from ELF and supplementary XML information + QList dependenciesToCheck; + for (const QString &dependency : dependencies) { + if (usedDependencies->contains(dependency)) + continue; + + QString absoluteDependencyPath(options->qtInstallDirectory + QLatin1Char('/') + dependency); + usedDependencies->insert(dependency); + if (!readDependenciesFromElf(options, + absoluteDependencyPath, + usedDependencies, + remainingDependencies)) { + return false; + } + + options->qtDependencies.append(QtDependency(dependency, absoluteDependencyPath)); + if (options->verbose) + fprintf(stdout, "Appending dependency: %s\n", qPrintable(dependency)); + dependenciesToCheck.append(dependency); + } + + for (const QString &dependency : qAsConst(dependenciesToCheck)) { + QString qtBaseName = dependency.mid(sizeof("lib/lib") - 1); + qtBaseName = qtBaseName.left(qtBaseName.size() - (sizeof(".so") - 1)); + if (!readAndroidDependencyXml(options, qtBaseName, usedDependencies, remainingDependencies)) { + return false; + } + } + + return true; +} + +bool goodToCopy(const Options *options, const QString &file, QStringList *unmetDependencies); + +bool scanImports(Options *options, QSet *usedDependencies) +{ + if (options->verbose) + fprintf(stdout, "Scanning for QML imports.\n"); + + QString qmlImportScanner = options->qtInstallDirectory + QLatin1String("/bin/qmlimportscanner"); +#if defined(Q_OS_WIN32) + qmlImportScanner += QLatin1String(".exe"); +#endif + + if (!QFile::exists(qmlImportScanner)) { + fprintf(stderr, "qmlimportscanner not found: %s\n", qPrintable(qmlImportScanner)); + return true; + } + + QString rootPath = options->rootPath; + if (rootPath.isEmpty()) + rootPath = QFileInfo(options->inputFileName).absolutePath(); + else + rootPath = QFileInfo(rootPath).absoluteFilePath(); + + if (!rootPath.endsWith(QLatin1Char('/'))) + rootPath += QLatin1Char('/'); + + QStringList importPaths; + importPaths += shellQuote(options->qtInstallDirectory + QLatin1String("/qml")); + importPaths += rootPath; + for (const QString &qmlImportPath : qAsConst(options->qmlImportPaths)) + importPaths += shellQuote(qmlImportPath); + + qmlImportScanner += QString::fromLatin1(" -rootPath %1 -importPath %2") + .arg(shellQuote(rootPath)) + .arg(importPaths.join(QLatin1Char(' '))); + + FILE *qmlImportScannerCommand = popen(qmlImportScanner.toLocal8Bit().constData(), "r"); + if (qmlImportScannerCommand == 0) { + fprintf(stderr, "Couldn't run qmlimportscanner.\n"); + return false; + } + + QByteArray output; + char buffer[512]; + while (fgets(buffer, sizeof(buffer), qmlImportScannerCommand) != 0) + output += QByteArray(buffer, qstrlen(buffer)); + + QJsonDocument jsonDocument = QJsonDocument::fromJson(output); + if (jsonDocument.isNull()) { + fprintf(stderr, "Invalid json output from qmlimportscanner.\n"); + return false; + } + + QJsonArray jsonArray = jsonDocument.array(); + for (int i=0; iverbose) + fprintf(stdout, " -- Adding '%s' as QML dependency\n", path.toLocal8Bit().constData()); + + QFileInfo info(path); + + // The qmlimportscanner sometimes outputs paths that do not exist. + if (!info.exists()) { + if (options->verbose) + fprintf(stdout, " -- Skipping because file does not exist.\n"); + continue; + } + + QString absolutePath = info.absolutePath(); + if (!absolutePath.endsWith(QLatin1Char('/'))) + absolutePath += QLatin1Char('/'); + + if (absolutePath.startsWith(rootPath)) { + if (options->verbose) + fprintf(stdout, " -- Skipping because file is in QML root path.\n"); + continue; + } + + QString importPathOfThisImport; + for (const QString &importPath : qAsConst(importPaths)) { +#if defined(Q_OS_WIN32) + Qt::CaseSensitivity caseSensitivity = Qt::CaseInsensitive; +#else + Qt::CaseSensitivity caseSensitivity = Qt::CaseSensitive; +#endif + QString cleanImportPath = QDir::cleanPath(importPath); + if (info.absoluteFilePath().startsWith(cleanImportPath, caseSensitivity)) { + importPathOfThisImport = importPath; + break; + } + } + + if (importPathOfThisImport.isEmpty()) { + fprintf(stderr, "Import found outside of import paths: %s.\n", qPrintable(info.absoluteFilePath())); + return false; + } + + QDir dir(importPathOfThisImport); + importPathOfThisImport = dir.absolutePath() + QLatin1Char('/'); + + const QList fileNames = findFilesRecursively(*options, info, importPathOfThisImport); + for (QtDependency fileName : fileNames) { + if (usedDependencies->contains(fileName.absolutePath)) + continue; + + usedDependencies->insert(fileName.absolutePath); + + if (options->verbose) + fprintf(stdout, " -- Appending dependency found by qmlimportscanner: %s\n", qPrintable(fileName.absolutePath)); + + // Put all imports in default import path in assets + fileName.relativePath.prepend(QLatin1String("qml/")); + options->qtDependencies.append(fileName); + + if (fileName.absolutePath.endsWith(QLatin1String(".so"))) { + QSet remainingDependencies; + if (!readDependenciesFromElf(options, fileName.absolutePath, usedDependencies, &remainingDependencies)) + return false; + + } + } + } + } + + return true; +} + +bool readDependencies(Options *options) +{ + if (options->verbose) + fprintf(stdout, "Detecting dependencies of application.\n"); + + // Override set in .pro file + if (!options->qtDependencies.isEmpty()) { + if (options->verbose) + fprintf(stdout, "\tDependencies explicitly overridden in .pro file. No detection needed.\n"); + return true; + } + + QSet usedDependencies; + QSet remainingDependencies; + + // Add dependencies of application binary first + if (!readDependenciesFromElf(options, options->applicationBinary, &usedDependencies, &remainingDependencies)) + return false; + + // Jam in the dependencies of the platform plugin, since the application will crash without it + if (!readDependenciesFromElf(options, options->qtInstallDirectory + QLatin1String("/plugins/platforms/android/libqtforandroid.so"), &usedDependencies, &remainingDependencies)) + return false; + + QString qtDir = options->qtInstallDirectory + QLatin1Char('/'); + + while (!remainingDependencies.isEmpty()) { + QSet::iterator start = remainingDependencies.begin(); + QString fileName = qtDir + *start; + remainingDependencies.erase(start); + + QStringList unmetDependencies; + if (goodToCopy(options, fileName, &unmetDependencies)) { + bool ok = readDependenciesFromElf(options, fileName, &usedDependencies, &remainingDependencies); + if (!ok) + return false; + } else { + fprintf(stdout, "Skipping %s due to unmet dependencies: %s\n", + qPrintable(fileName), + qPrintable(unmetDependencies.join(QLatin1Char(',')))); + } + } + + QStringList::iterator it = options->localLibs.begin(); + while (it != options->localLibs.end()) { + QStringList unmetDependencies; + if (!goodToCopy(options, qtDir + *it, &unmetDependencies)) { + fprintf(stdout, "Skipping %s due to unmet dependencies: %s\n", + qPrintable(*it), + qPrintable(unmetDependencies.join(QLatin1Char(',')))); + it = options->localLibs.erase(it); + } else { + ++it; + } + } + + if (!options->rootPath.isEmpty() && !scanImports(options, &usedDependencies)) + return false; + + return true; +} + +bool stripFile(const Options &options, const QString &fileName) +{ + QString strip = options.ndkPath + + QLatin1String("/toolchains/") + + options.toolchainPrefix + + QLatin1Char('-') + + options.toolchainVersion + + QLatin1String("/prebuilt/") + + options.ndkHost + + QLatin1String("/bin/") + + options.toolPrefix + + QLatin1String("-strip"); +#if defined(Q_OS_WIN32) + strip += QLatin1String(".exe"); +#endif + + if (!QFile::exists(strip)) { + fprintf(stderr, "Command does not exist: %s\n", qPrintable(strip)); + return false; + } + + strip = QString::fromLatin1("%1 %2").arg(shellQuote(strip)).arg(shellQuote(fileName)); + + FILE *stripCommand = openProcess(strip); + if (stripCommand == 0) { + fprintf(stderr, "Cannot execute command %s", qPrintable(strip)); + return false; + } + + pclose(stripCommand); + + return true; +} + +bool stripLibraries(const Options &options) +{ + if (options.verbose) + fprintf(stdout, "Stripping libraries to minimize size.\n"); + + + QString libraryPath = options.outputDirectory + + QLatin1String("/libs/") + + options.architecture; + const QStringList libraries = QDir(libraryPath).entryList(QDir::Files); + for (const QString &library : libraries) { + if (library.endsWith(QLatin1String(".so"))) { + if (!stripFile(options, libraryPath + QLatin1Char('/') + library)) + return false; + } + } + + + return true; +} + +bool containsApplicationBinary(const Options &options) +{ + if (options.verbose) + fprintf(stdout, "Checking if application binary is in package.\n"); + + QFileInfo applicationBinary(options.applicationBinary); + QString destinationFileName = options.outputDirectory + + QLatin1String("/libs/") + + options.architecture + + QLatin1Char('/') + + applicationBinary.fileName(); + + if (!QFile::exists(destinationFileName)) { +#if defined(Q_OS_WIN32) + QLatin1String makeTool("mingw32-make"); // Only Mingw host builds supported on Windows currently +#else + QLatin1String makeTool("make"); +#endif + + fprintf(stderr, "Application binary is not in output directory: %s. Please run '%s install INSTALL_ROOT=%s' first.\n", + qPrintable(destinationFileName), + qPrintable(makeTool), + qPrintable(options.outputDirectory)); + return false; + } + + return true; +} + +FILE *runAdb(const Options &options, const QString &arguments) +{ + QString adb = options.sdkPath + QLatin1String("/platform-tools/adb"); +#if defined(Q_OS_WIN32) + adb += QLatin1String(".exe"); +#endif + + if (!QFile::exists(adb)) { + fprintf(stderr, "Cannot find adb tool: %s\n", qPrintable(adb)); + return 0; + } + QString installOption; + if (!options.installLocation.isEmpty()) + installOption = QLatin1String(" -s ") + shellQuote(options.installLocation); + + adb = QString::fromLatin1("%1%2 %3").arg(shellQuote(adb)).arg(installOption).arg(arguments); + + if (options.verbose) + fprintf(stdout, "Running command \"%s\"\n", adb.toLocal8Bit().constData()); + + FILE *adbCommand = openProcess(adb); + if (adbCommand == 0) { + fprintf(stderr, "Cannot start adb: %s\n", qPrintable(adb)); + return 0; + } + + return adbCommand; +} + +bool goodToCopy(const Options *options, const QString &file, QStringList *unmetDependencies) +{ + if (!file.endsWith(QLatin1String(".so"))) + return true; + + bool ret = true; + const auto libs = getQtLibsFromElf(*options, file); + for (const QString &lib : libs) { + if (!options->qtDependencies.contains(QtDependency(lib, options->qtInstallDirectory + QLatin1Char('/') + lib))) { + ret = false; + unmetDependencies->append(lib); + } + } + + return ret; +} + +bool copyQtFiles(Options *options) +{ + if (options->verbose) { + switch (options->deploymentMechanism) { + case Options::Bundled: + fprintf(stdout, "Copying %d dependencies from Qt into package.\n", options->qtDependencies.size()); + break; + case Options::Ministro: + fprintf(stdout, "Setting %d dependencies from Qt in package.\n", options->qtDependencies.size()); + break; + }; + } + + if (!options->build) + return true; + + QString libsDirectory = QLatin1String("libs/"); + + // Copy other Qt dependencies + QString libDestinationDirectory = libsDirectory + options->architecture + QLatin1Char('/'); + QString assetsDestinationDirectory = QLatin1String("assets/--Added-by-androiddeployqt--/"); + for (const QtDependency &qtDependency : qAsConst(options->qtDependencies)) { + QString sourceFileName = qtDependency.absolutePath; + QString destinationFileName; + + if (qtDependency.relativePath.endsWith(QLatin1String(".so"))) { + QString garbledFileName; + if (qtDependency.relativePath.startsWith(QLatin1String("lib/"))) { + garbledFileName = qtDependency.relativePath.mid(sizeof("lib/") - 1); + } else { + garbledFileName = QLatin1String("lib") + + QString(qtDependency.relativePath).replace(QLatin1Char('/'), QLatin1Char('_')); + + } + destinationFileName = libDestinationDirectory + garbledFileName; + + } else if (qtDependency.relativePath.startsWith(QLatin1String("jar/"))) { + destinationFileName = libsDirectory + qtDependency.relativePath.mid(sizeof("jar/") - 1); + } else { + destinationFileName = assetsDestinationDirectory + qtDependency.relativePath; + } + + if (!QFile::exists(sourceFileName)) { + fprintf(stderr, "Source Qt file does not exist: %s.\n", qPrintable(sourceFileName)); + return false; + } + + QStringList unmetDependencies; + if (!goodToCopy(options, sourceFileName, &unmetDependencies)) { + fprintf(stdout, " -- Skipping %s. It has unmet dependencies: %s.\n", + qPrintable(sourceFileName), + qPrintable(unmetDependencies.join(QLatin1Char(',')))); + continue; + } + + if (options->deploymentMechanism == Options::Bundled + && !copyFileIfNewer(sourceFileName, + options->outputDirectory + QLatin1Char('/') + destinationFileName, + options->verbose)) { + return false; + } + + options->bundledFiles += qMakePair(destinationFileName, qtDependency.relativePath); + } + + return true; +} + +QStringList getLibraryProjectsInOutputFolder(const Options &options) +{ + QStringList ret; + + QFile file(options.outputDirectory + QLatin1String("/project.properties")); + if (file.open(QIODevice::ReadOnly)) { + while (!file.atEnd()) { + QByteArray line = file.readLine().trimmed(); + if (line.startsWith("android.library.reference")) { + int equalSignIndex = line.indexOf('='); + if (equalSignIndex >= 0) { + QString path = QString::fromLocal8Bit(line.mid(equalSignIndex + 1)); + + QFileInfo info(options.outputDirectory + QLatin1Char('/') + path); + if (QDir::isRelativePath(path) + && info.exists() + && info.isDir() + && info.canonicalFilePath().startsWith(options.outputDirectory)) { + ret += info.canonicalFilePath(); + } + } + } + } + } + + return ret; +} + +bool createAndroidProject(const Options &options) +{ + if (options.verbose) + fprintf(stdout, "Running Android tool to create package definition.\n"); + + QString androidToolExecutable = options.sdkPath + QLatin1String("/tools/android"); +#if defined(Q_OS_WIN32) + androidToolExecutable += QLatin1String(".bat"); +#endif + + if (!QFile::exists(androidToolExecutable)) { + fprintf(stderr, "Cannot find Android tool: %s\n", qPrintable(androidToolExecutable)); + return false; + } + + QString androidTool = QString::fromLatin1("%1 update project --path %2 --target %3 --name QtApp") + .arg(shellQuote(androidToolExecutable)) + .arg(shellQuote(options.outputDirectory)) + .arg(shellQuote(options.androidPlatform)); + + if (options.verbose) + fprintf(stdout, " -- Command: %s\n", qPrintable(androidTool)); + + FILE *androidToolCommand = openProcess(androidTool); + if (androidToolCommand == 0) { + fprintf(stderr, "Cannot run command '%s'\n", qPrintable(androidTool)); + return false; + } + + pclose(androidToolCommand); + + // If the project has subprojects inside the current folder, we need to also run android update on these. + const QStringList libraryProjects = getLibraryProjectsInOutputFolder(options); + for (const QString &libraryProject : libraryProjects) { + if (options.verbose) + fprintf(stdout, "Updating subproject %s\n", qPrintable(libraryProject)); + + androidTool = QString::fromLatin1("%1 update lib-project --path %2 --target %3") + .arg(shellQuote(androidToolExecutable)) + .arg(shellQuote(libraryProject)) + .arg(shellQuote(options.androidPlatform)); + + if (options.verbose) + fprintf(stdout, " -- Command: %s\n", qPrintable(androidTool)); + + FILE *androidToolCommand = popen(androidTool.toLocal8Bit().constData(), "r"); + if (androidToolCommand == 0) { + fprintf(stderr, "Cannot run command '%s'\n", qPrintable(androidTool)); + return false; + } + + pclose(androidToolCommand); + } + + return true; +} + +QString findInPath(const QString &fileName) +{ + const QString path = QString::fromLocal8Bit(qgetenv("PATH")); +#if defined(Q_OS_WIN32) + QLatin1Char separator(';'); +#else + QLatin1Char separator(':'); +#endif + + const QStringList paths = path.split(separator); + for (const QString &path : paths) { + QFileInfo fileInfo(path + QLatin1Char('/') + fileName); + if (fileInfo.exists() && fileInfo.isFile() && fileInfo.isExecutable()) + return path + QLatin1Char('/') + fileName; + } + + return QString(); +} + +bool buildAntProject(const Options &options) +{ + if (options.verbose) + fprintf(stdout, "Building Android package using ant.\n"); + + QString antTool = options.antTool; + if (antTool.isEmpty()) { +#if defined(Q_OS_WIN32) + antTool = findInPath(QLatin1String("ant.bat")); +#else + antTool = findInPath(QLatin1String("ant")); +#endif + } + + if (antTool.isEmpty()) { + fprintf(stderr, "Cannot find ant in PATH. Please use --ant option to pass in the correct path.\n"); + return false; + } + + if (options.verbose) + fprintf(stdout, "Using ant: %s\n", qPrintable(antTool)); + + QString oldPath = QDir::currentPath(); + if (!QDir::setCurrent(options.outputDirectory)) { + fprintf(stderr, "Cannot current path to %s\n", qPrintable(options.outputDirectory)); + return false; + } + + QString ant = QString::fromLatin1("%1 %2").arg(shellQuote(antTool)).arg(options.releasePackage ? QLatin1String(" release") : QLatin1String(" debug")); + + FILE *antCommand = openProcess(ant); + if (antCommand == 0) { + fprintf(stderr, "Cannot run ant command: %s\n.", qPrintable(ant)); + return false; + } + + char buffer[512]; + while (fgets(buffer, sizeof(buffer), antCommand) != 0) { + fprintf(stdout, "%s", buffer); + fflush(stdout); + } + + int errorCode = pclose(antCommand); + if (errorCode != 0) { + fprintf(stderr, "Building the android package failed!\n"); + if (!options.verbose) + fprintf(stderr, " -- For more information, run this command with --verbose.\n"); + return false; + } + + if (!QDir::setCurrent(oldPath)) { + fprintf(stderr, "Cannot change back to old path: %s\n", qPrintable(oldPath)); + return false; + } + + return true; +} + +typedef QMap GradleProperties; + +static GradleProperties readGradleProperties(const QString &path) +{ + GradleProperties properties; + QFile file(path); + if (!file.open(QIODevice::ReadOnly)) + return properties; + + const auto lines = file.readAll().split('\n'); + for (const QByteArray &line : lines) { + if (line.trimmed().startsWith('#')) + continue; + + QList prop(line.split('=')); + if (prop.size() > 1) + properties[prop.at(0).trimmed()] = prop.at(1).trimmed(); + } + file.close(); + return properties; +} + +static bool mergeGradleProperties(const QString &path, GradleProperties properties) +{ + QFile::remove(path + QLatin1Char('~')); + QFile::rename(path, path + QLatin1Char('~')); + QFile file(path); + if (!file.open(QIODevice::Truncate | QIODevice::WriteOnly | QIODevice::Text)) { + fprintf(stderr, "Can't open file: %s for writing\n", qPrintable(file.fileName())); + return false; + } + + QFile oldFile(path + QLatin1Char('~')); + if (oldFile.open(QIODevice::ReadOnly)) { + while (!oldFile.atEnd()) { + QByteArray line(oldFile.readLine()); + QList prop(line.split('=')); + if (prop.size() > 1) { + GradleProperties::iterator it = properties.find(prop.at(0).trimmed()); + if (it != properties.end()) { + file.write(it.key() + '=' + it.value() + '\n'); + properties.erase(it); + continue; + } + } + file.write(line); + } + oldFile.close(); + } + + for (GradleProperties::const_iterator it = properties.begin(); it != properties.end(); ++it) + file.write(it.key() + '=' + it.value() + '\n'); + + file.close(); + return true; +} + +bool buildGradleProject(const Options &options) +{ + GradleProperties localProperties; + localProperties["sdk.dir"] = options.sdkPath.toLocal8Bit(); + + if (!mergeGradleProperties(options.outputDirectory + QLatin1String("local.properties"), localProperties)) + return false; + + QString gradlePropertiesPath = options.outputDirectory + QLatin1String("gradle.properties"); + GradleProperties gradleProperties = readGradleProperties(gradlePropertiesPath); + gradleProperties["buildDir"] = "build"; + gradleProperties["qt5AndroidDir"] = (options.qtInstallDirectory + QLatin1String("/src/android/java")).toUtf8(); + gradleProperties["androidCompileSdkVersion"] = options.androidPlatform.split(QLatin1Char('-')).last().toLocal8Bit(); + if (gradleProperties["androidBuildToolsVersion"].isEmpty()) + gradleProperties["androidBuildToolsVersion"] = options.sdkBuildToolsVersion.toLocal8Bit(); + + if (!mergeGradleProperties(gradlePropertiesPath, gradleProperties)) + return false; + +#if defined(Q_OS_WIN32) + QString gradlePath(options.outputDirectory + QLatin1String("gradlew.bat")); +#else + QString gradlePath(options.outputDirectory + QLatin1String("gradlew")); + { + QFile f(gradlePath); + if (!f.setPermissions(f.permissions() | QFileDevice::ExeUser)) + fprintf(stderr, "Cannot set permissions %s\n", qPrintable(gradlePath)); + } +#endif + + QString oldPath = QDir::currentPath(); + if (!QDir::setCurrent(options.outputDirectory)) { + fprintf(stderr, "Cannot current path to %s\n", qPrintable(options.outputDirectory)); + return false; + } + + QString commandLine = QString::fromLatin1("%1 --no-daemon %2").arg(shellQuote(gradlePath)).arg(options.releasePackage ? QLatin1String(" assembleRelease") : QLatin1String(" assembleDebug")); + if (options.verbose) + commandLine += QLatin1String(" --info"); + + FILE *gradleCommand = openProcess(commandLine); + if (gradleCommand == 0) { + fprintf(stderr, "Cannot run gradle command: %s\n.", qPrintable(commandLine)); + return false; + } + + char buffer[512]; + while (fgets(buffer, sizeof(buffer), gradleCommand) != 0) { + fprintf(stdout, "%s", buffer); + fflush(stdout); + } + + int errorCode = pclose(gradleCommand); + if (errorCode != 0) { + fprintf(stderr, "Building the android package failed!\n"); + if (!options.verbose) + fprintf(stderr, " -- For more information, run this command with --verbose.\n"); + return false; + } + + if (!QDir::setCurrent(oldPath)) { + fprintf(stderr, "Cannot change back to old path: %s\n", qPrintable(oldPath)); + return false; + } + + return true; +} + +bool buildAndroidProject(const Options &options) +{ + return options.gradle ? buildGradleProject(options) + : buildAntProject(options); +} + +bool uninstallApk(const Options &options) +{ + if (options.verbose) + fprintf(stdout, "Uninstalling old Android package %s if present.\n", qPrintable(options.packageName)); + + + FILE *adbCommand = runAdb(options, QLatin1String(" uninstall ") + shellQuote(options.packageName)); + if (adbCommand == 0) + return false; + + if (options.verbose || mustReadOutputAnyway) { + char buffer[512]; + while (fgets(buffer, sizeof(buffer), adbCommand) != 0) + if (options.verbose) + fprintf(stdout, "%s", buffer); + } + + int returnCode = pclose(adbCommand); + if (returnCode != 0) { + fprintf(stderr, "Warning: Uninstall failed!\n"); + if (!options.verbose) + fprintf(stderr, " -- Run with --verbose for more information.\n"); + return false; + } + + return true; +} + +enum PackageType { + UnsignedAPK, + SignedAPK +}; + +QString apkPath(const Options &options, PackageType pt) +{ + QString path(options.outputDirectory); + if (options.gradle) + path += QLatin1String("/build/outputs/apk/") + QDir(options.outputDirectory).dirName() + QLatin1Char('-'); + else + path += QLatin1String("/bin/QtApp-"); + if (options.releasePackage) { + path += QLatin1String("release-"); + if (pt == UnsignedAPK) + path += QLatin1String("un"); + path += QLatin1String("signed.apk"); + } else { + path += QLatin1String("debug"); + if (pt == SignedAPK) + path += QLatin1String("-signed"); + path += QLatin1String(".apk"); + } + return shellQuote(path); +} + +bool installApk(const Options &options) +{ + fflush(stdout); + // Uninstall if necessary + if (options.uninstallApk) + uninstallApk(options); + + if (options.verbose) + fprintf(stdout, "Installing Android package to device.\n"); + + FILE *adbCommand = runAdb(options, + QLatin1String(" install -r ") + + apkPath(options, options.keyStore.isEmpty() ? UnsignedAPK + : SignedAPK)); + if (adbCommand == 0) + return false; + + if (options.verbose || mustReadOutputAnyway) { + char buffer[512]; + while (fgets(buffer, sizeof(buffer), adbCommand) != 0) + if (options.verbose) + fprintf(stdout, "%s", buffer); + } + + int returnCode = pclose(adbCommand); + if (returnCode != 0) { + fprintf(stderr, "Installing to device failed!\n"); + if (!options.verbose) + fprintf(stderr, " -- Run with --verbose for more information.\n"); + return false; + } + + return true; +} + +bool copyStdCpp(Options *options) +{ + if (options->verbose) + fprintf(stdout, "Copying STL library\n"); + + QString filePath = !options->stdCppPath.isEmpty() ? options->stdCppPath + : options->ndkPath + + QLatin1String("/sources/cxx-stl/gnu-libstdc++/") + + options->toolchainVersion + + QLatin1String("/libs/") + + options->architecture + + QLatin1String("/libgnustl_shared.so"); + if (!QFile::exists(filePath)) { + fprintf(stderr, "STL library does not exist at %s\n", qPrintable(filePath)); + return false; + } + + const QString destinationDirectory = options->outputDirectory + + QLatin1String("/libs/") + options->architecture; + + if (!copyFileIfNewer(filePath, destinationDirectory + QLatin1String("/lib") + + options->stdCppName + QLatin1String(".so"), + options->verbose)) { + return false; + } + + return true; +} + +bool jarSignerSignPackage(const Options &options) +{ + if (options.verbose) + fprintf(stdout, "Signing Android package.\n"); + + QString jdkPath = options.jdkPath; + + if (jdkPath.isEmpty()) + jdkPath = QString::fromLocal8Bit(qgetenv("JAVA_HOME")); + +#if defined(Q_OS_WIN32) + QString jarSignerTool = QString::fromLatin1("jarsigner.exe"); +#else + QString jarSignerTool = QString::fromLatin1("jarsigner"); +#endif + + if (jdkPath.isEmpty() || !QFile::exists(jdkPath + QLatin1String("/bin/") + jarSignerTool)) + jarSignerTool = findInPath(jarSignerTool); + else + jarSignerTool = jdkPath + QLatin1String("/bin/") + jarSignerTool; + + if (!QFile::exists(jarSignerTool)) { + fprintf(stderr, "Cannot find jarsigner in JAVA_HOME or PATH. Please use --jdk option to pass in the correct path to JDK.\n"); + return false; + } + + jarSignerTool = QString::fromLatin1("%1 -sigalg %2 -digestalg %3 -keystore %4") + .arg(shellQuote(jarSignerTool)).arg(shellQuote(options.sigAlg)).arg(shellQuote(options.digestAlg)).arg(shellQuote(options.keyStore)); + + if (!options.keyStorePassword.isEmpty()) + jarSignerTool += QString::fromLatin1(" -storepass %1").arg(shellQuote(options.keyStorePassword)); + + if (!options.storeType.isEmpty()) + jarSignerTool += QString::fromLatin1(" -storetype %1").arg(shellQuote(options.storeType)); + + if (!options.keyPass.isEmpty()) + jarSignerTool += QString::fromLatin1(" -keypass %1").arg(shellQuote(options.keyPass)); + + if (!options.sigFile.isEmpty()) + jarSignerTool += QString::fromLatin1(" -sigfile %1").arg(shellQuote(options.sigFile)); + + if (!options.signedJar.isEmpty()) + jarSignerTool += QString::fromLatin1(" -signedjar %1").arg(shellQuote(options.signedJar)); + + if (!options.tsaUrl.isEmpty()) + jarSignerTool += QString::fromLatin1(" -tsa %1").arg(shellQuote(options.tsaUrl)); + + if (!options.tsaCert.isEmpty()) + jarSignerTool += QString::fromLatin1(" -tsacert %1").arg(shellQuote(options.tsaCert)); + + if (options.internalSf) + jarSignerTool += QLatin1String(" -internalsf"); + + if (options.sectionsOnly) + jarSignerTool += QLatin1String(" -sectionsonly"); + + if (options.protectedAuthenticationPath) + jarSignerTool += QLatin1String(" -protected"); + + jarSignerTool += QString::fromLatin1(" %1 %2") + .arg(apkPath(options, UnsignedAPK)) + .arg(shellQuote(options.keyStoreAlias)); + + FILE *jarSignerCommand = openProcess(jarSignerTool); + if (jarSignerCommand == 0) { + fprintf(stderr, "Couldn't run jarsigner.\n"); + return false; + } + + if (options.verbose) { + char buffer[512]; + while (fgets(buffer, sizeof(buffer), jarSignerCommand) != 0) + fprintf(stdout, "%s", buffer); + } + + int errorCode = pclose(jarSignerCommand); + if (errorCode != 0) { + fprintf(stderr, "jarsigner command failed.\n"); + if (!options.verbose) + fprintf(stderr, " -- Run with --verbose for more information.\n"); + return false; + } + + QString zipAlignTool = options.sdkPath + QLatin1String("/tools/zipalign"); +#if defined(Q_OS_WIN32) + zipAlignTool += QLatin1String(".exe"); +#endif + + if (!QFile::exists(zipAlignTool)) { + zipAlignTool = options.sdkPath + QLatin1String("/build-tools/") + options.sdkBuildToolsVersion + QLatin1String("/zipalign"); +#if defined(Q_OS_WIN32) + zipAlignTool += QLatin1String(".exe"); +#endif + if (!QFile::exists(zipAlignTool)) { + fprintf(stderr, "zipalign tool not found: %s\n", qPrintable(zipAlignTool)); + return false; + } + } + + zipAlignTool = QString::fromLatin1("%1%2 -f 4 %3 %4") + .arg(shellQuote(zipAlignTool)) + .arg(options.verbose ? QString::fromLatin1(" -v") : QString()) + .arg(apkPath(options, UnsignedAPK)) + .arg(apkPath(options, SignedAPK)); + + FILE *zipAlignCommand = openProcess(zipAlignTool); + if (zipAlignCommand == 0) { + fprintf(stderr, "Couldn't run zipalign.\n"); + return false; + } + + char buffer[512]; + while (fgets(buffer, sizeof(buffer), zipAlignCommand) != 0) + fprintf(stdout, "%s", buffer); + + errorCode = pclose(zipAlignCommand); + if (errorCode != 0) { + fprintf(stderr, "zipalign command failed.\n"); + if (!options.verbose) + fprintf(stderr, " -- Run with --verbose for more information.\n"); + return false; + } + + return QFile::remove(apkPath(options, UnsignedAPK)); +} + +bool signPackage(const Options &options) +{ + QString apksignerTool = options.sdkPath + QLatin1String("/build-tools/") + options.sdkBuildToolsVersion + QLatin1String("/apksigner"); +#if defined(Q_OS_WIN32) + apksignerTool += QLatin1String(".bat"); +#endif + + if (options.jarSigner || !QFile::exists(apksignerTool)) + return jarSignerSignPackage(options); + + // APKs signed with apksigner must not be changed after they're signed, therefore we need to zipalign it before we sign it. + + QString zipAlignTool = options.sdkPath + QLatin1String("/tools/zipalign"); +#if defined(Q_OS_WIN32) + zipAlignTool += QLatin1String(".exe"); +#endif + + if (!QFile::exists(zipAlignTool)) { + zipAlignTool = options.sdkPath + QLatin1String("/build-tools/") + options.sdkBuildToolsVersion + QLatin1String("/zipalign"); +#if defined(Q_OS_WIN32) + zipAlignTool += QLatin1String(".exe"); +#endif + if (!QFile::exists(zipAlignTool)) { + fprintf(stderr, "zipalign tool not found: %s\n", qPrintable(zipAlignTool)); + return false; + } + } + + zipAlignTool = QString::fromLatin1("%1%2 -f 4 %3 %4") + .arg(shellQuote(zipAlignTool)) + .arg(options.verbose ? QString::fromLatin1(" -v") : QString()) + .arg(apkPath(options, UnsignedAPK)) + .arg(apkPath(options, SignedAPK)); + + FILE *zipAlignCommand = openProcess(zipAlignTool); + if (zipAlignCommand == 0) { + fprintf(stderr, "Couldn't run zipalign.\n"); + return false; + } + + char buffer[512]; + while (fgets(buffer, sizeof(buffer), zipAlignCommand) != 0) + fprintf(stdout, "%s", buffer); + + int errorCode = pclose(zipAlignCommand); + if (errorCode != 0) { + fprintf(stderr, "zipalign command failed.\n"); + if (!options.verbose) + fprintf(stderr, " -- Run with --verbose for more information.\n"); + return false; + } + + QString apkSignerCommandLine = QString::fromLatin1("%1 sign --ks %2") + .arg(shellQuote(apksignerTool)).arg(shellQuote(options.keyStore)); + + if (!options.keyStorePassword.isEmpty()) + apkSignerCommandLine += QString::fromLatin1(" --ks-pass pass:%1").arg(shellQuote(options.keyStorePassword)); + + if (!options.keyStoreAlias.isEmpty()) + apkSignerCommandLine += QString::fromLatin1(" --ks-key-alias %1").arg(shellQuote(options.keyStoreAlias)); + + if (!options.keyPass.isEmpty()) + apkSignerCommandLine += QString::fromLatin1(" --key-pass pass:%1").arg(shellQuote(options.keyPass)); + + if (options.verbose) + apkSignerCommandLine += QLatin1String(" --verbose"); + + apkSignerCommandLine += QString::fromLatin1(" %1") + .arg(apkPath(options, SignedAPK)); + + auto apkSignerRunner = [&] { + FILE *apkSignerCommand = openProcess(apkSignerCommandLine); + if (apkSignerCommand == 0) { + fprintf(stderr, "Couldn't run apksigner.\n"); + return false; + } + + char buffer[512]; + while (fgets(buffer, sizeof(buffer), apkSignerCommand) != 0) + fprintf(stdout, "%s", buffer); + + errorCode = pclose(apkSignerCommand); + if (errorCode != 0) { + fprintf(stderr, "apksigner command failed.\n"); + if (!options.verbose) + fprintf(stderr, " -- Run with --verbose for more information.\n"); + return false; + } + return true; + }; + + // Sign the package + if (!apkSignerRunner()) + return false; + + apkSignerCommandLine = QString::fromLatin1("%1 verify --verbose %2") + .arg(shellQuote(apksignerTool)).arg(apkPath(options, SignedAPK)); + + // Verify the package and remove the unsigned apk + return apkSignerRunner() && QFile::remove(apkPath(options, UnsignedAPK)); +} + +bool copyGdbServer(const Options &options) +{ + if (options.verbose) + fprintf(stdout, "Copying gdbserver into package.\n"); + + QString architectureSubDirectory; + if (options.architecture == QLatin1String("arm64-v8a")) + architectureSubDirectory = QLatin1String("android-arm64"); + else if (options.architecture.startsWith(QLatin1String("arm"))) + architectureSubDirectory = QLatin1String("android-arm"); + else + architectureSubDirectory = QLatin1String("android-") + options.architecture; + + QString gdbServerBinary = options.ndkPath + + QLatin1String("/prebuilt/") + + architectureSubDirectory + + QLatin1String("/gdbserver/gdbserver"); + if (!QFile::exists(gdbServerBinary)) { + fprintf(stderr, "Cannot find gdbserver at %s.\n", qPrintable(gdbServerBinary)); + return false; + } + + QString gdbServerTarget = options.outputDirectory + QLatin1String("/libs/") + options.architecture; + + if (!copyFileIfNewer(gdbServerBinary, + gdbServerTarget + QLatin1String("/gdbserver"), + options.verbose) + || !copyFileIfNewer(gdbServerBinary, + gdbServerTarget + QLatin1String("/libgdbserver.so"), + options.verbose)) { + return false; + } + + QString addedByAndroidDeployQtPath = options.outputDirectory + QLatin1String("/assets/--Added-by-androiddeployqt--/"); + if (!QDir().mkpath(addedByAndroidDeployQtPath)) { + fprintf(stderr, "Failed to create directory '%s'", qPrintable(addedByAndroidDeployQtPath)); + return false; + } + QFile f(addedByAndroidDeployQtPath + QLatin1String("debugger.command")); + if (!f.open(QIODevice::WriteOnly)) { + fprintf(stderr, "Failed to create directory '%s'", qPrintable(addedByAndroidDeployQtPath)); + return false; + } + f.write("lib/libgdbserver.so --multi +"); + f.close(); + + return true; +} + +bool generateAssetsFileList(const Options &options) +{ + if (options.verbose) + fprintf(stdout, "Pregenerating entry list for assets file engine.\n"); + + QString assetsPath = options.outputDirectory + QLatin1String("/assets/"); + QString addedByAndroidDeployQtPath = assetsPath + QLatin1String("--Added-by-androiddeployqt--/"); + if (!QDir().mkpath(addedByAndroidDeployQtPath)) { + fprintf(stderr, "Failed to create directory '%s'", qPrintable(addedByAndroidDeployQtPath)); + return false; + } + + QFile file(addedByAndroidDeployQtPath + QLatin1String("/qt_cache_pregenerated_file_list")); + if (file.open(QIODevice::WriteOnly)) { + QDirIterator dirIterator(assetsPath, + QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot, + QDirIterator::Subdirectories); + + QHash directoryContents; + while (dirIterator.hasNext()) { + const QString name = dirIterator.next().mid(assetsPath.length()); + + int slashIndex = name.lastIndexOf(QLatin1Char('/')); + QString pathName = slashIndex >= 0 ? name.left(slashIndex) : QString::fromLatin1("/"); + QString fileName = slashIndex >= 0 ? name.mid(pathName.length() + 1) : name; + + if (!fileName.isEmpty() && dirIterator.fileInfo().isDir() && !fileName.endsWith(QLatin1Char('/'))) + fileName += QLatin1Char('/'); + + if (fileName.isEmpty() && !directoryContents.contains(pathName)) + directoryContents[pathName] = QStringList(); + else if (!fileName.isEmpty()) + directoryContents[pathName].append(fileName); + } + + QDataStream stream(&file); + stream.setVersion(QDataStream::Qt_5_3); + for (auto it = directoryContents.cbegin(), end = directoryContents.cend(); it != end; ++it) { + const QStringList &entryList = it.value(); + stream << it.key() << entryList.size(); + for (const QString &entry : entryList) + stream << entry; + } + } else { + fprintf(stderr, "Pregenerating entry list for assets file engine failed!\n"); + return false; + } + + return true; +} + +enum ErrorCode +{ + Success, + SyntaxErrorOrHelpRequested = 1, + CannotReadInputFile = 2, + CannotCopyAndroidTemplate = 3, + CannotReadDependencies = 4, + CannotCopyGnuStl = 5, + CannotCopyQtFiles = 6, + CannotFindApplicationBinary = 7, + CannotCopyGdbServer = 8, + CannotStripLibraries = 9, + CannotCopyAndroidExtraLibs = 10, + CannotCopyAndroidSources = 11, + CannotUpdateAndroidFiles = 12, + CannotCreateAndroidProject = 13, + CannotBuildAndroidProject = 14, + CannotSignPackage = 15, + CannotInstallApk = 16, + CannotGenerateAssetsFileList = 18, + CannotCopyAndroidExtraResources = 19 +}; + +int main(int argc, char *argv[]) +{ + QCoreApplication a(argc, argv); + + Options options = parseOptions(); + if (options.helpRequested || options.outputDirectory.isEmpty()) { + printHelp(); + return SyntaxErrorOrHelpRequested; + } + + options.timer.start(); + + if (!readInputFile(&options)) + return CannotReadInputFile; + + if (Q_UNLIKELY(options.timing)) + fprintf(stdout, "[TIMING] %d ms: Read input file\n", options.timer.elapsed()); + + fprintf(stdout, +// "012345678901234567890123456789012345678901234567890123456789012345678901" + "Generating Android Package\n" + " Input file: %s\n" + " Output directory: %s\n" + " Application binary: %s\n" + " Android build platform: %s\n" + " Install to device: %s\n", + qPrintable(options.inputFileName), + qPrintable(options.outputDirectory), + qPrintable(options.applicationBinary), + qPrintable(options.androidPlatform), + options.installApk + ? (options.installLocation.isEmpty() ? "Default device" : qPrintable(options.installLocation)) + : "No" + ); + + if (options.build) { + if (options.gradle) + cleanAndroidFiles(options); + if (Q_UNLIKELY(options.timing)) + fprintf(stdout, "[TIMING] %d ms: Cleaned Android file\n", options.timer.elapsed()); + + if (!copyAndroidTemplate(options)) + return CannotCopyAndroidTemplate; + + if (Q_UNLIKELY(options.timing)) + fprintf(stdout, "[TIMING] %d ms: Copied Android template\n", options.timer.elapsed()); + } + + if (!readDependencies(&options)) + return CannotReadDependencies; + + if (Q_UNLIKELY(options.timing)) + fprintf(stdout, "[TIMING] %d ms: Read dependencies\n", options.timer.elapsed()); + + if (options.deploymentMechanism != Options::Ministro && !copyStdCpp(&options)) + return CannotCopyGnuStl; + + if (Q_UNLIKELY(options.timing)) + fprintf(stdout, "[TIMING] %d ms: Copied GNU STL\n", options.timer.elapsed()); + + if (!copyQtFiles(&options)) + return CannotCopyQtFiles; + + if (options.build) { + if (Q_UNLIKELY(options.timing)) + fprintf(stdout, "[TIMING] %d ms: Copied Qt files\n", options.timer.elapsed()); + + if (!containsApplicationBinary(options)) + return CannotFindApplicationBinary; + + if (Q_UNLIKELY(options.timing)) + fprintf(stdout, "[TIMING] %d ms: Checked for application binary\n", options.timer.elapsed()); + + bool needToCopyGdbServer = options.gdbServer == Options::True + || (options.gdbServer == Options::Auto && !options.releasePackage); + if (needToCopyGdbServer && !copyGdbServer(options)) + return CannotCopyGdbServer; + + if (Q_UNLIKELY(options.timing)) + fprintf(stdout, "[TIMING] %d ms: Copied GDB server\n", options.timer.elapsed()); + + if (!copyAndroidExtraLibs(options)) + return CannotCopyAndroidExtraLibs; + + if (Q_UNLIKELY(options.timing)) + fprintf(stdout, "[TIMING] %d ms: Copied extra libs\n", options.timer.elapsed()); + + if (!copyAndroidExtraResources(options)) + return CannotCopyAndroidExtraResources; + + if (!copyAndroidSources(options)) + return CannotCopyAndroidSources; + + if (Q_UNLIKELY(options.timing)) + fprintf(stdout, "[TIMING] %d ms: Copied android sources\n", options.timer.elapsed()); + + if (!stripLibraries(options)) + return CannotStripLibraries; + + if (Q_UNLIKELY(options.timing)) + fprintf(stdout, "[TIMING] %d ms: Stripped libraries\n", options.timer.elapsed()); + + if (!updateAndroidFiles(options)) + return CannotUpdateAndroidFiles; + + if (options.generateAssetsFileList && !generateAssetsFileList(options)) + return CannotGenerateAssetsFileList; + + if (Q_UNLIKELY(options.timing)) + fprintf(stdout, "[TIMING] %d ms: Updated files\n", options.timer.elapsed()); + + if (!options.gradle && !createAndroidProject(options)) + return CannotCreateAndroidProject; + + if (Q_UNLIKELY(options.timing)) + fprintf(stdout, "[TIMING] %d ms: Created project\n", options.timer.elapsed()); + + if (!buildAndroidProject(options)) + return CannotBuildAndroidProject; + + if (Q_UNLIKELY(options.timing)) + fprintf(stdout, "[TIMING] %d ms: Built project\n", options.timer.elapsed()); + + if (!options.keyStore.isEmpty() && !signPackage(options)) + return CannotSignPackage; + + if (Q_UNLIKELY(options.timing)) + fprintf(stdout, "[TIMING] %d ms: Signed package\n", options.timer.elapsed()); + } + + if (options.installApk && !installApk(options)) + return CannotInstallApk; + + if (Q_UNLIKELY(options.timing)) + fprintf(stdout, "[TIMING] %d ms: Installed APK\n", options.timer.elapsed()); + + fprintf(stdout, "Android package built successfully in %.3f ms.\n", options.timer.elapsed() / 1000.); + + if (options.installApk) + fprintf(stdout, " -- It can now be run from the selected device/emulator.\n"); + + fprintf(stdout, " -- File: %s\n", qPrintable(apkPath(options, options.keyStore.isEmpty() ? UnsignedAPK + : SignedAPK))); + fflush(stdout); + return 0; +} diff --git a/src/widgets/dialogs/qfiledialog.cpp b/src/widgets/dialogs/qfiledialog.cpp index 8248676a9f..2742b152f2 100644 --- a/src/widgets/dialogs/qfiledialog.cpp +++ b/src/widgets/dialogs/qfiledialog.cpp @@ -1462,19 +1462,6 @@ void QFileDialog::selectNameFilter(const QString &filter) } } -/*! - * \since 5.9 - * \return The mimetype of the file that the user selected in the file dialog. - */ -QString QFileDialog::selectedMimeTypeFilter() const -{ - Q_D(const QFileDialog); - if (!d->usingWidgets()) - return d->selectedMimeTypeFilter_sys(); - - return d->options->initiallySelectedMimeTypeFilter(); -} - /*! \since 4.4 @@ -1611,6 +1598,36 @@ void QFileDialog::selectMimeTypeFilter(const QString &filter) #endif // QT_NO_MIMETYPE +/*! + * \since 5.9 + * \return The mimetype of the file that the user selected in the file dialog. + */ +QString QFileDialog::selectedMimeTypeFilter() const +{ + Q_D(const QFileDialog); + QString mimeTypeFilter; + if (!d->usingWidgets()) + mimeTypeFilter = d->selectedMimeTypeFilter_sys(); + +#ifndef QT_NO_MIMETYPE + if (mimeTypeFilter.isNull() && !d->options->mimeTypeFilters().isEmpty()) { + const auto nameFilter = selectedNameFilter(); + const auto mimeTypes = d->options->mimeTypeFilters(); + for (const auto &mimeType: mimeTypes) { + QString filter = nameFilterForMime(mimeType); + if (testOption(HideNameFilterDetails)) + filter = qt_strip_filters({ filter }).first(); + if (filter == nameFilter) { + mimeTypeFilter = mimeType; + break; + } + } + } +#endif + + return mimeTypeFilter; +} + /*! \property QFileDialog::viewMode \brief the way files and directories are displayed in the dialog diff --git a/src/widgets/graphicsview/qgraphicsitem.cpp b/src/widgets/graphicsview/qgraphicsitem.cpp index 38df9e72bd..203b879020 100644 --- a/src/widgets/graphicsview/qgraphicsitem.cpp +++ b/src/widgets/graphicsview/qgraphicsitem.cpp @@ -1579,6 +1579,7 @@ QGraphicsItem::~QGraphicsItem() QObjectPrivate *p = QObjectPrivate::get(o); p->wasDeleted = true; if (p->declarativeData) { + p->wasDeleted = true; // needed, so that destroying the declarative data does the right thing if (static_cast(p->declarativeData)->ownedByQml1) { if (QAbstractDeclarativeData::destroyed_qml1) QAbstractDeclarativeData::destroyed_qml1(p->declarativeData, o); @@ -1587,6 +1588,7 @@ QGraphicsItem::~QGraphicsItem() QAbstractDeclarativeData::destroyed(p->declarativeData, o); } p->declarativeData = 0; + p->wasDeleted = false; } } diff --git a/src/widgets/itemviews/qheaderview.cpp b/src/widgets/itemviews/qheaderview.cpp index 6dc0543255..762e852f88 100644 --- a/src/widgets/itemviews/qheaderview.cpp +++ b/src/widgets/itemviews/qheaderview.cpp @@ -2727,7 +2727,7 @@ void QHeaderView::mouseMoveEvent(QMouseEvent *e) statusTip = d->model->headerData(logical, d->orientation, Qt::StatusTipRole).toString(); if (d->shouldClearStatusTip || !statusTip.isEmpty()) { QStatusTipEvent tip(statusTip); - QCoreApplication::sendEvent(d->parent, &tip); + QCoreApplication::sendEvent(d->parent ? d->parent : this, &tip); d->shouldClearStatusTip = !statusTip.isEmpty(); } #endif // !QT_NO_STATUSTIP diff --git a/src/widgets/kernel/qwidget.cpp b/src/widgets/kernel/qwidget.cpp index e59bd4098d..9a19597cad 100644 --- a/src/widgets/kernel/qwidget.cpp +++ b/src/widgets/kernel/qwidget.cpp @@ -1677,8 +1677,8 @@ QWidget::~QWidget() } } - d->wasDeleted = true; if (d->declarativeData) { + d->wasDeleted = true; // needed, so that destroying the declarative data does the right thing if (static_cast(d->declarativeData)->ownedByQml1) { if (QAbstractDeclarativeData::destroyed_qml1) QAbstractDeclarativeData::destroyed_qml1(d->declarativeData, this); @@ -1687,6 +1687,7 @@ QWidget::~QWidget() QAbstractDeclarativeData::destroyed(d->declarativeData, this); } d->declarativeData = 0; // don't activate again in ~QObject + d->wasDeleted = false; } d->blockSig = blocked; diff --git a/src/widgets/widgets/qmenubar.cpp b/src/widgets/widgets/qmenubar.cpp index 4758f64c8c..6df53dc4e4 100644 --- a/src/widgets/widgets/qmenubar.cpp +++ b/src/widgets/widgets/qmenubar.cpp @@ -327,7 +327,7 @@ void QMenuBarPrivate::popupAction(QAction *action, bool activateFirst) QRect screenRect = QDesktopWidgetPrivate::screenGeometry(pos + QPoint(adjustedActionRect.width() / 2, 0)); pos = QPoint(qMax(pos.x(), screenRect.x()), qMax(pos.y(), screenRect.y())); - const bool fitUp = (q->mapToGlobal(adjustedActionRect.topLeft()).y() >= popup_size.height()); + const bool fitUp = (pos.y() - popup_size.height() >= screenRect.top()); const bool fitDown = (pos.y() + popup_size.height() <= screenRect.bottom()); const bool rtl = q->isRightToLeft(); const int actionWidth = adjustedActionRect.width(); @@ -1209,8 +1209,15 @@ void QMenuBar::keyPressEvent(QKeyEvent *e) void QMenuBar::mouseMoveEvent(QMouseEvent *e) { Q_D(QMenuBar); - if (!(e->buttons() & Qt::LeftButton)) + if (!(e->buttons() & Qt::LeftButton)) { d->mouseDown = false; + // We receive mouse move and mouse press on touch. + // Mouse move will open the menu and mouse press + // will close it, so ignore mouse move. + if (e->source() != Qt::MouseEventNotSynthesized) + return; + } + bool popupState = d->popupState || d->mouseDown; QAction *action = d->actionAt(e->pos()); if ((action && d->isVisible(action)) || !popupState) diff --git a/src/widgets/widgets/qplaintextedit.cpp b/src/widgets/widgets/qplaintextedit.cpp index f15a846b5e..252d5a79df 100644 --- a/src/widgets/widgets/qplaintextedit.cpp +++ b/src/widgets/widgets/qplaintextedit.cpp @@ -110,7 +110,7 @@ public: /*! \class QPlainTextDocumentLayout \since 4.4 - \brief The QPlainTextDocumentLayout class implements a plain text layout for QTextDocument + \brief The QPlainTextDocumentLayout class implements a plain text layout for QTextDocument. \ingroup richtext-processing \inmodule QtWidgets diff --git a/src/widgets/widgets/qtextedit.cpp b/src/widgets/widgets/qtextedit.cpp index bbcd3ca386..3a368651de 100644 --- a/src/widgets/widgets/qtextedit.cpp +++ b/src/widgets/widgets/qtextedit.cpp @@ -2048,7 +2048,7 @@ void QTextEdit::setAcceptRichText(bool accept) \inmodule QtWidgets \brief The QTextEdit::ExtraSelection structure provides a way of specifying a - character format for a given selection in a document + character format for a given selection in a document. */ /*! diff --git a/tests/auto/cmake/CMakeLists.txt b/tests/auto/cmake/CMakeLists.txt index f1d8657091..ec75ec7caf 100644 --- a/tests/auto/cmake/CMakeLists.txt +++ b/tests/auto/cmake/CMakeLists.txt @@ -47,6 +47,7 @@ find_package(Qt5Core REQUIRED) include("${_Qt5CTestMacros}") +expect_pass(test_use_modules_function) expect_pass(test_umbrella_config) expect_pass(test_wrap_cpp_and_resources) if (NOT NO_WIDGETS) diff --git a/tests/auto/cmake/test_use_modules_function/CMakeLists.txt b/tests/auto/cmake/test_use_modules_function/CMakeLists.txt new file mode 100644 index 0000000000..be05c75054 --- /dev/null +++ b/tests/auto/cmake/test_use_modules_function/CMakeLists.txt @@ -0,0 +1,18 @@ + +cmake_minimum_required(VERSION 2.8) + +project(test_use_modules_function) + +set(CMAKE_AUTOMOC ON) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +add_executable(two two.cpp) +add_executable(three three.cpp) + +find_package(Qt5Core) + +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${Qt5Core_EXECUTABLE_COMPILE_FLAGS}") + +qt5_use_modules(two Test) +qt5_use_modules(three Gui Test) diff --git a/tests/auto/cmake/test_use_modules_function/three.cpp b/tests/auto/cmake/test_use_modules_function/three.cpp new file mode 100644 index 0000000000..507cc8479d --- /dev/null +++ b/tests/auto/cmake/test_use_modules_function/three.cpp @@ -0,0 +1,45 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Stephen Kelly +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite 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 +#include + +class Three : public QObject +{ + Q_OBJECT +public: + Three(QObject *parent = 0) + { + QWindow *w = new QWindow; + w->show(); + } +}; + +QTEST_MAIN(Three) + +#include "three.moc" diff --git a/tests/auto/compilerwarnings/data/test_cpp.txt b/tests/auto/cmake/test_use_modules_function/two.cpp similarity index 74% rename from tests/auto/compilerwarnings/data/test_cpp.txt rename to tests/auto/cmake/test_use_modules_function/two.cpp index 6ea63f56fd..44eb7fe96e 100644 --- a/tests/auto/compilerwarnings/data/test_cpp.txt +++ b/tests/auto/cmake/test_use_modules_function/two.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2011 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Stephen Kelly ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the test suite of the Qt Toolkit. @@ -26,29 +26,18 @@ ** ****************************************************************************/ +#include -#include -#include -#include -#include - -#ifndef QT_NO_GUI -#include -#endif - -#ifndef QT_NO_OPENGL -#include -#endif - -#include - -#if !defined(QT_NO_DBUS) && defined(Q_OS_UNIX) -#include -#endif - -#ifndef Q_OS_MAC -int main(int, char **) +class Two : public QObject { - return 0; -} -#endif + Q_OBJECT +public: + Two(QObject *parent = 0) + { + + } +}; + +QTEST_MAIN(Two) + +#include "two.moc" diff --git a/tests/auto/corelib/global/qlogging/test/test.pro b/tests/auto/corelib/global/qlogging/test/test.pro index 8dafc4509c..91896d4494 100644 --- a/tests/auto/corelib/global/qlogging/test/test.pro +++ b/tests/auto/corelib/global/qlogging/test/test.pro @@ -4,14 +4,14 @@ qtConfig(c++14): CONFIG += c++14 debug_and_release { CONFIG(debug, debug|release) { TARGET = ../../debug/tst_qlogging - !winrt: TEST_HELPER_INSTALLS = ../debug/helper + !android:!winrt: TEST_HELPER_INSTALLS = ../debug/helper } else { TARGET = ../../release/tst_qlogging - !winrt: TEST_HELPER_INSTALLS = ../release/helper + !android:!winrt: TEST_HELPER_INSTALLS = ../release/helper } } else { TARGET = ../tst_qlogging - !winrt: TEST_HELPER_INSTALLS = ../helper + !android:!winrt: TEST_HELPER_INSTALLS = ../helper } QT = core testlib diff --git a/tests/auto/corelib/global/qlogging/tst_qlogging.cpp b/tests/auto/corelib/global/qlogging/tst_qlogging.cpp index 863582f498..d3ed1a6d0d 100644 --- a/tests/auto/corelib/global/qlogging/tst_qlogging.cpp +++ b/tests/auto/corelib/global/qlogging/tst_qlogging.cpp @@ -813,12 +813,19 @@ void tst_qmessagehandler::qMessagePattern() #if !QT_CONFIG(process) QSKIP("This test requires QProcess support"); #else +#ifdef Q_OS_ANDROID + QSKIP("This test crashes on Android"); +#endif QFETCH(QString, pattern); QFETCH(bool, valid); QFETCH(QList, expected); QProcess process; +#ifndef Q_OS_ANDROID const QString appExe(QLatin1String("helper")); +#else + const QString appExe(QCoreApplication::applicationDirPath() + QLatin1String("/libhelper.so")); +#endif // // test QT_MESSAGE_PATTERN @@ -855,13 +862,20 @@ void tst_qmessagehandler::setMessagePattern() #if !QT_CONFIG(process) QSKIP("This test requires QProcess support"); #else +#ifdef Q_OS_ANDROID + QSKIP("This test crashes on Android"); +#endif // // test qSetMessagePattern // QProcess process; +#ifndef Q_OS_ANDROID const QString appExe(QLatin1String("helper")); +#else + const QString appExe(QCoreApplication::applicationDirPath() + QLatin1String("/libhelper.so")); +#endif // make sure there is no QT_MESSAGE_PATTERN in the environment QStringList environment = m_baseEnvironment; diff --git a/tests/auto/corelib/io/io.pro b/tests/auto/corelib/io/io.pro index 5618a42203..5eab944fe4 100644 --- a/tests/auto/corelib/io/io.pro +++ b/tests/auto/corelib/io/io.pro @@ -64,3 +64,8 @@ win32:!qtConfig(private_tests): SUBDIRS -= \ winrt: SUBDIRS -= \ qstorageinfo + +android: SUBDIRS -= \ + qprocess \ + qdir \ + qresourceengine diff --git a/tests/auto/corelib/io/qdiriterator/qdiriterator.qrc b/tests/auto/corelib/io/qdiriterator/qdiriterator.qrc index 058d474780..af9998bdb4 100644 --- a/tests/auto/corelib/io/qdiriterator/qdiriterator.qrc +++ b/tests/auto/corelib/io/qdiriterator/qdiriterator.qrc @@ -1,5 +1,5 @@ - + entrylist/file entrylist/directory/dummy diff --git a/tests/auto/corelib/io/qdiriterator/tst_qdiriterator.cpp b/tests/auto/corelib/io/qdiriterator/tst_qdiriterator.cpp index a55989aacd..0b125925bb 100644 --- a/tests/auto/corelib/io/qdiriterator/tst_qdiriterator.cpp +++ b/tests/auto/corelib/io/qdiriterator/tst_qdiriterator.cpp @@ -120,7 +120,7 @@ void tst_QDirIterator::initTestCase() { #if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED) QString testdata_dir = QStandardPaths::writableLocation(QStandardPaths::CacheLocation); - QString resourceSourcePath = QStringLiteral(":/"); + QString resourceSourcePath = QStringLiteral(":/testdata"); QDirIterator it(resourceSourcePath, QDirIterator::Subdirectories); while (it.hasNext()) { it.next(); @@ -141,7 +141,7 @@ void tst_QDirIterator::initTestCase() testdata_dir += QStringLiteral("/entrylist"); #elif defined(BUILTIN_TESTDATA) - m_dataDir = QEXTRACTTESTDATA("/"); + m_dataDir = QEXTRACTTESTDATA("/testdata"); QVERIFY2(!m_dataDir.isNull(), qPrintable("Could not extract test data")); QString testdata_dir = m_dataDir->path(); #else @@ -399,18 +399,18 @@ void tst_QDirIterator::iterateResource_data() QTest::addColumn("nameFilters"); QTest::addColumn("entries"); - QTest::newRow("invalid") << QString::fromLatin1(":/burpaburpa") << QDirIterator::IteratorFlags(0) + QTest::newRow("invalid") << QString::fromLatin1(":/testdata/burpaburpa") << QDirIterator::IteratorFlags(0) << QDir::Filters(QDir::NoFilter) << QStringList(QLatin1String("*")) << QStringList(); - QTest::newRow(":/") << QString::fromLatin1(":/") << QDirIterator::IteratorFlags(0) + QTest::newRow(":/testdata") << QString::fromLatin1(":/testdata/") << QDirIterator::IteratorFlags(0) << QDir::Filters(QDir::NoFilter) << QStringList(QLatin1String("*")) - << QString::fromLatin1(":/entrylist").split(QLatin1String(",")); - QTest::newRow(":/entrylist") << QString::fromLatin1(":/entrylist") << QDirIterator::IteratorFlags(0) + << QString::fromLatin1(":/testdata/entrylist").split(QLatin1String(",")); + QTest::newRow(":/testdata/entrylist") << QString::fromLatin1(":/testdata/entrylist") << QDirIterator::IteratorFlags(0) << QDir::Filters(QDir::NoFilter) << QStringList(QLatin1String("*")) - << QString::fromLatin1(":/entrylist/directory,:/entrylist/file").split(QLatin1String(",")); - QTest::newRow(":/ recursive") << QString::fromLatin1(":/") << QDirIterator::IteratorFlags(QDirIterator::Subdirectories) + << QString::fromLatin1(":/testdata/entrylist/directory,:/testdata/entrylist/file").split(QLatin1String(",")); + QTest::newRow(":/testdata recursive") << QString::fromLatin1(":/testdata") << QDirIterator::IteratorFlags(QDirIterator::Subdirectories) << QDir::Filters(QDir::NoFilter) << QStringList(QLatin1String("*")) - << QString::fromLatin1(":/entrylist,:/entrylist/directory,:/entrylist/directory/dummy,:/entrylist/file").split(QLatin1String(",")); + << QString::fromLatin1(":/testdata/entrylist,:/testdata/entrylist/directory,:/testdata/entrylist/directory/dummy,:/testdata/entrylist/file").split(QLatin1String(",")); } void tst_QDirIterator::iterateResource() diff --git a/tests/auto/corelib/io/qfile/tst_qfile.cpp b/tests/auto/corelib/io/qfile/tst_qfile.cpp index a61b7cc573..41c9871e26 100644 --- a/tests/auto/corelib/io/qfile/tst_qfile.cpp +++ b/tests/auto/corelib/io/qfile/tst_qfile.cpp @@ -85,6 +85,12 @@ QT_END_NAMESPACE #include #include +#ifdef Q_OS_ANDROID +// Android introduces a braindamaged fileno macro that isn't +// compatible with the POSIX fileno or its own FILE type. +# undef fileno +#endif + #if defined(Q_OS_WIN) #include "../../../network-settings.h" #endif @@ -442,10 +448,12 @@ void tst_QFile::initTestCase() { QVERIFY2(m_temporaryDir.isValid(), qPrintable(m_temporaryDir.errorString())); #if QT_CONFIG(process) -#ifndef Q_OS_WIN - m_stdinProcess = QFINDTESTDATA("stdinprocess_helper"); -#else +#if defined(Q_OS_ANDROID) + m_stdinProcess = QCoreApplication::applicationDirPath() + QLatin1String("/libstdinprocess_helper.so"); +#elif defined(Q_OS_WIN) m_stdinProcess = QFINDTESTDATA("stdinprocess_helper.exe"); +#else + m_stdinProcess = QFINDTESTDATA("stdinprocess_helper"); #endif QVERIFY(!m_stdinProcess.isEmpty()); #endif @@ -962,6 +970,9 @@ void tst_QFile::readAllStdin() #if !QT_CONFIG(process) QSKIP("No qprocess support", SkipAll); #else +#if defined(Q_OS_ANDROID) + QSKIP("This test crashes when doing nanosleep. See QTBUG-69034."); +#endif QByteArray lotsOfData(1024, '@'); // 10 megs QProcess process; @@ -985,6 +996,9 @@ void tst_QFile::readLineStdin() #if !QT_CONFIG(process) QSKIP("No qprocess support", SkipAll); #else +#if defined(Q_OS_ANDROID) + QSKIP("This test crashes when doing nanosleep. See QTBUG-69034."); +#endif QByteArray lotsOfData(1024, '@'); // 10 megs for (int i = 0; i < lotsOfData.size(); ++i) { if ((i % 32) == 31) @@ -1026,6 +1040,9 @@ void tst_QFile::readLineStdin_lineByLine() #if !QT_CONFIG(process) QSKIP("No qprocess support", SkipAll); #else +#if defined(Q_OS_ANDROID) + QSKIP("This test crashes when calling ::poll. See QTBUG-69034."); +#endif for (int i = 0; i < 2; ++i) { QProcess process; StdinReaderProcessGuard processGuard(&process); diff --git a/tests/auto/corelib/itemmodels/qidentityproxymodel/tst_qidentityproxymodel.cpp b/tests/auto/corelib/itemmodels/qidentityproxymodel/tst_qidentityproxymodel.cpp index f8c5c92677..262c6dd9c8 100644 --- a/tests/auto/corelib/itemmodels/qidentityproxymodel/tst_qidentityproxymodel.cpp +++ b/tests/auto/corelib/itemmodels/qidentityproxymodel/tst_qidentityproxymodel.cpp @@ -26,9 +26,12 @@ ** ****************************************************************************/ -#include -#include -#include +#include +#include +#include +#include +#include +#include #include "dynamictreemodel.h" #include "qidentityproxymodel.h" @@ -76,6 +79,7 @@ protected: private: QStandardItemModel *m_model; QIdentityProxyModel *m_proxy; + QAbstractItemModelTester *m_modelTest; }; tst_QIdentityProxyModel::tst_QIdentityProxyModel() @@ -88,12 +92,14 @@ void tst_QIdentityProxyModel::initTestCase() qRegisterMetaType >(); m_model = new QStandardItemModel(0, 1); m_proxy = new QIdentityProxyModel(); + m_modelTest = new QAbstractItemModelTester(m_proxy, this); } void tst_QIdentityProxyModel::cleanupTestCase() { delete m_proxy; delete m_model; + delete m_modelTest; } void tst_QIdentityProxyModel::cleanup() diff --git a/tests/auto/corelib/itemmodels/qsortfilterproxymodel/tst_qsortfilterproxymodel.cpp b/tests/auto/corelib/itemmodels/qsortfilterproxymodel/tst_qsortfilterproxymodel.cpp index 9bc558580b..a9138a6505 100644 --- a/tests/auto/corelib/itemmodels/qsortfilterproxymodel/tst_qsortfilterproxymodel.cpp +++ b/tests/auto/corelib/itemmodels/qsortfilterproxymodel/tst_qsortfilterproxymodel.cpp @@ -1898,6 +1898,7 @@ void tst_QSortFilterProxyModel::changeSourceData_data() QTest::addColumn("sourceItems"); QTest::addColumn("sortOrder"); QTest::addColumn("filter"); + QTest::addColumn("expectedInitialProxyItems"); QTest::addColumn("dynamic"); QTest::addColumn("row"); QTest::addColumn("newValue"); @@ -1905,10 +1906,11 @@ void tst_QSortFilterProxyModel::changeSourceData_data() QTest::addColumn("insertIntervals"); QTest::addColumn("proxyItems"); - QTest::newRow("changeSourceData (1)") + QTest::newRow("move_to_end_ascending") << (QStringList() << "c" << "b" << "a") // sourceItems << static_cast(Qt::AscendingOrder) // sortOrder << "" // filter + << (QStringList() << "a" << "b" << "c") // expectedInitialProxyItems << true // dynamic << 2 // row << "z" // newValue @@ -1917,10 +1919,11 @@ void tst_QSortFilterProxyModel::changeSourceData_data() << (QStringList() << "b" << "c" << "z") // proxyItems ; - QTest::newRow("changeSourceData (2)") + QTest::newRow("move_to_end_descending") << (QStringList() << "b" << "c" << "z") // sourceItems << static_cast(Qt::DescendingOrder) // sortOrder << "" // filter + << (QStringList() << "z" << "c" << "b") // expectedInitialProxyItems << true // dynamic << 1 // row << "a" // newValue @@ -1929,10 +1932,11 @@ void tst_QSortFilterProxyModel::changeSourceData_data() << (QStringList() << "z" << "b" << "a") // proxyItems ; - QTest::newRow("changeSourceData (3)") + QTest::newRow("no_op_change") << (QStringList() << "a" << "b") // sourceItems << static_cast(Qt::DescendingOrder) // sortOrder << "" // filter + << (QStringList() << "b" << "a") // expectedInitialProxyItems << true // dynamic << 0 // row << "a" // newValue @@ -1941,10 +1945,11 @@ void tst_QSortFilterProxyModel::changeSourceData_data() << (QStringList() << "b" << "a") // proxyItems ; - QTest::newRow("changeSourceData (4)") + QTest::newRow("filtered_out_value_stays_out") << (QStringList() << "a" << "b" << "c" << "d") // sourceItems << static_cast(Qt::AscendingOrder) // sortOrder << "a|c" // filter + << (QStringList() << "a" << "c") // expectedInitialProxyItems << true // dynamic << 1 // row << "x" // newValue @@ -1953,10 +1958,11 @@ void tst_QSortFilterProxyModel::changeSourceData_data() << (QStringList() << "a" << "c") // proxyItems ; - QTest::newRow("changeSourceData (5)") + QTest::newRow("filtered_out_now_matches") << (QStringList() << "a" << "b" << "c" << "d") // sourceItems << static_cast(Qt::AscendingOrder) // sortOrder << "a|c|x" // filter + << (QStringList() << "a" << "c") // expectedInitialProxyItems << true // dynamic << 1 // row << "x" // newValue @@ -1965,10 +1971,24 @@ void tst_QSortFilterProxyModel::changeSourceData_data() << (QStringList() << "a" << "c" << "x") // proxyItems ; - QTest::newRow("changeSourceData (6)") + QTest::newRow("value_is_now_filtered_out") + << (QStringList() << "a" << "b" << "c" << "d") // sourceItems + << static_cast(Qt::AscendingOrder) // sortOrder + << "a|c" // filter + << (QStringList() << "a" << "c") // expectedInitialProxyItems + << true // dynamic + << 2 // row + << "x" // newValue + << (IntPairList() << IntPair(1, 1)) // removeIntervals + << IntPairList() // insertIntervals + << (QStringList() << "a") // proxyItems + ; + + QTest::newRow("non_dynamic_filter_does_not_update_sort") << (QStringList() << "c" << "b" << "a") // sourceItems << static_cast(Qt::AscendingOrder) // sortOrder << "" // filter + << (QStringList() << "a" << "b" << "c") // expectedInitialProxyItems << false // dynamic << 2 // row << "x" // newValue @@ -1983,6 +2003,7 @@ void tst_QSortFilterProxyModel::changeSourceData() QFETCH(QStringList, sourceItems); QFETCH(int, sortOrder); QFETCH(QString, filter); + QFETCH(QStringList, expectedInitialProxyItems); QFETCH(bool, dynamic); QFETCH(int, row); QFETCH(QString, newValue); @@ -2008,6 +2029,12 @@ void tst_QSortFilterProxyModel::changeSourceData() proxy.setFilterRegExp(filter); + QCOMPARE(proxy.rowCount(), expectedInitialProxyItems.count()); + for (int i = 0; i < expectedInitialProxyItems.count(); ++i) { + const QModelIndex index = proxy.index(i, 0, QModelIndex()); + QCOMPARE(proxy.data(index, Qt::DisplayRole).toString(), expectedInitialProxyItems.at(i)); + } + QSignalSpy removeSpy(&proxy, &QSortFilterProxyModel::rowsRemoved); QSignalSpy insertSpy(&proxy, &QSortFilterProxyModel::rowsInserted); diff --git a/tests/auto/corelib/kernel/kernel.pro b/tests/auto/corelib/kernel/kernel.pro index b5b64973d3..09074a9e8a 100644 --- a/tests/auto/corelib/kernel/kernel.pro +++ b/tests/auto/corelib/kernel/kernel.pro @@ -40,7 +40,7 @@ SUBDIRS=\ # This test is only applicable on Windows !win32*|winrt: SUBDIRS -= qwineventnotifier -android|uikit: SUBDIRS -= qclipboard qobject qsharedmemory qsystemsemaphore +android|uikit: SUBDIRS -= qobject qsharedmemory qsystemsemaphore !qtConfig(systemsemaphore): SUBDIRS -= \ qsystemsemaphore diff --git a/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp b/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp index c6fd5d17c2..e312199980 100644 --- a/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp +++ b/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp @@ -1696,11 +1696,21 @@ public: Q_ENUM(MyEnum) }; +class MyQObjectFromGadget : public QObject, public MyGadget +{ + Q_OBJECT +public: + MyQObjectFromGadget(QObject *parent = 0) + : QObject(parent) + {} +}; + Q_DECLARE_METATYPE(MyGadget); Q_DECLARE_METATYPE(MyGadget*); Q_DECLARE_METATYPE(const QMetaObject *); Q_DECLARE_METATYPE(Qt::ScrollBarPolicy); Q_DECLARE_METATYPE(MyGadget::MyEnum); +Q_DECLARE_METATYPE(MyQObjectFromGadget*); void tst_QMetaType::metaObject_data() { @@ -1719,6 +1729,7 @@ void tst_QMetaType::metaObject_data() QTest::newRow("MyGadget*") << ::qMetaTypeId() << &MyGadget::staticMetaObject << false << true << false; QTest::newRow("MyEnum") << ::qMetaTypeId() << &MyGadget::staticMetaObject << false << false << false; QTest::newRow("Qt::ScrollBarPolicy") << ::qMetaTypeId() << &QObject::staticQtMetaObject << false << false << false; + QTest::newRow("MyQObjectFromGadget*") << ::qMetaTypeId() << &MyQObjectFromGadget::staticMetaObject << false << false << true; QTest::newRow("GadgetDerivedAndTyped") << ::qMetaTypeId>() << &GadgetDerivedAndTyped::staticMetaObject << true << false << false; QTest::newRow("GadgetDerivedAndTyped*") << ::qMetaTypeId*>() << &GadgetDerivedAndTyped::staticMetaObject << false << true << false; diff --git a/tests/auto/corelib/kernel/qtimer/tst_qtimer.cpp b/tests/auto/corelib/kernel/qtimer/tst_qtimer.cpp index 2d34aceab8..f004ec7856 100644 --- a/tests/auto/corelib/kernel/qtimer/tst_qtimer.cpp +++ b/tests/auto/corelib/kernel/qtimer/tst_qtimer.cpp @@ -78,102 +78,65 @@ private slots: void connectTo(); }; -class TimerHelper : public QObject -{ - Q_OBJECT -public: - TimerHelper() : QObject(), count(0), remainingTime(-1) - { - } - - int count; - int remainingTime; - -public slots: - void timeout(); - void fetchRemainingTime(); -}; - -void TimerHelper::timeout() -{ - ++count; -} - -void TimerHelper::fetchRemainingTime() -{ - QTimer *timer = static_cast(sender()); - remainingTime = timer->remainingTime(); -} - void tst_QTimer::zeroTimer() { - TimerHelper helper; QTimer timer; timer.setInterval(0); - timer.start(); - connect(&timer, SIGNAL(timeout()), &helper, SLOT(timeout())); + QSignalSpy timeoutSpy(&timer, &QTimer::timeout); + timer.start(); QCoreApplication::processEvents(); - QCOMPARE(helper.count, 1); + QCOMPARE(timeoutSpy.count(), 1); } void tst_QTimer::singleShotTimeout() { - TimerHelper helper; QTimer timer; timer.setSingleShot(true); - connect(&timer, SIGNAL(timeout()), &helper, SLOT(timeout())); + QSignalSpy timeoutSpy(&timer, &QTimer::timeout); timer.start(100); + QVERIFY(timeoutSpy.wait(500)); + QCOMPARE(timeoutSpy.count(), 1); QTest::qWait(500); - QCOMPARE(helper.count, 1); - QTest::qWait(500); - QCOMPARE(helper.count, 1); + QCOMPARE(timeoutSpy.count(), 1); } #define TIMEOUT_TIMEOUT 200 void tst_QTimer::timeout() { - TimerHelper helper; QTimer timer; - - connect(&timer, SIGNAL(timeout()), &helper, SLOT(timeout())); + QSignalSpy timeoutSpy(&timer, &QTimer::timeout); timer.start(100); - QCOMPARE(helper.count, 0); + QCOMPARE(timeoutSpy.count(), 0); - QTRY_VERIFY_WITH_TIMEOUT(helper.count > 0, TIMEOUT_TIMEOUT); - int oldCount = helper.count; + QTRY_VERIFY_WITH_TIMEOUT(timeoutSpy.count() > 0, TIMEOUT_TIMEOUT); + int oldCount = timeoutSpy.count(); - QTRY_VERIFY_WITH_TIMEOUT(helper.count > oldCount, TIMEOUT_TIMEOUT); + QTRY_VERIFY_WITH_TIMEOUT(timeoutSpy.count() > oldCount, TIMEOUT_TIMEOUT); } void tst_QTimer::remainingTime() { - TimerHelper helper; QTimer timer; - - connect(&timer, SIGNAL(timeout()), &helper, SLOT(timeout())); + QSignalSpy timeoutSpy(&timer, &QTimer::timeout); timer.setTimerType(Qt::PreciseTimer); timer.start(200); - QCOMPARE(helper.count, 0); - + QCOMPARE(timeoutSpy.count(), 0); QTest::qWait(50); - QCOMPARE(helper.count, 0); + QCOMPARE(timeoutSpy.count(), 0); int remainingTime = timer.remainingTime(); QVERIFY2(qAbs(remainingTime - 150) < 50, qPrintable(QString::number(remainingTime))); - // wait for the timer to actually fire now - connect(&timer, SIGNAL(timeout()), &QTestEventLoop::instance(), SLOT(exitLoop())); - QTestEventLoop::instance().enterLoop(5); - QVERIFY(!QTestEventLoop::instance().timeout()); - QCOMPARE(helper.count, 1); + QVERIFY(timeoutSpy.wait()); + QCOMPARE(timeoutSpy.count(), 1); // the timer is still active, so it should have a non-zero remaining time remainingTime = timer.remainingTime(); @@ -183,7 +146,7 @@ void tst_QTimer::remainingTime() void tst_QTimer::remainingTimeDuringActivation_data() { QTest::addColumn("singleShot"); - QTest::newRow("repeating") << true; + QTest::newRow("repeating") << false; QTest::newRow("single-shot") << true; } @@ -191,29 +154,31 @@ void tst_QTimer::remainingTimeDuringActivation() { QFETCH(bool, singleShot); - TimerHelper helper; QTimer timer; - - const int timeout = 20; // 20 ms is short enough and should not round down to 0 in any timer mode - - connect(&timer, SIGNAL(timeout()), &helper, SLOT(fetchRemainingTime())); - connect(&timer, SIGNAL(timeout()), &QTestEventLoop::instance(), SLOT(exitLoop())); - timer.start(timeout); timer.setSingleShot(singleShot); - QTestEventLoop::instance().enterLoop(5); - QVERIFY(!QTestEventLoop::instance().timeout()); + int remainingTime = 0; // not the expected value in either case + connect(&timer, &QTimer::timeout, + [&]() { + remainingTime = timer.remainingTime(); + }); + QSignalSpy timeoutSpy(&timer, &QTimer::timeout); + const int timeout = 20; // 20 ms is short enough and should not round down to 0 in any timer mode + timer.start(timeout); + + QVERIFY(timeoutSpy.wait()); if (singleShot) - QCOMPARE(helper.remainingTime, -1); // timer not running + QCOMPARE(remainingTime, -1); // timer not running else - QCOMPARE(helper.remainingTime, timeout); + QVERIFY2(remainingTime <= timeout && remainingTime > 0, + qPrintable(QString::number(remainingTime))); if (!singleShot) { // do it again - see QTBUG-46940 - helper.remainingTime = -1; - QTestEventLoop::instance().enterLoop(5); - QVERIFY(!QTestEventLoop::instance().timeout()); - QCOMPARE(helper.remainingTime, timeout); + remainingTime = -1; + QVERIFY(timeoutSpy.wait()); + QVERIFY2(remainingTime <= timeout && remainingTime > 0, + qPrintable(QString::number(remainingTime))); } } @@ -234,47 +199,44 @@ void tst_QTimer::basic_chrono() #else // duplicates zeroTimer, singleShotTimeout, interval and remainingTime using namespace std::chrono; - TimerHelper helper; QTimer timer; + QSignalSpy timeoutSpy(&timer, &QTimer::timeout); timer.setInterval(to_ms(nanoseconds(0))); timer.start(); QCOMPARE(timer.intervalAsDuration().count(), milliseconds::rep(0)); QCOMPARE(timer.remainingTimeAsDuration().count(), milliseconds::rep(0)); - connect(&timer, SIGNAL(timeout()), &helper, SLOT(timeout())); - QCoreApplication::processEvents(); - QCOMPARE(helper.count, 1); + QCOMPARE(timeoutSpy.count(), 1); - helper.count = 0; + timeoutSpy.clear(); timer.start(milliseconds(100)); - QCOMPARE(helper.count, 0); + QCOMPARE(timeoutSpy.count(), 0); - QTest::qWait(TIMEOUT_TIMEOUT); - QVERIFY(helper.count > 0); - int oldCount = helper.count; + QVERIFY(timeoutSpy.wait(TIMEOUT_TIMEOUT)); + QVERIFY(timeoutSpy.count() > 0); + int oldCount = timeoutSpy.count(); - QTest::qWait(TIMEOUT_TIMEOUT); - QVERIFY(helper.count > oldCount); + QVERIFY(timeoutSpy.wait(TIMEOUT_TIMEOUT)); + QVERIFY(timeoutSpy.count() > oldCount); - helper.count = 0; + timeoutSpy.clear(); timer.start(to_ms(microseconds(200000))); QCOMPARE(timer.intervalAsDuration().count(), milliseconds::rep(200)); QTest::qWait(50); - QCOMPARE(helper.count, 0); + QCOMPARE(timeoutSpy.count(), 0); milliseconds rt = timer.remainingTimeAsDuration(); QVERIFY2(qAbs(rt.count() - 150) < 50, qPrintable(QString::number(rt.count()))); - helper.count = 0; + timeoutSpy.clear(); timer.setSingleShot(true); timer.start(milliseconds(100)); + QVERIFY(timeoutSpy.wait(TIMEOUT_TIMEOUT)); + QCOMPARE(timeoutSpy.count(), 1); QTest::qWait(500); - QCOMPARE(helper.count, 1); - QTest::qWait(500); - QCOMPARE(helper.count, 1); - helper.count = 0; + QCOMPARE(timeoutSpy.count(), 1); #endif } @@ -449,47 +411,40 @@ signals: void tst_QTimer::recurringTimer_data() { QTest::addColumn("interval"); - QTest::newRow("zero timer") << 0; - QTest::newRow("non-zero timer") << 1; + QTest::addColumn("recurse"); + // make sure that eventloop recursion doesn't affect timer recurrence + QTest::newRow("zero timer, don't recurse") << 0 << false; + QTest::newRow("zero timer, recurse") << 0 << true; + QTest::newRow("non-zero timer, don't recurse") << 1 << false; + QTest::newRow("non-zero timer, recurse") << 1 << true; } void tst_QTimer::recurringTimer() { const int target = 5; QFETCH(int, interval); + QFETCH(bool, recurse); - { - RecurringTimerObject object(target); - QObject::connect(&object, SIGNAL(done()), &QTestEventLoop::instance(), SLOT(exitLoop())); - (void) object.startTimer(interval); - QTestEventLoop::instance().enterLoop(5); + RecurringTimerObject object(target); + object.recurse = recurse; + QSignalSpy doneSpy(&object, &RecurringTimerObject::done); - QCOMPARE(object.times, target); - } + (void) object.startTimer(interval); + QVERIFY(doneSpy.wait()); - { - // make sure that eventloop recursion doesn't effect timer recurrance - RecurringTimerObject object(target); - object.recurse = true; - - QObject::connect(&object, SIGNAL(done()), &QTestEventLoop::instance(), SLOT(exitLoop())); - (void) object.startTimer(interval); - QTestEventLoop::instance().enterLoop(5); - - QCOMPARE(object.times, target); - } + QCOMPARE(object.times, target); } void tst_QTimer::deleteLaterOnQTimer() { QTimer *timer = new QTimer; connect(timer, SIGNAL(timeout()), timer, SLOT(deleteLater())); - connect(timer, SIGNAL(destroyed()), &QTestEventLoop::instance(), SLOT(exitLoop())); + QSignalSpy destroyedSpy(timer, &QObject::destroyed); timer->setInterval(1); timer->setSingleShot(true); timer->start(); QPointer pointer = timer; - QTestEventLoop::instance().enterLoop(5); + QVERIFY(destroyedSpy.wait()); QVERIFY(pointer.isNull()); } @@ -691,23 +646,34 @@ void tst_QTimer::cancelLongTimer() QVERIFY(!timer.isActive()); } +class TimeoutCounter : public QObject +{ + Q_OBJECT +public slots: + void timeout() { ++count; }; +public: + int count = 0; +}; + void tst_QTimer::singleShotStaticFunctionZeroTimeout() { - TimerHelper helper; + { + TimeoutCounter counter; - QTimer::singleShot(0, &helper, SLOT(timeout())); - QTest::qWait(500); - QCOMPARE(helper.count, 1); - QTest::qWait(500); - QCOMPARE(helper.count, 1); + QTimer::singleShot(0, &counter, SLOT(timeout())); + QTRY_COMPARE(counter.count, 1); + QTest::qWait(500); + QCOMPARE(counter.count, 1); + } - TimerHelper nhelper; + { + TimeoutCounter counter; - QTimer::singleShot(0, &nhelper, &TimerHelper::timeout); - QCoreApplication::processEvents(); - QCOMPARE(nhelper.count, 1); - QCoreApplication::processEvents(); - QCOMPARE(nhelper.count, 1); + QTimer::singleShot(0, &counter, &TimeoutCounter::timeout); + QTRY_COMPARE(counter.count, 1); + QTest::qWait(500); + QCOMPARE(counter.count, 1); + } } class RecursOnTimeoutAndStopTimerTimer : public QObject @@ -808,8 +774,7 @@ void tst_QTimer::singleShotToFunctors() QCOMPARE(e.exec(), 0); QTimer::singleShot(0, &c1, CountedStruct(&count, &t1)); - QTest::qWait(500); - QCOMPARE(count, 2); + QTRY_COMPARE(count, 2); t1.quit(); t1.wait(); @@ -834,12 +799,11 @@ void tst_QTimer::singleShotToFunctors() QObject c3; QTimer::singleShot(500, &c3, CountedStruct(&count)); } - QTest::qWait(800); + QTest::qWait(800); // Wait until the singleshot timer would have timed out QCOMPARE(count, 2); QTimer::singleShot(0, [&count] { ++count; }); - QCoreApplication::processEvents(); - QCOMPARE(count, 3); + QTRY_COMPARE(count, 3); QObject context; QThread thread; @@ -850,8 +814,7 @@ void tst_QTimer::singleShotToFunctors() QCOMPARE(e.exec(), 0); QTimer::singleShot(0, &context, [&count, &thread] { ++count; QCOMPARE(QThread::currentThread(), &thread); }); - QTest::qWait(500); - QCOMPARE(count, 4); + QTRY_COMPARE(count, 4); thread.quit(); thread.wait(); @@ -862,8 +825,7 @@ void tst_QTimer::singleShotToFunctors() MoveOnly(int *c) : CountedStruct(c) {} }; QTimer::singleShot(0, MoveOnly(&count)); - QCoreApplication::processEvents(); - QCOMPARE(count, 5); + QTRY_COMPARE(count, 5); _e.reset(); _t = nullptr; @@ -876,26 +838,27 @@ void tst_QTimer::singleShot_chrono() #else // duplicates singleShotStaticFunctionZeroTimeout and singleShotToFunctors using namespace std::chrono; - TimerHelper helper; + { + TimeoutCounter counter; - QTimer::singleShot(hours(0), &helper, SLOT(timeout())); - QTest::qWait(500); - QCOMPARE(helper.count, 1); - QTest::qWait(500); - QCOMPARE(helper.count, 1); + QTimer::singleShot(hours(0), &counter, SLOT(timeout())); + QTRY_COMPARE(counter.count, 1); + QTest::qWait(500); + QCOMPARE(counter.count, 1); + } - TimerHelper nhelper; + { + TimeoutCounter counter; - QTimer::singleShot(seconds(0), &nhelper, &TimerHelper::timeout); - QCoreApplication::processEvents(); - QCOMPARE(nhelper.count, 1); - QCoreApplication::processEvents(); - QCOMPARE(nhelper.count, 1); + QTimer::singleShot(hours(0), &counter, &TimeoutCounter::timeout); + QTRY_COMPARE(counter.count, 1); + QTest::qWait(500); + QCOMPARE(counter.count, 1); + } int count = 0; QTimer::singleShot(to_ms(microseconds(0)), CountedStruct(&count)); - QCoreApplication::processEvents(); - QCOMPARE(count, 1); + QTRY_COMPARE(count, 1); _e.reset(new QEventLoop); QTimer::singleShot(0, &StaticEventLoop::quitEventLoop); @@ -903,12 +866,10 @@ void tst_QTimer::singleShot_chrono() QObject c3; QTimer::singleShot(milliseconds(500), &c3, CountedStruct(&count)); - QTest::qWait(800); - QCOMPARE(count, 2); + QTRY_COMPARE(count, 2); QTimer::singleShot(0, [&count] { ++count; }); - QCoreApplication::processEvents(); - QCOMPARE(count, 3); + QTRY_COMPARE(count, 3); _e.reset(); #endif @@ -986,16 +947,14 @@ public slots: void tst_QTimer::postedEventsShouldNotStarveTimers() { - TimerHelper timerHelper; QTimer timer; - connect(&timer, SIGNAL(timeout()), &timerHelper, SLOT(timeout())); timer.setInterval(0); timer.setSingleShot(false); + QSignalSpy timeoutSpy(&timer, &QTimer::timeout); timer.start(); SlotRepeater slotRepeater; slotRepeater.repeatThisSlot(); - QTest::qWait(100); - QVERIFY(timerHelper.count > 5); + QTRY_VERIFY_WITH_TIMEOUT(timeoutSpy.count() > 5, 100); } struct DummyFunctor { @@ -1024,7 +983,7 @@ void tst_QTimer::crossThreadSingleShotToFunctor() void tst_QTimer::connectTo() { QTimer timer; - TimerHelper timerHelper; + QSignalSpy timeoutSpy(&timer, &QTimer::timeout); timer.setInterval(0); timer.start(); @@ -1033,13 +992,12 @@ void tst_QTimer::connectTo() int count = 0; timer.connectTo([&count] { count++; }); QMetaObject::Connection connection = timer.connectTo(context, [&count] { count++; }); - timer.connectTo(&timerHelper, &TimerHelper::timeout); timer.connectTo(&timer, &QTimer::stop); QTest::qWait(100); QCOMPARE(count, 2); - QCOMPARE(timerHelper.count, 1); + QCOMPARE(timeoutSpy.count(), 1); // Test that connection is bound to context lifetime QVERIFY(connection); diff --git a/tests/auto/corelib/plugin/qlibrary/tst/tst.pro b/tests/auto/corelib/plugin/qlibrary/tst/tst.pro index 6e71ec8ff9..56bef14405 100644 --- a/tests/auto/corelib/plugin/qlibrary/tst/tst.pro +++ b/tests/auto/corelib/plugin/qlibrary/tst/tst.pro @@ -12,3 +12,14 @@ win32 { } TESTDATA += ../library_path/invalid.so + +android { + libs.prefix = android_test_data + libs.base = $$OUT_PWD/.. + libs.files += $$OUT_PWD/../libmylib.so \ + $$OUT_PWD/../libmylib.so2 \ + $$OUT_PWD/../libmylib.prl \ + $$OUT_PWD/../system.qt.test.mylib.so + + RESOURCES += libs +} diff --git a/tests/auto/corelib/plugin/qlibrary/tst_qlibrary.cpp b/tests/auto/corelib/plugin/qlibrary/tst_qlibrary.cpp index 72d60d71c7..c9c9202a80 100644 --- a/tests/auto/corelib/plugin/qlibrary/tst_qlibrary.cpp +++ b/tests/auto/corelib/plugin/qlibrary/tst_qlibrary.cpp @@ -88,12 +88,6 @@ # define PREFIX "lib" #endif -static QString sys_qualifiedLibraryName(const QString &fileName) -{ - QString appDir = QCoreApplication::applicationDirPath(); - return appDir + QLatin1Char('/') + PREFIX + fileName + SUFFIX; -} - QT_FORWARD_DECLARE_CLASS(QLibrary) class tst_QLibrary : public QObject { @@ -106,6 +100,13 @@ enum QLibraryOperation { OperationMask = 7, DontSetFileName = 0x100 }; + + QString sys_qualifiedLibraryName(const QString &fileName); + + QString directory; +#ifdef Q_OS_ANDROID + QSharedPointer temporaryDir; +#endif private slots: void initTestCase(); @@ -130,19 +131,49 @@ private slots: void multipleInstancesForOneLibrary(); }; +QString tst_QLibrary::sys_qualifiedLibraryName(const QString &fileName) +{ + return directory + QLatin1Char('/') + PREFIX + fileName + SUFFIX; +} + typedef int (*VersionFunction)(void); void tst_QLibrary::initTestCase() { -#ifndef Q_OS_WINRT +#ifdef Q_OS_ANDROID + auto tempDir = QEXTRACTTESTDATA("android_test_data"); + + QVERIFY2(QDir::setCurrent(tempDir->path()), qPrintable("Could not chdir to " + tempDir->path())); + + // copy :/library_path into ./library_path + QVERIFY(QDir().mkdir("library_path")); + QDirIterator iterator(":/library_path", QDirIterator::Subdirectories); + while (iterator.hasNext()) { + iterator.next(); + QFileInfo sourceFileInfo(iterator.path()); + QFileInfo targetFileInfo("./library_path/" + sourceFileInfo.fileName()); + if (!targetFileInfo.exists()) { + QDir().mkpath(targetFileInfo.path()); + QVERIFY(QFile::copy(sourceFileInfo.filePath(), targetFileInfo.filePath())); + } + } + directory = tempDir->path(); + temporaryDir = std::move(tempDir); +#elif !defined(Q_OS_WINRT) // chdir to our testdata directory, and use relative paths in some tests. QString testdatadir = QFileInfo(QFINDTESTDATA("library_path")).absolutePath(); QVERIFY2(QDir::setCurrent(testdatadir), qPrintable("Could not chdir to " + testdatadir)); + directory = QCoreApplication::applicationDirPath(); +#elif defined(Q_OS_WINRT) + directory = QCoreApplication::applicationDirPath(); #endif } void tst_QLibrary::version_data() { +#ifdef Q_OS_ANDROID + QSKIP("Versioned .so files are not generated for Android, so this test is not applicable."); +#endif QTest::addColumn("lib"); QTest::addColumn("loadversion"); QTest::addColumn("resultversion"); @@ -159,7 +190,7 @@ void tst_QLibrary::version() QFETCH( int, resultversion ); #if !defined(Q_OS_AIX) && !defined(Q_OS_WIN) - QString appDir = QCoreApplication::applicationDirPath(); + QString appDir = directory; QLibrary library( appDir + QLatin1Char('/') + lib, loadversion ); QVERIFY2(library.load(), qPrintable(library.errorString())); @@ -179,7 +210,7 @@ void tst_QLibrary::load_data() QTest::addColumn("lib"); QTest::addColumn("result"); - QString appDir = QCoreApplication::applicationDirPath(); + QString appDir = directory; QTest::newRow( "ok00" ) << appDir + "/mylib" << true; QTest::newRow( "notexist" ) << appDir + "/nolib" << false; @@ -220,7 +251,7 @@ void tst_QLibrary::unload_data() QTest::addColumn("lib"); QTest::addColumn("result"); - QString appDir = QCoreApplication::applicationDirPath(); + QString appDir = directory; QTest::newRow( "mylib" ) << appDir + "/mylib" << true; QTest::newRow( "ok01" ) << appDir + "/nolib" << false; @@ -243,7 +274,7 @@ void tst_QLibrary::unload() void tst_QLibrary::unload_after_implicit_load() { - QLibrary library( QCoreApplication::applicationDirPath() + "/mylib" ); + QLibrary library( directory + "/mylib" ); QFunctionPointer p = library.resolve("mylibversion"); QVERIFY(p); // Check if it was loaded QVERIFY(library.isLoaded()); @@ -257,7 +288,7 @@ void tst_QLibrary::resolve_data() QTest::addColumn("symbol"); QTest::addColumn("goodPointer"); - QString appDir = QCoreApplication::applicationDirPath(); + QString appDir = directory; QTest::newRow( "ok00" ) << appDir + "/mylib" << QString("mylibversion") << true; QTest::newRow( "bad00" ) << appDir + "/mylib" << QString("nosym") << false; @@ -333,7 +364,7 @@ void tst_QLibrary::errorString_data() QTest::addColumn("success"); QTest::addColumn("errorString"); - QString appDir = QCoreApplication::applicationDirPath(); + QString appDir = directory; QTest::newRow("bad load()") << (int)Load << QString("nosuchlib") << false << QString("Cannot load library nosuchlib: .*"); QTest::newRow("call errorString() on QLibrary with no d-pointer (crashtest)") << (int)(Load | DontSetFileName) << QString() << false << QString("Unknown error"); @@ -398,7 +429,7 @@ void tst_QLibrary::loadHints_data() QLibrary::LoadHints lh; - QString appDir = QCoreApplication::applicationDirPath(); + QString appDir = directory; lh |= QLibrary::ResolveAllSymbolsHint; # if defined(Q_OS_WIN32) || defined(Q_OS_WINRT) @@ -477,7 +508,7 @@ void tst_QLibrary::fileName() void tst_QLibrary::multipleInstancesForOneLibrary() { - QString lib = QCoreApplication::applicationDirPath() + "/mylib"; + QString lib = directory + "/mylib"; { QLibrary lib1(lib); diff --git a/tests/auto/corelib/plugin/quuid/tst_quuid.cpp b/tests/auto/corelib/plugin/quuid/tst_quuid.cpp index bad72c081b..16552059dd 100644 --- a/tests/auto/corelib/plugin/quuid/tst_quuid.cpp +++ b/tests/auto/corelib/plugin/quuid/tst_quuid.cpp @@ -94,7 +94,11 @@ void tst_QUuid::initTestCase() #if QT_CONFIG(process) // chdir to the directory containing our testdata, then refer to it with relative paths +#ifdef Q_OS_ANDROID + QString testdata_dir = QCoreApplication::applicationDirPath(); +#else // !Q_OS_ANDROID QString testdata_dir = QFileInfo(QFINDTESTDATA("testProcessUniqueness")).absolutePath(); +#endif QVERIFY2(QDir::setCurrent(testdata_dir), qPrintable("Could not chdir to " + testdata_dir)); #endif @@ -401,6 +405,9 @@ void tst_QUuid::processUniqueness() #if !QT_CONFIG(process) QSKIP("No qprocess support", SkipAll); #else +#ifdef Q_OS_ANDROID + QSKIP("This test crashes on Android"); +#endif QProcess process; QString processOneOutput; QString processTwoOutput; @@ -408,6 +415,8 @@ void tst_QUuid::processUniqueness() // Start it once #ifdef Q_OS_MAC process.start("testProcessUniqueness/testProcessUniqueness.app"); +#elif defined(Q_OS_ANDROID) + process.start("libtestProcessUniqueness.so"); #else process.start("testProcessUniqueness/testProcessUniqueness"); #endif @@ -417,6 +426,8 @@ void tst_QUuid::processUniqueness() // Start it twice #ifdef Q_OS_MAC process.start("testProcessUniqueness/testProcessUniqueness.app"); +#elif defined(Q_OS_ANDROID) + process.start("libtestProcessUniqueness.so"); #else process.start("testProcessUniqueness/testProcessUniqueness"); #endif diff --git a/tests/auto/corelib/thread/qthread/tst_qthread.cpp b/tests/auto/corelib/thread/qthread/tst_qthread.cpp index aee243d880..d73dcc1b6d 100644 --- a/tests/auto/corelib/thread/qthread/tst_qthread.cpp +++ b/tests/auto/corelib/thread/qthread/tst_qthread.cpp @@ -465,8 +465,8 @@ void tst_QThread::start() void tst_QThread::terminate() { -#if defined(Q_OS_WINRT) - QSKIP("Thread termination is not supported on WinRT."); +#if defined(Q_OS_WINRT) || defined(Q_OS_ANDROID) + QSKIP("Thread termination is not supported on WinRT or Android."); #endif Terminate_Thread thread; { @@ -531,8 +531,8 @@ void tst_QThread::finished() void tst_QThread::terminated() { -#if defined(Q_OS_WINRT) - QSKIP("Thread termination is not supported on WinRT."); +#if defined(Q_OS_WINRT) || defined(Q_OS_ANDROID) + QSKIP("Thread termination is not supported on WinRT or Android."); #endif SignalRecorder recorder; Terminate_Thread thread; diff --git a/tests/auto/corelib/thread/qthreadpool/tst_qthreadpool.cpp b/tests/auto/corelib/thread/qthreadpool/tst_qthreadpool.cpp index 1092216fb7..838431cd5a 100644 --- a/tests/auto/corelib/thread/qthreadpool/tst_qthreadpool.cpp +++ b/tests/auto/corelib/thread/qthreadpool/tst_qthreadpool.cpp @@ -32,6 +32,10 @@ #include #include +#ifdef Q_OS_UNIX +#include +#endif + typedef void (*FunctionPointer)(); class FunctionPointerTask : public QRunnable @@ -1145,6 +1149,10 @@ void tst_QThreadPool::destroyingWaitsForTasksToFinish() // stack size used by the native thread. void tst_QThreadPool::stackSize() { +#if defined(Q_OS_UNIX) && !(defined(_POSIX_THREAD_ATTR_STACKSIZE) && (_POSIX_THREAD_ATTR_STACKSIZE-0 > 0)) + QSKIP("Setting stack size is unsupported on this platform."); +#endif + uint targetStackSize = 512 * 1024; uint threadStackSize = 1; // impossible value diff --git a/tests/auto/corelib/thread/qthreadstorage/qthreadstorage.pro b/tests/auto/corelib/thread/qthreadstorage/qthreadstorage.pro index 75898f6add..432c564ba1 100644 --- a/tests/auto/corelib/thread/qthreadstorage/qthreadstorage.pro +++ b/tests/auto/corelib/thread/qthreadstorage/qthreadstorage.pro @@ -1,6 +1,6 @@ TEMPLATE = subdirs -!winrt { +!android:!winrt { test.depends = crashonexit SUBDIRS += crashonexit } diff --git a/tests/auto/corelib/thread/qthreadstorage/test/test.pro b/tests/auto/corelib/thread/qthreadstorage/test/test.pro index 79ac2e5405..d2f21f48f0 100644 --- a/tests/auto/corelib/thread/qthreadstorage/test/test.pro +++ b/tests/auto/corelib/thread/qthreadstorage/test/test.pro @@ -2,17 +2,15 @@ CONFIG += testcase debug_and_release { CONFIG(debug, debug|release) { TARGET = ../../debug/tst_qthreadstorage - !winrt: TEST_HELPER_INSTALLS = ../../debug/crashonexit_helper + !android:!winrt: TEST_HELPER_INSTALLS = ../../debug/crashonexit_helper } else { TARGET = ../../release/tst_qthreadstorage - !winrt: TEST_HELPER_INSTALLS = ../../release/crashonexit_helper + !android:!winrt: TEST_HELPER_INSTALLS = ../../release/crashonexit_helper } } else { TARGET = ../tst_qthreadstorage - !winrt: TEST_HELPER_INSTALLS = ../crashonexit_helper + !android:!winrt: TEST_HELPER_INSTALLS = ../crashonexit_helper } CONFIG += console QT = core testlib SOURCES = ../tst_qthreadstorage.cpp - - diff --git a/tests/auto/corelib/tools/qdatetime/tst_qdatetime.cpp b/tests/auto/corelib/tools/qdatetime/tst_qdatetime.cpp index f8432b8472..10856a4d57 100644 --- a/tests/auto/corelib/tools/qdatetime/tst_qdatetime.cpp +++ b/tests/auto/corelib/tools/qdatetime/tst_qdatetime.cpp @@ -924,12 +924,16 @@ void tst_QDateTime::toString_textDate_extra() else QCOMPARE(dt.toString(), QLatin1String("Thu Jan 1 00:00:00 1970")); #if QT_CONFIG(timezone) +# if defined Q_OS_UNIX && !defined Q_OS_DARWIN && !defined Q_OS_ANDROID +# define CORRECT_ZONE_ABBREV +# endif // QTBUG-57320, QTBUG-57298, QTBUG-68833 + QTimeZone PST("America/Vancouver"); if (PST.isValid()) { dt = QDateTime::fromMSecsSinceEpoch(0, PST); -# if defined Q_OS_UNIX && !defined Q_OS_DARWIN +# ifdef CORRECT_ZONE_ABBREV QCOMPARE(dt.toString(), QLatin1String("Wed Dec 31 16:00:00 1969 PST")); -# else // QTBUG-57320, QTBUG-57298 +# else QVERIFY(dt.toString().startsWith(QLatin1String("Wed Dec 31 16:00:00 1969 "))); # endif dt = dt.toLocalTime(); @@ -940,9 +944,9 @@ void tst_QDateTime::toString_textDate_extra() QTimeZone CET("Europe/Berlin"); if (CET.isValid()) { dt = QDateTime::fromMSecsSinceEpoch(0, CET); -# if defined Q_OS_UNIX && !defined Q_OS_DARWIN +# ifdef CORRECT_ZONE_ABBREV QCOMPARE(dt.toString(), QLatin1String("Thu Jan 1 01:00:00 1970 CET")); -# else // QTBUG-57320, QTBUG-57298 +# else QVERIFY(dt.toString().startsWith(QLatin1String("Thu Jan 1 01:00:00 1970 "))); # endif dt = dt.toLocalTime(); @@ -1864,12 +1868,14 @@ void tst_QDateTime::springForward() QFETCH(int, adjust); QDateTime direct = QDateTime(day.addDays(-step), time, Qt::LocalTime).addDays(step); - QCOMPARE(direct.date(), day); - QCOMPARE(direct.time().minute(), time.minute()); - QCOMPARE(direct.time().second(), time.second()); - int off = direct.time().hour() - time.hour(); - QVERIFY(off == 1 || off == -1); - // Note: function doc claims always +1, but this should be reviewed ! + if (direct.isValid()) { // mktime() may deem a time in the gap invalid + QCOMPARE(direct.date(), day); + QCOMPARE(direct.time().minute(), time.minute()); + QCOMPARE(direct.time().second(), time.second()); + int off = direct.time().hour() - time.hour(); + QVERIFY(off == 1 || off == -1); + // Note: function doc claims always +1, but this should be reviewed ! + } // Repeat, but getting there via .toLocalTime(): QDateTime detour = QDateTime(day.addDays(-step), @@ -1877,7 +1883,11 @@ void tst_QDateTime::springForward() Qt::UTC).toLocalTime(); QCOMPARE(detour.time(), time); detour = detour.addDays(step); - QCOMPARE(detour, direct); // Insist on consistency. + // Insist on consistency: + if (direct.isValid()) + QCOMPARE(detour, direct); + else + QVERIFY(!detour.isValid()); } void tst_QDateTime::operator_eqeq_data() @@ -2651,14 +2661,20 @@ void tst_QDateTime::zoneAtTime_data() ADDROW("summer70:EST", "America/New_York", summer70, -4 * 3600); } +#ifdef Q_OS_ANDROID // QTBUG-68835; gets offset 0 for the affected tests. +# define NONANDROIDROW(name, zone, date, offset) +#else +# define NONANDROIDROW(name, zone, date, offset) ADDROW(name, zone, date, offset) +#endif + #ifndef Q_OS_WIN // Bracket a few noteworthy transitions: ADDROW("before:ACWST", "Australia/Eucla", QDate(1974, 10, 26), 31500); // 8:45 - ADDROW("after:ACWST", "Australia/Eucla", QDate(1974, 10, 27), 35100); // 9:45 - ADDROW("before:NPT", "Asia/Kathmandu", QDate(1985, 12, 31), 19800); // 5:30 + NONANDROIDROW("after:ACWST", "Australia/Eucla", QDate(1974, 10, 27), 35100); // 9:45 + NONANDROIDROW("before:NPT", "Asia/Kathmandu", QDate(1985, 12, 31), 19800); // 5:30 ADDROW("after:NPT", "Asia/Kathmandu", QDate(1986, 1, 1), 20700); // 5:45 // The two that have skipped a day (each): - ADDROW("before:LINT", "Pacific/Kiritimati", QDate(1994, 12, 30), -36000); + NONANDROIDROW("before:LINT", "Pacific/Kiritimati", QDate(1994, 12, 30), -36000); ADDROW("after:LINT", "Pacific/Kiritimati", QDate(1995, 1, 2), 14 * 3600); ADDROW("after:WST", "Pacific/Apia", QDate(2011, 12, 31), 14 * 3600); #endif // MS lacks ACWST, NPT; doesn't grok date-line crossings; and Windows 7 lacks LINT. @@ -2697,29 +2713,37 @@ void tst_QDateTime::timeZoneAbbreviation() // Time definitely in Standard Time QDateTime dt4(QDate(2013, 1, 1), QTime(0, 0, 0), Qt::LocalTime); #ifdef Q_OS_WIN - QEXPECT_FAIL("", "Windows only returns long name (QTBUG-32759)", Continue); -#endif // Q_OS_WIN - QCOMPARE(dt4.timeZoneAbbreviation(), QString("CET")); + QEXPECT_FAIL("", "Windows only reports long name (QTBUG-32759)", Continue); +#endif + QCOMPARE(dt4.timeZoneAbbreviation(), QStringLiteral("CET")); // Time definitely in Daylight Time QDateTime dt5(QDate(2013, 6, 1), QTime(0, 0, 0), Qt::LocalTime); #ifdef Q_OS_WIN - QEXPECT_FAIL("", "Windows only returns long name (QTBUG-32759)", Continue); -#endif // Q_OS_WIN - QCOMPARE(dt5.timeZoneAbbreviation(), QString("CEST")); + QEXPECT_FAIL("", "Windows only reports long name (QTBUG-32759)", Continue); +#endif + QCOMPARE(dt5.timeZoneAbbreviation(), QStringLiteral("CEST")); } else { QSKIP("You must test using Central European (CET/CEST) time zone, e.g. TZ=Europe/Oslo"); } +#ifdef Q_OS_ANDROID // Only reports (general) zones as offsets (QTBUG-68837) + const QString cet(QStringLiteral("GMT+01:00")); + const QString cest(QStringLiteral("GMT+02:00")); +#else + const QString cet(QStringLiteral("CET")); + const QString cest(QStringLiteral("CEST")); +#endif + QDateTime dt5(QDate(2013, 1, 1), QTime(0, 0, 0), QTimeZone("Europe/Berlin")); #ifdef Q_OS_WIN - QEXPECT_FAIL("", "QTimeZone windows backend only returns long name", Continue); + QEXPECT_FAIL("", "Windows only reports long names (QTBUG-32759)", Continue); #endif - QCOMPARE(dt5.timeZoneAbbreviation(), QString("CET")); + QCOMPARE(dt5.timeZoneAbbreviation(), cet); QDateTime dt6(QDate(2013, 6, 1), QTime(0, 0, 0), QTimeZone("Europe/Berlin")); #ifdef Q_OS_WIN - QEXPECT_FAIL("", "QTimeZone windows backend only returns long name", Continue); + QEXPECT_FAIL("", "Windows only reports long names (QTBUG-32759)", Continue); #endif - QCOMPARE(dt6.timeZoneAbbreviation(), QString("CEST")); + QCOMPARE(dt6.timeZoneAbbreviation(), cest); } void tst_QDateTime::getDate() @@ -2889,38 +2913,40 @@ void tst_QDateTime::daylightTransitions() const QCOMPARE(utc.date(), QDate(2012, 3, 25)); QCOMPARE(utc.time(), QTime(2, 0, 0)); - // Test date maths, if result falls in missing hour then becomes next hour + // Test date maths, if result falls in missing hour then becomes next + // hour (or is always invalid; mktime() may reject gap-times). QDateTime test(QDate(2011, 3, 25), QTime(2, 0, 0)); QVERIFY(test.isValid()); test = test.addYears(1); - QVERIFY(test.isValid()); - QCOMPARE(test.date(), QDate(2012, 3, 25)); - QCOMPARE(test.time(), QTime(3, 0, 0)); + const bool handled = test.isValid(); +#define CHECK_SPRING_FORWARD(test) \ + if (test.isValid()) { \ + QCOMPARE(test.date(), QDate(2012, 3, 25)); \ + QCOMPARE(test.time(), QTime(3, 0, 0)); \ + } else { \ + QVERIFY(!handled); \ + } + CHECK_SPRING_FORWARD(test); test = QDateTime(QDate(2012, 2, 25), QTime(2, 0, 0)); QVERIFY(test.isValid()); test = test.addMonths(1); - QVERIFY(test.isValid()); - QCOMPARE(test.date(), QDate(2012, 3, 25)); - QCOMPARE(test.time(), QTime(3, 0, 0)); + CHECK_SPRING_FORWARD(test); test = QDateTime(QDate(2012, 3, 24), QTime(2, 0, 0)); QVERIFY(test.isValid()); test = test.addDays(1); - QVERIFY(test.isValid()); - QCOMPARE(test.date(), QDate(2012, 3, 25)); - QCOMPARE(test.time(), QTime(3, 0, 0)); + CHECK_SPRING_FORWARD(test); test = QDateTime(QDate(2012, 3, 25), QTime(1, 0, 0)); QVERIFY(test.isValid()); QCOMPARE(test.toMSecsSinceEpoch(), daylight2012 - msecsOneHour); test = test.addMSecs(msecsOneHour); - QVERIFY(test.isValid()); - QCOMPARE(test.date(), QDate(2012, 3, 25)); - QCOMPARE(test.time(), QTime(3, 0, 0)); - QCOMPARE(test.toMSecsSinceEpoch(), daylight2012); - + CHECK_SPRING_FORWARD(test); + if (handled) + QCOMPARE(test.toMSecsSinceEpoch(), daylight2012); +#undef CHECK_SPRING_FORWARD // Test for correct behviour for DaylightTime -> StandardTime transition, i.e. second occurrence @@ -2942,7 +2968,7 @@ void tst_QDateTime::daylightTransitions() const QVERIFY(msecBefore.isValid()); QCOMPARE(msecBefore.date(), QDate(2012, 10, 28)); QCOMPARE(msecBefore.time(), QTime(2, 59, 59, 999)); -#if defined(Q_OS_MAC) || defined(Q_OS_WIN) || defined(Q_OS_QNX) +#if defined(Q_OS_DARWIN) || defined(Q_OS_WIN) || defined(Q_OS_QNX) || defined(Q_OS_ANDROID) // Win and Mac uses SecondOccurrence here QEXPECT_FAIL("", "QDateTime doesn't properly support Daylight Transitions", Continue); #endif // Q_OS_MAC @@ -2964,8 +2990,8 @@ void tst_QDateTime::daylightTransitions() const QVERIFY(afterTran.isValid()); QCOMPARE(afterTran.date(), QDate(2012, 10, 28)); QCOMPARE(afterTran.time(), QTime(2, 59, 59, 999)); -#if defined (Q_OS_UNIX) && !defined(Q_OS_MAC) && !defined(Q_OS_QNX) - // Linux mktime bug uses last calculation +#ifdef __GLIBCXX__ + // Linux (i.e. glibc) mktime bug reuses last calculation QEXPECT_FAIL("", "QDateTime doesn't properly support Daylight Transitions", Continue); #endif // Q_OS_UNIX QCOMPARE(afterTran.toMSecsSinceEpoch(), standard2012 + msecsOneHour - 1); @@ -3171,12 +3197,12 @@ void tst_QDateTime::daylightTransitions() const test = test.addMSecs(msecsOneHour); QVERIFY(test.isValid()); QCOMPARE(test.date(), QDate(2012, 10, 28)); -#if defined(Q_OS_MAC) || defined(Q_OS_QNX) +#if defined(Q_OS_DARWIN) || defined(Q_OS_QNX) || defined(Q_OS_ANDROID) // Mac uses FirstOccurrence, Windows uses SecondOccurrence, Linux uses last calculation QEXPECT_FAIL("", "QDateTime doesn't properly support Daylight Transitions", Continue); #endif // Q_OS_WIN QCOMPARE(test.time(), QTime(3, 0, 0)); -#if defined(Q_OS_MAC) || defined(Q_OS_QNX) +#if defined(Q_OS_DARWIN) || defined(Q_OS_QNX) || defined(Q_OS_ANDROID) // Mac uses FirstOccurrence, Windows uses SecondOccurrence, Linux uses last calculation QEXPECT_FAIL("", "QDateTime doesn't properly support Daylight Transitions", Continue); #endif // Q_OS_WIN diff --git a/tests/auto/corelib/tools/qlocale/test/test.pro b/tests/auto/corelib/tools/qlocale/test/test.pro index c87e29e764..f7243e99a7 100644 --- a/tests/auto/corelib/tools/qlocale/test/test.pro +++ b/tests/auto/corelib/tools/qlocale/test/test.pro @@ -16,4 +16,4 @@ win32 { } } -!winrt: TEST_HELPER_INSTALLS = ../syslocaleapp/syslocaleapp +!android:!winrt: TEST_HELPER_INSTALLS = ../syslocaleapp/syslocaleapp diff --git a/tests/auto/corelib/tools/qlocale/tst_qlocale.cpp b/tests/auto/corelib/tools/qlocale/tst_qlocale.cpp index 375cecd521..884cff553c 100644 --- a/tests/auto/corelib/tools/qlocale/tst_qlocale.cpp +++ b/tests/auto/corelib/tools/qlocale/tst_qlocale.cpp @@ -168,14 +168,18 @@ tst_QLocale::tst_QLocale() void tst_QLocale::initTestCase() { #if QT_CONFIG(process) +# ifdef Q_OS_ANDROID + m_sysapp = QCoreApplication::applicationDirPath() + "/libsyslocaleapp.so"; +# else // !defined(Q_OS_ANDROID) const QString syslocaleapp_dir = QFINDTESTDATA("syslocaleapp"); QVERIFY2(!syslocaleapp_dir.isEmpty(), qPrintable(QStringLiteral("Cannot find 'syslocaleapp' starting from ") + QDir::toNativeSeparators(QDir::currentPath()))); m_sysapp = syslocaleapp_dir + QStringLiteral("/syslocaleapp"); -#ifdef Q_OS_WIN +# ifdef Q_OS_WIN m_sysapp += QStringLiteral(".exe"); -#endif +# endif +# endif // Q_OS_ANDROID const QFileInfo fi(m_sysapp); QVERIFY2(fi.exists() && fi.isExecutable(), qPrintable(QDir::toNativeSeparators(m_sysapp) @@ -502,6 +506,9 @@ void tst_QLocale::emptyCtor() #if !QT_CONFIG(process) QSKIP("No qprocess support", SkipAll); #else +#ifdef Q_OS_ANDROID + QSKIP("This test crashes on Android"); +#endif #define TEST_CTOR(req_lc, exp_str) \ { \ /* Test constructor without arguments. Needs separate process */ \ @@ -1542,17 +1549,25 @@ void tst_QLocale::formatTimeZone() QSKIP("You must test using Central European (CET/CEST) time zone, e.g. TZ=Europe/Oslo"); } +#ifdef Q_OS_ANDROID // Only reports (general) zones as offsets (QTBUG-68837) + const QString cet(QStringLiteral("GMT+01:00")); + const QString cest(QStringLiteral("GMT+02:00")); +#else + const QString cet(QStringLiteral("CET")); + const QString cest(QStringLiteral("CEST")); +#endif + QDateTime dt6(QDate(2013, 1, 1), QTime(0, 0, 0), QTimeZone("Europe/Berlin")); #ifdef Q_OS_WIN QEXPECT_FAIL("", "QTimeZone windows backend only returns long name", Continue); #endif - QCOMPARE(enUS.toString(dt6, "t"), QLatin1String("CET")); + QCOMPARE(enUS.toString(dt6, "t"), cet); QDateTime dt7(QDate(2013, 6, 1), QTime(0, 0, 0), QTimeZone("Europe/Berlin")); #ifdef Q_OS_WIN QEXPECT_FAIL("", "QTimeZone windows backend only returns long name", Continue); #endif - QCOMPARE(enUS.toString(dt7, "t"), QLatin1String("CEST")); + QCOMPARE(enUS.toString(dt7, "t"), cest); // Current datetime should return current abbreviation QCOMPARE(enUS.toString(QDateTime::currentDateTime(), "t"), diff --git a/tests/auto/corelib/tools/qstring/tst_qstring.cpp b/tests/auto/corelib/tools/qstring/tst_qstring.cpp index 47ccfb8b8a..cdabd51d43 100644 --- a/tests/auto/corelib/tools/qstring/tst_qstring.cpp +++ b/tests/auto/corelib/tools/qstring/tst_qstring.cpp @@ -518,6 +518,7 @@ private slots: void toUcs4(); void arg(); void number(); + void doubleOut(); void arg_fillChar_data(); void arg_fillChar(); void capacity_data(); @@ -4922,6 +4923,28 @@ void tst_QString::number() #endif } +void tst_QString::doubleOut() +{ + // Regression test for QTBUG-63620; the first two paths lost the exponent's + // leading 0 at 5.7; C's printf() family guarantee a two-digit exponent (in + // contrast with ECMAScript, which forbids leading zeros). + const QString expect(QStringLiteral("1e-06")); + const double micro = 1e-6; + QCOMPARE(QString::number(micro), expect); + QCOMPARE(QString("%1").arg(micro), expect); + { + QString text; + text.sprintf("%g", micro); + QCOMPARE(text, expect); + } + { + QString text; + QTextStream stream(&text); + stream << micro; + QCOMPARE(text, expect); + } +} + void tst_QString::capacity_data() { length_data(); diff --git a/tests/auto/corelib/tools/qtimezone/BLACKLIST b/tests/auto/corelib/tools/qtimezone/BLACKLIST new file mode 100644 index 0000000000..840c3b1181 --- /dev/null +++ b/tests/auto/corelib/tools/qtimezone/BLACKLIST @@ -0,0 +1,171 @@ +# QTBUG-69122 +[dataStreamTest] +android + +# QTBUG-69128 +[isTimeZoneIdAvailable] +android + +# QTBUG-69129 +[specificTransition] +android + +# QTBUG-69131 +[transitionEachZone:America/Cancun@2010] +android +[transitionEachZone:America/Eirunepe@2010] +android +[transitionEachZone:America/Montevideo@2010] +android +[transitionEachZone:America/Porto_Acre@2010] +android +[transitionEachZone:America/Rio_Branco@2010] +android +[transitionEachZone:Asia/Anadyr@2010] +android +[transitionEachZone:Asia/Chita@2010] +android +[transitionEachZone:Asia/Kamchatka@2010] +android +[transitionEachZone:Asia/Khandyga@2010] +android +[transitionEachZone:Asia/Magadan@2010] +android +[transitionEachZone:Asia/Novokuznetsk@2010] +android +[transitionEachZone:Asia/Pyongyang@2010] +android +[transitionEachZone:Asia/Ust-Nera@2010] +android +[transitionEachZone:Asia/Yerevan@2010] +android +[transitionEachZone:Europe/Kaliningrad@2010] +android +[transitionEachZone:Europe/Minsk@2010] +android +[transitionEachZone:Europe/Moscow@2010] +android +[transitionEachZone:Europe/Samara@2010] +android +[transitionEachZone:Europe/Simferopol@2010] +android +[transitionEachZone:Europe/Volgograd@2010] +android +[transitionEachZone:W-SU@2010] +android +[transitionEachZone:Africa/Bissau@1970] +android +[transitionEachZone:Africa/Juba@1970] +android +[transitionEachZone:Africa/Khartoum@1970] +android +[transitionEachZone:America/Metlakatla@1970] +android +[transitionEachZone:America/Montevideo@1970] +android +[transitionEachZone:America/Paramaribo@1970] +android +[transitionEachZone:America/Santarem@1970] +android +[transitionEachZone:America/Santo_Domingo@1970] +android +[transitionEachZone:Asia/Anadyr@1970] +android +[transitionEachZone:Asia/Bahrain@1970] +android +[transitionEachZone:Asia/Chita@1970] +android +[transitionEachZone:Asia/Dushanbe@1970] +android +[transitionEachZone:Asia/Ho_Chi_Minh@1970] +android +[transitionEachZone:Asia/Kathmandu@1970] +android +[transitionEachZone:Asia/Katmandu@1970] +android +[transitionEachZone:Asia/Kuala_Lumpur@1970] +android +[transitionEachZone:Asia/Magadan@1970] +android +[transitionEachZone:Asia/Novosibirsk@1970] +android +[transitionEachZone:Asia/Pontianak@1970] +android +[transitionEachZone:Asia/Pyongyang@1970] +android +[transitionEachZone:Asia/Qatar@1970] +android +[transitionEachZone:Asia/Qyzylorda@1970] +android +[transitionEachZone:Asia/Saigon@1970] +android +[transitionEachZone:Asia/Sakhalin@1970] +android +[transitionEachZone:Asia/Singapore@1970] +android +[transitionEachZone:Asia/Tashkent@1970] +android +[transitionEachZone:Asia/Thimbu@1970] +android +[transitionEachZone:Asia/Thimphu@1970] +android +[transitionEachZone:Asia/Ust-Nera@1970] +android +[transitionEachZone:Atlantic/Cape_Verde@1970] +android +[transitionEachZone:Chile/EasterIsland@1970] +android +[transitionEachZone:Europe/Kaliningrad@1970] +android +[transitionEachZone:Pacific/Bougainville@1970] +android +[transitionEachZone:Pacific/Easter@1970] +android +[transitionEachZone:Pacific/Enderbury@1970] +android +[transitionEachZone:Pacific/Galapagos@1970] +android +[transitionEachZone:Pacific/Kiritimati@1970] +android +[transitionEachZone:Pacific/Kosrae@1970] +android +[transitionEachZone:Pacific/Kwajalein@1970] +android +[transitionEachZone:Pacific/Nauru@1970] +android +[transitionEachZone:Pacific/Niue@1970] +android +[transitionEachZone:Singapore@1970] +android +[transitionEachZone:Brazil/Acre@2010] +android +[transitionEachZone:Pacific/Bougainville@2010] +android +[transitionEachZone:Africa/Algiers@1970] +android +[transitionEachZone:Africa/Monrovia@1970] +android +[transitionEachZone:Kwajalein@1970] +android +[transitionEachZone:Indian/Chagos@1970] +android +[transitionEachZone:Europe/Volgograd@1970] +android +[transitionEachZone:Atlantic/Stanley@1970] +android +[transitionEachZone:Antarctica/Mawson@1970] +android +[transitionEachZone:America/Swift_Current@1970] +android +[transitionEachZone:America/Guyana@1970] +android +[transitionEachZone:America/Grand_Turk@1970] +android +[transitionEachZone:America/Dawson_Creek@1970] +android +[transitionEachZone:America/Cancun@1970] +android +[transitionEachZone:America/Caracas@1970] +android +[transitionEachZone:America/Danmarkshavn@1970] +android diff --git a/tests/auto/corelib/tools/qtimezone/tst_qtimezone.cpp b/tests/auto/corelib/tools/qtimezone/tst_qtimezone.cpp index d040f3bafd..d335dae7bc 100644 --- a/tests/auto/corelib/tools/qtimezone/tst_qtimezone.cpp +++ b/tests/auto/corelib/tools/qtimezone/tst_qtimezone.cpp @@ -512,6 +512,10 @@ void tst_QTimeZone::transitionEachZone() && zone == "Europe/Samara" && i == -3) { continue; } +#endif +#ifdef Q_OS_ANDROID + if (zone == "America/Mazatlan" || zone == "Mexico/BajaSur") + QSKIP("Crashes on Android, see QTBUG-69132"); #endif qint64 here = secs + i * 3600; QDateTime when = QDateTime::fromMSecsSinceEpoch(here * 1000, named); @@ -887,7 +891,7 @@ void tst_QTimeZone::icuTest() void tst_QTimeZone::tzTest() { -#if defined QT_BUILD_INTERNAL && defined Q_OS_UNIX && !defined Q_OS_DARWIN +#if defined QT_BUILD_INTERNAL && defined Q_OS_UNIX && !defined Q_OS_DARWIN && !defined Q_OS_ANDROID // Known datetimes qint64 std = QDateTime(QDate(2012, 1, 1), QTime(0, 0, 0), Qt::UTC).toMSecsSinceEpoch(); qint64 dst = QDateTime(QDate(2012, 6, 1), QTime(0, 0, 0), Qt::UTC).toMSecsSinceEpoch(); diff --git a/tests/auto/gui/kernel/kernel.pro b/tests/auto/gui/kernel/kernel.pro index 46786262c0..fbd3b1b371 100644 --- a/tests/auto/gui/kernel/kernel.pro +++ b/tests/auto/gui/kernel/kernel.pro @@ -37,4 +37,4 @@ win32:!winrt:qtHaveModule(network): SUBDIRS += noqteventloop !qtConfig(opengl): SUBDIRS -= qopenglwindow -uikit: SUBDIRS -= qclipboard +android|uikit: SUBDIRS -= qclipboard diff --git a/tests/auto/gui/kernel/qclipboard/test/test.pro b/tests/auto/gui/kernel/qclipboard/test/test.pro index 59b77b11ba..84e80d62e6 100644 --- a/tests/auto/gui/kernel/qclipboard/test/test.pro +++ b/tests/auto/gui/kernel/qclipboard/test/test.pro @@ -13,6 +13,6 @@ win32 { } } -!winrt: TEST_HELPER_INSTALLS = \ +!android:!winrt: TEST_HELPER_INSTALLS = \ ../copier/copier \ ../paster/paster diff --git a/tests/auto/gui/kernel/qkeyevent/BLACKLIST b/tests/auto/gui/kernel/qkeyevent/BLACKLIST new file mode 100644 index 0000000000..e55a200f4d --- /dev/null +++ b/tests/auto/gui/kernel/qkeyevent/BLACKLIST @@ -0,0 +1,6 @@ +# QTBUG-68974 +[basicEventDelivery] +android +# QTBUG-68974 +[modifiers] +android diff --git a/tests/auto/gui/kernel/qwindow/BLACKLIST b/tests/auto/gui/kernel/qwindow/BLACKLIST index bd2f6b5d60..d1f14de794 100644 --- a/tests/auto/gui/kernel/qwindow/BLACKLIST +++ b/tests/auto/gui/kernel/qwindow/BLACKLIST @@ -8,14 +8,22 @@ osx-10.12 ci ubuntu-16.04 # QTBUG-66851 opensuse +# QTBUG-69160 +android [setVisible] +# QTBUG-69154 +android [modalWindowEnterEventOnHide_QTBUG35109] ubuntu-16.04 osx ci +# QTBUG-69162 +android [modalDialogClosingOneOfTwoModal] osx [modalWindowModallity] osx +# QTBUG-69163 +android [visibility] osx-10.11 ci osx-10.12 ci @@ -25,3 +33,18 @@ rhel-7.4 [isActive] # QTBUG-67768 ubuntu +# QTBUG-69157 +android + +[exposeEventOnShrink_QTBUG54040] +# QTBUG-69155 +android +[initialSize] +# QTBUG-69159 +android +[modalWindowPosition] +# QTBUG-69161 +android +[childWindowPositioning:show] +# QTBUG-69156 +android diff --git a/tests/auto/gui/painting/qpainter/BLACKLIST b/tests/auto/gui/painting/qpainter/BLACKLIST new file mode 100644 index 0000000000..b828cbc75e --- /dev/null +++ b/tests/auto/gui/painting/qpainter/BLACKLIST @@ -0,0 +1,3 @@ +[textOnTransparentImage] +# QTBUG-69166 +android diff --git a/tests/auto/network/access/qnetworkreply/test/test.pro b/tests/auto/network/access/qnetworkreply/test/test.pro index 1f45ac0c49..e8464e81af 100644 --- a/tests/auto/network/access/qnetworkreply/test/test.pro +++ b/tests/auto/network/access/qnetworkreply/test/test.pro @@ -13,4 +13,4 @@ RESOURCES += ../qnetworkreply.qrc TESTDATA += ../empty ../rfc3252.txt ../resource ../bigfile ../*.jpg ../certs \ ../index.html ../smb-file.txt -!winrt: TEST_HELPER_INSTALLS = ../echo/echo +!android:!winrt: TEST_HELPER_INSTALLS = ../echo/echo diff --git a/tests/auto/network/bearer/qnetworksession/test/test.pro b/tests/auto/network/bearer/qnetworksession/test/test.pro index c95baa2b81..bfc1ec7727 100644 --- a/tests/auto/network/bearer/qnetworksession/test/test.pro +++ b/tests/auto/network/bearer/qnetworksession/test/test.pro @@ -15,4 +15,4 @@ CONFIG(debug_and_release) { DESTDIR = .. } -!winrt: TEST_HELPER_INSTALLS = ../lackey/lackey +!android:!winrt: TEST_HELPER_INSTALLS = ../lackey/lackey diff --git a/tests/auto/other/qcomplextext/android_testdata.qrc b/tests/auto/other/qcomplextext/android_testdata.qrc new file mode 100644 index 0000000000..828176df4a --- /dev/null +++ b/tests/auto/other/qcomplextext/android_testdata.qrc @@ -0,0 +1,6 @@ + + + data/BidiCharacterTest.txt + data/BidiTest.txt + + diff --git a/tests/auto/other/qcomplextext/qcomplextext.pro b/tests/auto/other/qcomplextext/qcomplextext.pro index d51dcb4cff..5135b48fee 100644 --- a/tests/auto/other/qcomplextext/qcomplextext.pro +++ b/tests/auto/other/qcomplextext/qcomplextext.pro @@ -8,5 +8,7 @@ TESTDATA += data android { RESOURCES += \ - testdata.qrc + android_testdata.qrc } + +builtin_testdata: DEFINES += BUILTIN_TESTDATA diff --git a/tests/auto/other/qcomplextext/tst_qcomplextext.cpp b/tests/auto/other/qcomplextext/tst_qcomplextext.cpp index 812cd8f369..0116e546a0 100644 --- a/tests/auto/other/qcomplextext/tst_qcomplextext.cpp +++ b/tests/auto/other/qcomplextext/tst_qcomplextext.cpp @@ -48,9 +48,7 @@ private slots: void bidiInvalidCursorNoMovement_data(); void bidiInvalidCursorNoMovement(); - void bidiCharacterTest_data(); void bidiCharacterTest(); - void bidiTest_data(); void bidiTest(); }; @@ -279,67 +277,6 @@ void tst_QComplexText::bidiCursor_PDF() QVERIFY(line.cursorToX(size) == line.cursorToX(size - 1)); } -void tst_QComplexText::bidiCharacterTest_data() -{ - QTest::addColumn("data"); - QTest::addColumn("paragraphDirection"); - QTest::addColumn>("resolvedLevels"); - QTest::addColumn>("visualOrder"); - - QString testFile = QFINDTESTDATA("data/BidiCharacterTest.txt"); - QFile f(testFile); - QVERIFY(f.exists()); - - f.open(QIODevice::ReadOnly); - - int linenum = 0; - while (!f.atEnd()) { - linenum++; - - QByteArray line = f.readLine().simplified(); - if (line.startsWith('#') || line.isEmpty()) - continue; - QVERIFY(!line.contains('#')); - - QList parts = line.split(';'); - QVERIFY(parts.size() == 5); - - QString data; - QList dataParts = parts.at(0).split(' '); - for (const auto &p : dataParts) { - bool ok; - data += QChar((ushort)p.toInt(&ok, 16)); - QVERIFY(ok); - } - - int paragraphDirection = parts.at(1).toInt(); -// int resolvedParagraphLevel = parts.at(2).toInt(); - - QVector resolvedLevels; - QList levelParts = parts.at(3).split(' '); - for (const auto &p : levelParts) { - if (p == "x") { - resolvedLevels += -1; - } else { - bool ok; - resolvedLevels += p.toInt(&ok); - QVERIFY(ok); - } - } - - QVector visualOrder; - QList orderParts = parts.at(4).split(' '); - for (const auto &p : orderParts) { - bool ok; - visualOrder += p.toInt(&ok); - QVERIFY(ok); - } - - const QByteArray nm = "line #" + QByteArray::number(linenum); - QTest::newRow(nm.constData()) << data << paragraphDirection << resolvedLevels << visualOrder; - } -} - static void testBidiString(const QString &data, int paragraphDirection, const QVector &resolvedLevels, const QVector &visualOrder) { Q_UNUSED(resolvedLevels); @@ -421,12 +358,59 @@ static void testBidiString(const QString &data, int paragraphDirection, const QV void tst_QComplexText::bidiCharacterTest() { - QFETCH(QString, data); - QFETCH(int, paragraphDirection); - QFETCH(QVector, resolvedLevels); - QFETCH(QVector, visualOrder); + QString testFile = QFINDTESTDATA("data/BidiCharacterTest.txt"); + QFile f(testFile); + QVERIFY(f.exists()); - testBidiString(data, paragraphDirection, resolvedLevels, visualOrder); + f.open(QIODevice::ReadOnly); + + int linenum = 0; + while (!f.atEnd()) { + linenum++; + + QByteArray line = f.readLine().simplified(); + if (line.startsWith('#') || line.isEmpty()) + continue; + QVERIFY(!line.contains('#')); + + QList parts = line.split(';'); + QVERIFY(parts.size() == 5); + + QString data; + QList dataParts = parts.at(0).split(' '); + for (const auto &p : dataParts) { + bool ok; + data += QChar((ushort)p.toInt(&ok, 16)); + QVERIFY(ok); + } + + int paragraphDirection = parts.at(1).toInt(); +// int resolvedParagraphLevel = parts.at(2).toInt(); + + QVector resolvedLevels; + QList levelParts = parts.at(3).split(' '); + for (const auto &p : levelParts) { + if (p == "x") { + resolvedLevels += -1; + } else { + bool ok; + resolvedLevels += p.toInt(&ok); + QVERIFY(ok); + } + } + + QVector visualOrder; + QList orderParts = parts.at(4).split(' '); + for (const auto &p : orderParts) { + bool ok; + visualOrder += p.toInt(&ok); + QVERIFY(ok); + } + + const QByteArray nm = "line #" + QByteArray::number(linenum); + + testBidiString(data, paragraphDirection, resolvedLevels, visualOrder); + } } ushort unicodeForDirection(const QByteArray &direction) @@ -466,13 +450,8 @@ ushort unicodeForDirection(const QByteArray &direction) Q_UNREACHABLE(); } -void tst_QComplexText::bidiTest_data() +void tst_QComplexText::bidiTest() { - QTest::addColumn("data"); - QTest::addColumn("paragraphDirection"); - QTest::addColumn>("resolvedLevels"); - QTest::addColumn>("visualOrder"); - QString testFile = QFINDTESTDATA("data/BidiTest.txt"); QFile f(testFile); QVERIFY(f.exists()); @@ -534,24 +513,13 @@ void tst_QComplexText::bidiTest_data() const QByteArray nm = "line #" + QByteArray::number(linenum); if (paragraphDirections & 1) - QTest::newRow((nm + " (Auto)").constData()) << data << 2 << resolvedLevels << visualOrder; + testBidiString(data, 2, resolvedLevels, visualOrder); if (paragraphDirections & 2) - QTest::newRow((nm + " (LTR)").constData()) << data << 0 << resolvedLevels << visualOrder; + testBidiString(data, 0, resolvedLevels, visualOrder); if (paragraphDirections & 4) - QTest::newRow((nm + " (RTL)").constData()) << data << 1 << resolvedLevels << visualOrder; + testBidiString(data, 1, resolvedLevels, visualOrder); } - -} - -void tst_QComplexText::bidiTest() -{ - QFETCH(QString, data); - QFETCH(int, paragraphDirection); - QFETCH(QVector, resolvedLevels); - QFETCH(QVector, visualOrder); - - testBidiString(data, paragraphDirection, resolvedLevels, visualOrder); } diff --git a/tests/auto/testlib/selftests/findtestdata/findtestdata.cpp b/tests/auto/testlib/selftests/findtestdata/findtestdata.cpp index a775bc1ee5..7d5857faa0 100644 --- a/tests/auto/testlib/selftests/findtestdata/findtestdata.cpp +++ b/tests/auto/testlib/selftests/findtestdata/findtestdata.cpp @@ -134,6 +134,30 @@ void FindTestData::paths() #endif QVERIFY(QFile(testfile_path3).remove()); +#if !defined(Q_OS_WIN) + struct ChdirOnReturn + { + ~ChdirOnReturn() { QDir::setCurrent(dir); } + QString dir; + }; + + // When cross-compiling from Windows to a *nix system the __FILE__ path's canonical path is an + // empty string, which, when used as a prefix, would cause QFINDTESTDATA to look for files in + // root ('/') when trying to look for files relative to the test source. + QString usrPath = app_path + "/temp/usr/"; + QVERIFY(QDir().mkpath(usrPath)); + { + ChdirOnReturn chdirObject{QDir::currentPath()}; + QDir::setCurrent(app_path + "/temp"); + QCOMPARE(QTest::qFindTestData("usr/", + "C:\\path\\to\\source\\source.cpp", + __LINE__, + "C:\\path\\to\\build\\").toLower(), + usrPath.toLower()); + } + QVERIFY(QDir().rmpath(usrPath)); +#endif + // Note, this is expected to generate a warning. // We can't use ignoreMessage, because the warning comes from testlib, // not via a "normal" qWarning. But it's OK, our caller (tst_selftests) diff --git a/tests/auto/testlib/selftests/test/test.pro b/tests/auto/testlib/selftests/test/test.pro index a348ea9ad5..ec1633ebff 100644 --- a/tests/auto/testlib/selftests/test/test.pro +++ b/tests/auto/testlib/selftests/test/test.pro @@ -17,5 +17,5 @@ expected_files.base = $$PWD/.. RESOURCES += expected_files include(../selftests.pri) -!winrt: for(file, SUBPROGRAMS): TEST_HELPER_INSTALLS += "../$${file}/$${file}" +!android:!winrt: for(file, SUBPROGRAMS): TEST_HELPER_INSTALLS += "../$${file}/$${file}" diff --git a/tests/auto/widgets/dialogs/qfiledialog/tst_qfiledialog.cpp b/tests/auto/widgets/dialogs/qfiledialog/tst_qfiledialog.cpp index eee227fc2f..eee649847f 100644 --- a/tests/auto/widgets/dialogs/qfiledialog/tst_qfiledialog.cpp +++ b/tests/auto/widgets/dialogs/qfiledialog/tst_qfiledialog.cpp @@ -1048,12 +1048,12 @@ void tst_QFiledialog::setMimeTypeFilters_data() QTest::addColumn("expectedSelectedMimeTypeFilter"); const auto headerMime = QStringLiteral("text/x-chdr"); - const auto jsonMime = QStringLiteral("application/json"); + const auto pdfMime = QStringLiteral("application/pdf"); const auto zipMime = QStringLiteral("application/zip"); QTest::newRow("single mime filter (C header file)") << QStringList {headerMime} << headerMime << headerMime; - QTest::newRow("single mime filter (JSON file)") << QStringList {jsonMime} << jsonMime << jsonMime; - QTest::newRow("multiple mime filters") << QStringList {jsonMime, zipMime} << jsonMime << jsonMime; + QTest::newRow("single mime filter (JSON file)") << QStringList {pdfMime} << pdfMime << pdfMime; + QTest::newRow("multiple mime filters") << QStringList {pdfMime, zipMime} << pdfMime << pdfMime; } void tst_QFiledialog::setMimeTypeFilters() @@ -1067,6 +1067,10 @@ void tst_QFiledialog::setMimeTypeFilters() fd.selectMimeTypeFilter(targetMimeTypeFilter); QCOMPARE(fd.selectedMimeTypeFilter(), expectedSelectedMimeTypeFilter); + + auto *filters = fd.findChild("fileTypeCombo"); + filters->setCurrentIndex(filters->count() - 1); + QCOMPARE(fd.selectedMimeTypeFilter(), mimeTypeFilters.last()); } void tst_QFiledialog::setEmptyNameFilter() diff --git a/tests/auto/widgets/itemviews/qheaderview/tst_qheaderview.cpp b/tests/auto/widgets/itemviews/qheaderview/tst_qheaderview.cpp index 8ec8f0e3c8..e880640b6b 100644 --- a/tests/auto/widgets/itemviews/qheaderview/tst_qheaderview.cpp +++ b/tests/auto/widgets/itemviews/qheaderview/tst_qheaderview.cpp @@ -43,6 +43,7 @@ #include #include #include +#include typedef QList IntList; @@ -244,6 +245,7 @@ private slots: void testMinMaxSectionSize(); void sizeHintCrash(); void testResetCachedSizeHint(); + void statusTips(); protected: void setupTestData(bool use_reset_model = false); @@ -270,12 +272,20 @@ public: int rowCount(const QModelIndex&) const override { return rows; } int columnCount(const QModelIndex&) const override { return cols; } bool isEditable(const QModelIndex &) const { return true; } - - QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override + QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const { - if (role == Qt::DisplayRole) - return m_bMultiLine ? QString("%1\n%1").arg(section) : QString::number(section); - return QAbstractTableModel::headerData(section, orientation, role); + if (section < 0 || (role != Qt::DisplayRole && role != Qt::StatusTipRole)) + return QVariant(); + const int row = (orientation == Qt::Vertical ? section : 0); + const int col = (orientation == Qt::Horizontal ? section : 0); + if (orientation == Qt::Vertical && row >= rows) + return QVariant(); + if (orientation == Qt::Horizontal && col >= cols) + return QVariant(); + if (m_bMultiLine) + return QString("%1\n%1").arg(section); + return QLatin1Char('[') + QString::number(row) + QLatin1Char(',') + + QString::number(col) + QLatin1String(",0] -- Header"); } QVariant data(const QModelIndex &idx, int role = Qt::DisplayRole) const override { @@ -3368,5 +3378,54 @@ void tst_QHeaderView::testResetCachedSizeHint() } +class StatusTipHeaderView : public QHeaderView +{ +public: + StatusTipHeaderView(Qt::Orientation orientation = Qt::Horizontal, QWidget *parent = 0) : + QHeaderView(orientation, parent), gotStatusTipEvent(false) {} + bool gotStatusTipEvent; + QString statusTipText; +protected: + bool event(QEvent *e) + { + if (e->type() == QEvent::StatusTip) { + gotStatusTipEvent = true; + statusTipText = static_cast(e)->tip(); + } + return QHeaderView::event(e); + } +}; + +void tst_QHeaderView::statusTips() +{ + StatusTipHeaderView headerView; + QtTestModel model; + model.rows = model.cols = 5; + headerView.setModel(&model); + headerView.viewport()->setMouseTracking(true); + headerView.setGeometry(QRect(QPoint(QApplication::desktop()->geometry().center() - QPoint(250, 250)), + QSize(500, 500))); + headerView.show(); + qApp->setActiveWindow(&headerView); + QVERIFY(QTest::qWaitForWindowActive(&headerView)); + + // Ensure it is moved away first and then moved to the relevant section + QTest::mouseMove(QApplication::desktop(), + headerView.rect().bottomLeft() + QPoint(20, 20)); + QPoint centerPoint = QRect(headerView.sectionPosition(0), headerView.y(), + headerView.sectionSize(0), headerView.height()).center(); + QTest::mouseMove(headerView.windowHandle(), centerPoint); + QTRY_VERIFY(headerView.gotStatusTipEvent); + QCOMPARE(headerView.statusTipText, QLatin1String("[0,0,0] -- Header")); + + headerView.gotStatusTipEvent = false; + headerView.statusTipText.clear(); + centerPoint = QRect(headerView.sectionPosition(1), headerView.y(), + headerView.sectionSize(1), headerView.height()).center(); + QTest::mouseMove(headerView.windowHandle(), centerPoint); + QTRY_VERIFY(headerView.gotStatusTipEvent); + QCOMPARE(headerView.statusTipText, QLatin1String("[0,1,0] -- Header")); +} + QTEST_MAIN(tst_QHeaderView) #include "tst_qheaderview.moc" diff --git a/tests/auto/widgets/kernel/qapplication/test/test.pro b/tests/auto/widgets/kernel/qapplication/test/test.pro index 76411a9ebe..8ade4d8364 100644 --- a/tests/auto/widgets/kernel/qapplication/test/test.pro +++ b/tests/auto/widgets/kernel/qapplication/test/test.pro @@ -9,20 +9,20 @@ builtin_testdata: DEFINES += BUILTIN_TESTDATA TESTDATA = ../test/test.pro ../tmp/README ../modal -!winrt: SUBPROGRAMS = desktopsettingsaware modal +!android:!winrt: SUBPROGRAMS = desktopsettingsaware modal debug_and_release { CONFIG(debug, debug|release) { TARGET = ../../debug/tst_qapplication - !winrt: TEST_HELPER_INSTALLS = ../debug/helper + !android:!winrt: TEST_HELPER_INSTALLS = ../debug/helper for(file, SUBPROGRAMS): TEST_HELPER_INSTALLS += "../debug/$${file}" } else { TARGET = ../../release/tst_qapplication - !winrt: TEST_HELPER_INSTALLS = ../release/helper + !android:!winrt: TEST_HELPER_INSTALLS = ../release/helper for(file, SUBPROGRAMS): TEST_HELPER_INSTALLS += "../release/$${file}" } } else { TARGET = ../tst_qapplication - !winrt: TEST_HELPER_INSTALLS = ../helper + !android:!winrt: TEST_HELPER_INSTALLS = ../helper for(file, SUBPROGRAMS): TEST_HELPER_INSTALLS += "../$${file}" } diff --git a/tests/auto/widgets/widgets/qframe/BLACKLIST b/tests/auto/widgets/widgets/qframe/BLACKLIST new file mode 100644 index 0000000000..3a28dd1239 --- /dev/null +++ b/tests/auto/widgets/widgets/qframe/BLACKLIST @@ -0,0 +1,3 @@ +# QTBUG-69064 +[testPainting] +android diff --git a/tests/auto/widgets/widgets/qgroupbox/BLACKLIST b/tests/auto/widgets/widgets/qgroupbox/BLACKLIST new file mode 100644 index 0000000000..62ba05797e --- /dev/null +++ b/tests/auto/widgets/widgets/qgroupbox/BLACKLIST @@ -0,0 +1,13 @@ +# QTBUG-69083 +[clicked:hit nothing, checkable] +android +[clicked:hit frame, checkable] +android +[clicked:hit nothing, checkable, but unchecked] +android +[clicked:hit frame, checkable, but unchecked] +android + +# QTBUG-69084 +[task_QTBUG_15519_propagateMouseEvents] +android diff --git a/tests/auto/widgets/widgets/qlineedit/BLACKLIST b/tests/auto/widgets/widgets/qlineedit/BLACKLIST new file mode 100644 index 0000000000..537c81413e --- /dev/null +++ b/tests/auto/widgets/widgets/qlineedit/BLACKLIST @@ -0,0 +1,31 @@ +# QTBUG-69111 +[undo_keypressevents:Inserts,moving,selection, delete and undo] +android + +# QTBUG-69112 +[inlineCompletion] +android + +# QTBUG-69116 +[leftKeyOnSelectedText] +android + +# QTBUG-69113 +[textMargin] +android + +# QTBUG-69119 +[task174640_editingFinished] +android + +# QTBUG-69118 +[task210502_caseInsensitiveInlineCompletion] +android + +# QTBUG-69114 +[QTBUG697_paletteCurrentColorGroup] +android + +# QTBUG-69115 +[testQuickSelectionWithMouse] +android diff --git a/tests/benchmarks/corelib/plugin/quuid/tst_quuid.cpp b/tests/benchmarks/corelib/plugin/quuid/tst_quuid.cpp index 6a93391896..b52654d1b4 100644 --- a/tests/benchmarks/corelib/plugin/quuid/tst_quuid.cpp +++ b/tests/benchmarks/corelib/plugin/quuid/tst_quuid.cpp @@ -138,13 +138,12 @@ void tst_bench_QUuid::createUuidV5() void tst_bench_QUuid::toDataStream() { - QUuid uuid1, uuid2; - uuid1 = QUuid::createUuid(); + QUuid uuid = QUuid::createUuid(); QByteArray ar; { QDataStream out(&ar,QIODevice::WriteOnly); QBENCHMARK { - out << uuid1; + out << uuid; } } } diff --git a/tests/manual/widgets/widgets/defaultUpMenuBar/defaultUpMenuBar.pro b/tests/manual/widgets/widgets/defaultUpMenuBar/defaultUpMenuBar.pro new file mode 100644 index 0000000000..f9cffb3709 --- /dev/null +++ b/tests/manual/widgets/widgets/defaultUpMenuBar/defaultUpMenuBar.pro @@ -0,0 +1,4 @@ +QT += widgets +TEMPLATE = app +TARGET = defaultUpMenuBar +SOURCES += main.cpp diff --git a/tests/manual/widgets/widgets/defaultUpMenuBar/main.cpp b/tests/manual/widgets/widgets/defaultUpMenuBar/main.cpp new file mode 100644 index 0000000000..602127febe --- /dev/null +++ b/tests/manual/widgets/widgets/defaultUpMenuBar/main.cpp @@ -0,0 +1,125 @@ +/**************************************************************************** + ** + ** Copyright (C) 2018 The Qt Company Ltd. + ** Contact: https://www.qt.io/licensing/ + ** + ** This file is part of the test suite 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$ + ** + ****************************************************************************/ + +// This test is to check that the menus in a menubar are displayed correctly in both the top and +// bottom cases. Especially when using multiple screens. If possible relayout the screens in order +// to have one that is entirely in negative coordinates (i.e. the primary starts at 0x0 and the +// secondary is above it). + +#include +#include + +class MainWindow : public QMainWindow +{ +public: + MainWindow(QWidget *parent = 0) : QMainWindow(parent) + { + auto *menu1Act1 = new QAction("Action 1"); + auto *menu1Act2 = new QAction("Action 2"); + auto *menu1Act3 = new QAction("Action 3"); + auto *menu1Act4 = new QAction("Action 4"); + auto *menu2Act1 = new QAction("2- Action 1"); + auto *menu2Act2 = new QAction("2- Action 2"); + auto *menu2Act3 = new QAction("2- Action 3"); + auto *menu2Act4 = new QAction("2- Action 4"); + auto *menu1 = new QMenu("Menu 1"); + menu1->addAction(menu1Act1); + menu1->addAction(menu1Act2); + menu1->addAction(menu1Act3); + menu1->addAction(menu1Act4); + auto *menu2 = new QMenu("Menu 2"); + menu2->addAction(menu2Act1); + menu2->addAction(menu2Act2); + menu2->addAction(menu2Act3); + menu2->addAction(menu2Act4); + menuBar()->addMenu(menu1); + menuBar()->addMenu(menu2); + menuBar()->setNativeMenuBar(false); + + auto *menu1Bottom = new QMenu("Menu 1"); + menu1Bottom->addAction(menu1Act1); + menu1Bottom->addAction(menu1Act2); + menu1Bottom->addAction(menu1Act3); + menu1Bottom->addAction(menu1Act4); + auto *menu2Bottom = new QMenu("Menu 2"); + menu2Bottom->addAction(menu2Act1); + menu2Bottom->addAction(menu2Act2); + menu2Bottom->addAction(menu2Act3); + menu2Bottom->addAction(menu2Act4); + + QWidget *central = new QWidget; + QVBoxLayout *layout = new QVBoxLayout; + auto *menuBarBottom = new QMenuBar(this); + menuBarBottom->addMenu(menu1Bottom); + menuBarBottom->addMenu(menu2Bottom); + menuBarBottom->setDefaultUp(true); + menuBarBottom->setNativeMenuBar(false); + layout->addWidget(menuBarBottom); + layout->setAlignment(menuBarBottom, Qt::AlignBottom); + central->setLayout(layout); + setCentralWidget(central); + setWindowFlags(windowFlags() | Qt::FramelessWindowHint); + } +}; + +int main(int argc, char **argv) +{ + QApplication a(argc, argv); + QList windows; + for (QScreen *screen : QApplication::screens()) { + MainWindow *mainWindow = new MainWindow; + mainWindow->setGeometry(screen->geometry()); + QWindowsWindowFunctions::setHasBorderInFullScreen(mainWindow->windowHandle(), true); + mainWindow->showMaximized(); + } + int ret = a.exec(); + qDeleteAll(windows); + return ret; +}