diff --git a/.circleci/config.yml b/.circleci/config.yml index 1a8b4b460..65e544005 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -144,41 +144,33 @@ commands: name: Install Dependencies command: > apt-get update && apt-get install -y + build-essential cmake - fakeroot gettext git libasound2-dev libboost-dev - libboost-serialization-dev - libcdio-cdda2 libcdio-dev libchromaprint-dev - libcrypto++-dev libdbus-1-dev libfftw3-dev libglew1.5-dev + libglib2.0-dev libgpod-dev libgstreamer-plugins-base1.0-dev libgstreamer1.0-dev - liblastfm-dev libmtp-dev - libmygpo-qt-dev - libplist-dev libprotobuf-dev libpulse-dev - libqca2-dev - libqca2-plugins - libqjson-dev - libqt4-dev - libqt4-opengl-dev - libqtwebkit-dev - libsparsehash-dev + libqt5x11extras5-dev libsqlite3-dev libtag1-dev - libusbmuxd-dev + pkg-config protobuf-compiler - qt4-dev-tools + qtbase5-dev + qttools5-dev-tools + qttools5-dev + libsparsehash-dev ssh install_disco_dependencies: description: Install Disco dependencies @@ -450,11 +442,11 @@ jobs: - run: name: Setup PATH command: | - echo 'export Qt5_DIR=/usr/local/opt/qt5/lib/cmake' >> $BASH_ENV - echo 'export Qt5LinguistTools_DIR=/usr/local/Cellar/qt/5.11.2/lib/cmake/Qt5LinguistTools' >> $BASH_ENV - echo 'export GST_SCANNER_PATH=/usr/local/Cellar/gstreamer/1.14.4/libexec/gstreamer-1.0/gst-plugin-scanner' >> $BASH_ENV + echo 'export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig' >> $BASH_ENV + echo 'export Qt5_DIR=/usr/local/Cellar/qt/5.13.1/lib/cmake/Qt5' >> $BASH_ENV + echo 'export Qt5LinguistTools_DIR=/usr/local/Cellar/qt/5.13.1/lib/cmake/Qt5LinguistTools' >> $BASH_ENV + echo 'export GST_SCANNER_PATH=/usr/local/Cellar/gstreamer/1.16.1/libexec/gstreamer-1.0/gst-plugin-scanner' >> $BASH_ENV echo 'export GST_PLUGIN_PATH=/usr/local/lib/gstreamer-1.0' >> $BASH_ENV - echo 'export PATH=/usr/local/opt/gettext/bin:$PATH' >> $BASH_ENV source $BASH_ENV - run: name: Install dependencies from homebrew @@ -464,39 +456,38 @@ jobs: chromaprint cmake cryptopp + fftw gettext + glew glib - liblastfm + google-sparsehash + gst-libav + gst-plugins-bad + gst-plugins-base + gst-plugins-good + gst-plugins-ugly + gstreamer pkgconfig protobuf protobuf-c qt - - run: - name: Install sqlite - command: brew install sqlite --with-fts - - run: - name: Install gstreamer - command: brew install gstreamer gst-plugins-base - - run: - name: Install gst-plugins-good - command: brew install gst-plugins-good --with-flac - - run: - name: Install gst-plugins - command: brew install gst-plugins-bad gst-plugins-ugly - - run: - name: Install other dependencies - command: brew install chromaprint liblastfm + sqlite - checkout - - run: - name: Checkout qt5 branch - command: git checkout qt5 - run: name: cmake - command: cmake .. -DUSE_VISUALISATIONS=OFF + command: > + cmake + .. + -Wno-dev + -DCMAKE_BUILD_TYPE=Release + -DCMAKE_OSX_ARCHITECTURES=x86_64 + -DGETTEXT_MSGMERGE_EXECUTABLE=/usr/local/Cellar/gettext/0.20.1/bin/msgmerge + -DGETTEXT_MSGFMT_EXECUTABLE=/usr/local/Cellar/gettext/0.20.1/bin/msgfmt + -DGETTEXT_XGETTEXT_EXECUTABLE=/usr/local/Cellar/gettext/0.20.1/bin/xgettext working_directory: bin - run: name: make - command: make + command: make -j2 working_directory: bin - run: name: Copy icon file and resources @@ -516,6 +507,10 @@ jobs: root: /tmp/artifacts paths: - mac/* + - store_artifacts: + path: bin/CMakeCache.txt + - store_artifacts: + path: bin/src/CMakeFiles/clementine.dir - store_artifacts: path: /tmp/artifacts/mac @@ -538,30 +533,13 @@ workflows: version: 2 build_all: jobs: - - build_xenial_32 - - build_xenial_64 - - build_bionic_32 - build_bionic_64 - - build_disco_32 - - build_disco_64 - - build_fedora_29_64 - - build_fedora_30_64 - - build_buster_64 - - build_stretch_64 - + - build_mac - upload_artifacts: context: gcp requires: - - build_xenial_32 - - build_xenial_64 - - build_bionic_32 - build_bionic_64 - - build_disco_32 - - build_disco_64 - - build_fedora_29_64 - - build_fedora_30_64 - - build_buster_64 - - build_stretch_64 + - build_mac filters: branches: - only: master + only: qt5 diff --git a/3rdparty/libmygpo-qt5/AUTHORS b/3rdparty/libmygpo-qt5/AUTHORS new file mode 100644 index 000000000..9080afb9e --- /dev/null +++ b/3rdparty/libmygpo-qt5/AUTHORS @@ -0,0 +1,3 @@ +Stefan Derkits +Christian Wagner +Felix Winter diff --git a/3rdparty/libmygpo-qt5/CMakeLists.txt b/3rdparty/libmygpo-qt5/CMakeLists.txt new file mode 100644 index 000000000..d53edbc8d --- /dev/null +++ b/3rdparty/libmygpo-qt5/CMakeLists.txt @@ -0,0 +1,50 @@ +cmake_minimum_required( VERSION 2.8.11 FATAL_ERROR ) + +set( CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules) +set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DQT_NO_CAST_FROM_ASCII -DQT_NO_CAST_TO_ASCII" ) + +set(MYGPO_QT_VERSION_SUFFIX 5) + +macro(qt_wrap_cpp) + qt5_wrap_cpp(${ARGN}) +endmacro() + +# pkg-config names of QtCore and QtNetwork are Qt5Core and Qt5Network for +# Qt5 +set(MYGPO_QT_MAJOR_VERSION "5") +set(MYGPO_QT4_QJSON_DEP "") + +# Don't use absolute path in Mygpo-qtTargets-$buildType.cmake +# (This will have no effect with CMake < 2.8) +# set(QT_USE_IMPORTED_TARGETS TRUE) + +set( MYGPO_QT_VERSION_MAJOR "1" ) +set( MYGPO_QT_VERSION_MINOR "0" ) +set( MYGPO_QT_VERSION_PATCH "8" ) +set( MYGPO_QT_VERSION "${MYGPO_QT_VERSION_MAJOR}.${MYGPO_QT_VERSION_MINOR}.${MYGPO_QT_VERSION_PATCH}" ) + +#Configure Version.h.in with the actual version number +configure_file( src/Version.h.in ${CMAKE_CURRENT_BINARY_DIR}/src/Version.h ) + +include(CheckCXXCompilerFlag) + +if (CMAKE_COMPILER_IS_GNUCXX) + ADD_DEFINITIONS( -Wcast-align -Wchar-subscripts -Wpointer-arith + -Wwrite-strings -Wpacked -Wformat-security -Wmissing-format-attribute + -Wold-style-cast -Woverloaded-virtual -Wnon-virtual-dtor -Wall -Wextra + -Wformat=2 -Wundef -Wstack-protector -Wmissing-include-dirs + -Winit-self -Wunsafe-loop-optimizations -ggdb3 -fno-inline -DQT_STRICT_ITERATORS ) + if ( NOT WIN32 ) + add_definitions( -fvisibility=hidden ) + endif() + + check_cxx_compiler_flag( -Wlogical-op GNUCXX_HAS_WLOGICAL_OP ) + if ( GNUCXX_HAS_WLOGICAL_OP ) + add_definitions( -Wlogical-op ) + endif() +endif(CMAKE_COMPILER_IS_GNUCXX) + + +set(MYGPO_QT_TARGET_NAME mygpo-qt${MYGPO_QT_VERSION_SUFFIX} CACHE INTERNAL "" FORCE ) + +add_subdirectory( src ) diff --git a/3rdparty/libmygpo-qt5/LICENSE b/3rdparty/libmygpo-qt5/LICENSE new file mode 100644 index 000000000..4362b4915 --- /dev/null +++ b/3rdparty/libmygpo-qt5/LICENSE @@ -0,0 +1,502 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/3rdparty/libmygpo-qt5/Mygpo-qtConfig.cmake.in b/3rdparty/libmygpo-qt5/Mygpo-qtConfig.cmake.in new file mode 100644 index 000000000..17873a74c --- /dev/null +++ b/3rdparty/libmygpo-qt5/Mygpo-qtConfig.cmake.in @@ -0,0 +1,18 @@ +get_filename_component(myDir ${CMAKE_CURRENT_LIST_FILE} PATH) # get the directory where I myself am +get_filename_component(rootDir ${myDir}/@relInstallDir@ ABSOLUTE) # get the chosen install prefix + +# set the version of myself +set(MYGPO_QT_VERSION_MAJOR @MYGPO_QT_VERSION_MAJOR@) +set(MYGPO_QT_VERSION_MINOR @MYGPO_QT_VERSION_MINOR@) +set(MYGPO_QT_VERSION_PATCH @MYGPO_QT_VERSION_PATCH@) +set(MYGPO_QT_VERSION ${MYGPO_QT_VERSION_MAJOR}.${MYGPO_QT_VERSION_MINOR}.${MYGPO_QT_VERSION_PATCH} ) + +# what is my include directory +set(LIBMYGPO_QT_INCLUDE_DIRS "@INCLUDE_INSTALL_DIR@") + +# import the exported targets +include(${myDir}/Mygpo-qtTargets.cmake) + +# set the expected library variable +set(LIBMYGPO_QT_LIBRARIES mygpo-qt ) +set(LIBMYGPO_QT_FOUND "True") diff --git a/3rdparty/libmygpo-qt5/Mygpo-qtConfigVersion.cmake.in b/3rdparty/libmygpo-qt5/Mygpo-qtConfigVersion.cmake.in new file mode 100644 index 000000000..1126fdfc3 --- /dev/null +++ b/3rdparty/libmygpo-qt5/Mygpo-qtConfigVersion.cmake.in @@ -0,0 +1,10 @@ +set(PACKAGE_VERSION @MYGPO_QT_VERSION_MAJOR@.@MYGPO_QT_VERSION_MINOR@.@MYGPO_QT_VERSION_PATCH@) + +if("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}" ) + set(PACKAGE_VERSION_COMPATIBLE FALSE) +else("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}" ) + set(PACKAGE_VERSION_COMPATIBLE TRUE) + if( "${PACKAGE_FIND_VERSION}" STREQUAL "${PACKAGE_VERSION}") + set(PACKAGE_VERSION_EXACT TRUE) + endif( "${PACKAGE_FIND_VERSION}" STREQUAL "${PACKAGE_VERSION}") +endif("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}" ) diff --git a/3rdparty/libmygpo-qt5/README b/3rdparty/libmygpo-qt5/README new file mode 100644 index 000000000..656949d9f --- /dev/null +++ b/3rdparty/libmygpo-qt5/README @@ -0,0 +1,52 @@ +========== README ========== + +=== What is libmygpo-qt === + +libmygpo-qt is a Qt Library that wraps the gpodder.net Web API (http://wiki.gpodder.org/wiki/Web_Services/API_2) + +=== Copyright & License === + +Copyright 2010 - 2014 Stefan Derkits (stefan@derkits.at) , Christian Wagner (christian.wagner86@gmx.at) & Felix Winter (ixos01@gmail.com) + +See COPYING File for License + +=== Maintainer === + +Current Maintainer: Stefan Derkits (HorusHorrendus @ irc.freenode.net) + +=== Requirements === + +-) Qt 4.6 or higher +-) Cmake 2.6 or higher +-) QJson + +=== Qt5 Support === + +libmygpo-qt version 1.0.8 supports also building the library with Qt5. The API is the same as in the Qt4 library. To build the library with Qt5 add "-DBUILD_WITH_QT4=OFF" to your CMake +command line. Please note that Qt5 support is still experimental. If you find anything to not work with Qt5, please report a bug. + +==== Qt5 Requirements === + +-) CMake 2.8.9 or higher +-) Qt 5.2 or higher + +=== Links === + +Homepage: http://wiki.gpodder.org/wiki/Libmygpo-qt +Git Repo: https://github.com/gpodder/libmygpo-qt +Doxygen Documentation: http://stefan.derkits.at/libmygpo-doc/ +Bugreports: http://bugs.gpodder.org +Contact: gpodder@freelists.org +IRC Channel: #gpodder on FreeNode (irc.freenode.net) + +=== How to Install === + +-) Create Directory "build" +-) change into build and run "cmake .. -DCMAKE_BUILD_TYPE=Debug" +-) make +-) make install (might need root) + +To use libmygpo-qt include the Header "ApiRequest.h" into your Code. You can find the cflags & linker flags for libmygpo-qt either via pkg-config (.pc file will be installed to your System) +or via cmake (Mygpo-qtConfig.cmake will be installed to your system). + +You can check the Example Application to see how you can use libmygpo-qt in your Application diff --git a/3rdparty/libmygpo-qt5/cmake/modules/FindQJSON.cmake b/3rdparty/libmygpo-qt5/cmake/modules/FindQJSON.cmake new file mode 100644 index 000000000..936d93b3c --- /dev/null +++ b/3rdparty/libmygpo-qt5/cmake/modules/FindQJSON.cmake @@ -0,0 +1,50 @@ +# Find QJSON - JSON handling library for Qt +# +# This module defines +# QJSON_FOUND - whether the qsjon library was found +# QJSON_LIBRARIES - the qjson library +# QJSON_INCLUDE_DIR - the include path of the qjson library +# + +if (QJSON_INCLUDE_DIR AND QJSON_LIBRARIES) + + # Already in cache + set (QJSON_FOUND TRUE) + +else (QJSON_INCLUDE_DIR AND QJSON_LIBRARIES) + + if (NOT WIN32) + # use pkg-config to get the values of QJSON_INCLUDE_DIRS + # and QJSON_LIBRARY_DIRS to add as hints to the find commands. + include (FindPkgConfig) + pkg_check_modules (QJSON REQUIRED QJson>=0.5) + endif (NOT WIN32) + + find_library (QJSON_LIBRARIES + NAMES + qjson + PATHS + ${QJSON_LIBRARY_DIRS} + ${LIB_INSTALL_DIR} + ${KDE4_LIB_DIR} + ) + + find_path (QJSON_INCLUDE_DIR + NAMES + parser.h + PATH_SUFFIXES + qjson + PATHS + ${QJSON_INCLUDE_DIRS} + ${INCLUDE_INSTALL_DIR} + ${KDE4_INCLUDE_DIR} + ) + + include(FindPackageHandleStandardArgs) + find_package_handle_standard_args(QJSON DEFAULT_MSG QJSON_LIBRARIES QJSON_INCLUDE_DIR) + + if ( UNIX AND NOT APPLE ) + set ( QJSON_LIBRARIES "${QJSON_LIBRARIES} ${QJSON_LDFLAGS}" CACHE INTERNAL "") + endif () + +endif (QJSON_INCLUDE_DIR AND QJSON_LIBRARIES) diff --git a/3rdparty/libmygpo-qt/AddRemoveResult.cpp b/3rdparty/libmygpo-qt5/src/AddRemoveResult.cpp similarity index 100% rename from 3rdparty/libmygpo-qt/AddRemoveResult.cpp rename to 3rdparty/libmygpo-qt5/src/AddRemoveResult.cpp diff --git a/3rdparty/libmygpo-qt/AddRemoveResult.h b/3rdparty/libmygpo-qt5/src/AddRemoveResult.h similarity index 100% rename from 3rdparty/libmygpo-qt/AddRemoveResult.h rename to 3rdparty/libmygpo-qt5/src/AddRemoveResult.h diff --git a/3rdparty/libmygpo-qt/AddRemoveResult_p.h b/3rdparty/libmygpo-qt5/src/AddRemoveResult_p.h similarity index 100% rename from 3rdparty/libmygpo-qt/AddRemoveResult_p.h rename to 3rdparty/libmygpo-qt5/src/AddRemoveResult_p.h diff --git a/3rdparty/libmygpo-qt/ApiRequest.cpp b/3rdparty/libmygpo-qt5/src/ApiRequest.cpp similarity index 100% rename from 3rdparty/libmygpo-qt/ApiRequest.cpp rename to 3rdparty/libmygpo-qt5/src/ApiRequest.cpp diff --git a/3rdparty/libmygpo-qt/ApiRequest.h b/3rdparty/libmygpo-qt5/src/ApiRequest.h similarity index 100% rename from 3rdparty/libmygpo-qt/ApiRequest.h rename to 3rdparty/libmygpo-qt5/src/ApiRequest.h diff --git a/3rdparty/libmygpo-qt/ApiRequest_p.h b/3rdparty/libmygpo-qt5/src/ApiRequest_p.h similarity index 100% rename from 3rdparty/libmygpo-qt/ApiRequest_p.h rename to 3rdparty/libmygpo-qt5/src/ApiRequest_p.h diff --git a/3rdparty/libmygpo-qt/CMakeLists.txt b/3rdparty/libmygpo-qt5/src/CMakeLists.txt similarity index 77% rename from 3rdparty/libmygpo-qt/CMakeLists.txt rename to 3rdparty/libmygpo-qt5/src/CMakeLists.txt index 64bd33cf2..5098160aa 100644 --- a/3rdparty/libmygpo-qt/CMakeLists.txt +++ b/3rdparty/libmygpo-qt5/src/CMakeLists.txt @@ -3,9 +3,8 @@ set( MYGPO_QT_VERSION_MAJOR "1" ) set( MYGPO_QT_VERSION_MINOR "0" ) set( MYGPO_QT_VERSION_PATCH "9" ) configure_file( Version.h.in ${CMAKE_CURRENT_BINARY_DIR}/Version.h ) -include_directories("${QJSON_INCLUDEDIR}/qjson") -include_directories( ${QT_INCLUDES} ${QJSON_INCLUDE_DIR} ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ) +include_directories( ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ) set ( LIBMYGPO_QT_SRC Config.cpp @@ -81,9 +80,8 @@ set ( LIBMYGPO_QT_INSTALL_H AddRemoveResult.h ) -QT4_WRAP_CPP(LIBMYGPO_QT_MOC_SRC ${LIBMYGPO_QT_MOC_H} ) +QT_WRAP_CPP(LIBMYGPO_QT_MOC_SRC ${LIBMYGPO_QT_MOC_H} ) -add_library( mygpo-qt STATIC ${LIBMYGPO_QT_SRC} ${LIBMYGPO_QT_MOC_SRC} ) +add_library( ${MYGPO_QT_TARGET_NAME} STATIC ${LIBMYGPO_QT_SRC} ${LIBMYGPO_QT_MOC_SRC} ) -target_link_libraries( mygpo-qt ${QJSON_LIBRARIES} ${QT_QTCORE_LIBRARY} ${QT_QTNETWORK_LIBRARY} ) -set_target_properties( mygpo-qt PROPERTIES VERSION ${MYGPO_QT_VERSION} SOVERSION ${MYGPO_QT_SONAME} DEFINE_SYMBOL MYGPO_MAKEDLL) +target_link_libraries( ${MYGPO_QT_TARGET_NAME} ${QJSON_LIBRARIES} Qt5::Core Qt5::Network ) diff --git a/3rdparty/libmygpo-qt/Config.cpp b/3rdparty/libmygpo-qt5/src/Config.cpp similarity index 100% rename from 3rdparty/libmygpo-qt/Config.cpp rename to 3rdparty/libmygpo-qt5/src/Config.cpp diff --git a/3rdparty/libmygpo-qt/Config.h b/3rdparty/libmygpo-qt5/src/Config.h similarity index 100% rename from 3rdparty/libmygpo-qt/Config.h rename to 3rdparty/libmygpo-qt5/src/Config.h diff --git a/3rdparty/libmygpo-qt/Config_p.h b/3rdparty/libmygpo-qt5/src/Config_p.h similarity index 100% rename from 3rdparty/libmygpo-qt/Config_p.h rename to 3rdparty/libmygpo-qt5/src/Config_p.h diff --git a/3rdparty/libmygpo-qt/Device.cpp b/3rdparty/libmygpo-qt5/src/Device.cpp similarity index 100% rename from 3rdparty/libmygpo-qt/Device.cpp rename to 3rdparty/libmygpo-qt5/src/Device.cpp diff --git a/3rdparty/libmygpo-qt/Device.h b/3rdparty/libmygpo-qt5/src/Device.h similarity index 100% rename from 3rdparty/libmygpo-qt/Device.h rename to 3rdparty/libmygpo-qt5/src/Device.h diff --git a/3rdparty/libmygpo-qt/DeviceList.cpp b/3rdparty/libmygpo-qt5/src/DeviceList.cpp similarity index 100% rename from 3rdparty/libmygpo-qt/DeviceList.cpp rename to 3rdparty/libmygpo-qt5/src/DeviceList.cpp diff --git a/3rdparty/libmygpo-qt/DeviceList.h b/3rdparty/libmygpo-qt5/src/DeviceList.h similarity index 100% rename from 3rdparty/libmygpo-qt/DeviceList.h rename to 3rdparty/libmygpo-qt5/src/DeviceList.h diff --git a/3rdparty/libmygpo-qt/DeviceList_p.h b/3rdparty/libmygpo-qt5/src/DeviceList_p.h similarity index 100% rename from 3rdparty/libmygpo-qt/DeviceList_p.h rename to 3rdparty/libmygpo-qt5/src/DeviceList_p.h diff --git a/3rdparty/libmygpo-qt/DeviceSyncResult.cpp b/3rdparty/libmygpo-qt5/src/DeviceSyncResult.cpp similarity index 100% rename from 3rdparty/libmygpo-qt/DeviceSyncResult.cpp rename to 3rdparty/libmygpo-qt5/src/DeviceSyncResult.cpp diff --git a/3rdparty/libmygpo-qt/DeviceSyncResult.h b/3rdparty/libmygpo-qt5/src/DeviceSyncResult.h similarity index 100% rename from 3rdparty/libmygpo-qt/DeviceSyncResult.h rename to 3rdparty/libmygpo-qt5/src/DeviceSyncResult.h diff --git a/3rdparty/libmygpo-qt/DeviceSyncResult_p.h b/3rdparty/libmygpo-qt5/src/DeviceSyncResult_p.h similarity index 100% rename from 3rdparty/libmygpo-qt/DeviceSyncResult_p.h rename to 3rdparty/libmygpo-qt5/src/DeviceSyncResult_p.h diff --git a/3rdparty/libmygpo-qt/DeviceUpdates.cpp b/3rdparty/libmygpo-qt5/src/DeviceUpdates.cpp similarity index 100% rename from 3rdparty/libmygpo-qt/DeviceUpdates.cpp rename to 3rdparty/libmygpo-qt5/src/DeviceUpdates.cpp diff --git a/3rdparty/libmygpo-qt/DeviceUpdates.h b/3rdparty/libmygpo-qt5/src/DeviceUpdates.h similarity index 100% rename from 3rdparty/libmygpo-qt/DeviceUpdates.h rename to 3rdparty/libmygpo-qt5/src/DeviceUpdates.h diff --git a/3rdparty/libmygpo-qt/DeviceUpdates_p.h b/3rdparty/libmygpo-qt5/src/DeviceUpdates_p.h similarity index 100% rename from 3rdparty/libmygpo-qt/DeviceUpdates_p.h rename to 3rdparty/libmygpo-qt5/src/DeviceUpdates_p.h diff --git a/3rdparty/libmygpo-qt/Device_p.h b/3rdparty/libmygpo-qt5/src/Device_p.h similarity index 100% rename from 3rdparty/libmygpo-qt/Device_p.h rename to 3rdparty/libmygpo-qt5/src/Device_p.h diff --git a/3rdparty/libmygpo-qt/Episode.cpp b/3rdparty/libmygpo-qt5/src/Episode.cpp similarity index 100% rename from 3rdparty/libmygpo-qt/Episode.cpp rename to 3rdparty/libmygpo-qt5/src/Episode.cpp diff --git a/3rdparty/libmygpo-qt/Episode.h b/3rdparty/libmygpo-qt5/src/Episode.h similarity index 100% rename from 3rdparty/libmygpo-qt/Episode.h rename to 3rdparty/libmygpo-qt5/src/Episode.h diff --git a/3rdparty/libmygpo-qt/EpisodeAction.cpp b/3rdparty/libmygpo-qt5/src/EpisodeAction.cpp similarity index 100% rename from 3rdparty/libmygpo-qt/EpisodeAction.cpp rename to 3rdparty/libmygpo-qt5/src/EpisodeAction.cpp diff --git a/3rdparty/libmygpo-qt/EpisodeAction.h b/3rdparty/libmygpo-qt5/src/EpisodeAction.h similarity index 100% rename from 3rdparty/libmygpo-qt/EpisodeAction.h rename to 3rdparty/libmygpo-qt5/src/EpisodeAction.h diff --git a/3rdparty/libmygpo-qt/EpisodeActionList.cpp b/3rdparty/libmygpo-qt5/src/EpisodeActionList.cpp similarity index 100% rename from 3rdparty/libmygpo-qt/EpisodeActionList.cpp rename to 3rdparty/libmygpo-qt5/src/EpisodeActionList.cpp diff --git a/3rdparty/libmygpo-qt/EpisodeActionList.h b/3rdparty/libmygpo-qt5/src/EpisodeActionList.h similarity index 100% rename from 3rdparty/libmygpo-qt/EpisodeActionList.h rename to 3rdparty/libmygpo-qt5/src/EpisodeActionList.h diff --git a/3rdparty/libmygpo-qt/EpisodeActionList_p.h b/3rdparty/libmygpo-qt5/src/EpisodeActionList_p.h similarity index 100% rename from 3rdparty/libmygpo-qt/EpisodeActionList_p.h rename to 3rdparty/libmygpo-qt5/src/EpisodeActionList_p.h diff --git a/3rdparty/libmygpo-qt/EpisodeAction_p.h b/3rdparty/libmygpo-qt5/src/EpisodeAction_p.h similarity index 100% rename from 3rdparty/libmygpo-qt/EpisodeAction_p.h rename to 3rdparty/libmygpo-qt5/src/EpisodeAction_p.h diff --git a/3rdparty/libmygpo-qt/EpisodeList.cpp b/3rdparty/libmygpo-qt5/src/EpisodeList.cpp similarity index 100% rename from 3rdparty/libmygpo-qt/EpisodeList.cpp rename to 3rdparty/libmygpo-qt5/src/EpisodeList.cpp diff --git a/3rdparty/libmygpo-qt/EpisodeList.h b/3rdparty/libmygpo-qt5/src/EpisodeList.h similarity index 100% rename from 3rdparty/libmygpo-qt/EpisodeList.h rename to 3rdparty/libmygpo-qt5/src/EpisodeList.h diff --git a/3rdparty/libmygpo-qt/EpisodeList_p.h b/3rdparty/libmygpo-qt5/src/EpisodeList_p.h similarity index 100% rename from 3rdparty/libmygpo-qt/EpisodeList_p.h rename to 3rdparty/libmygpo-qt5/src/EpisodeList_p.h diff --git a/3rdparty/libmygpo-qt/Episode_p.h b/3rdparty/libmygpo-qt5/src/Episode_p.h similarity index 100% rename from 3rdparty/libmygpo-qt/Episode_p.h rename to 3rdparty/libmygpo-qt5/src/Episode_p.h diff --git a/3rdparty/libmygpo-qt/JsonCreator.cpp b/3rdparty/libmygpo-qt5/src/JsonCreator.cpp similarity index 100% rename from 3rdparty/libmygpo-qt/JsonCreator.cpp rename to 3rdparty/libmygpo-qt5/src/JsonCreator.cpp diff --git a/3rdparty/libmygpo-qt/JsonCreator.h b/3rdparty/libmygpo-qt5/src/JsonCreator.h similarity index 100% rename from 3rdparty/libmygpo-qt/JsonCreator.h rename to 3rdparty/libmygpo-qt5/src/JsonCreator.h diff --git a/3rdparty/libmygpo-qt/Podcast.cpp b/3rdparty/libmygpo-qt5/src/Podcast.cpp similarity index 100% rename from 3rdparty/libmygpo-qt/Podcast.cpp rename to 3rdparty/libmygpo-qt5/src/Podcast.cpp diff --git a/3rdparty/libmygpo-qt/Podcast.h b/3rdparty/libmygpo-qt5/src/Podcast.h similarity index 100% rename from 3rdparty/libmygpo-qt/Podcast.h rename to 3rdparty/libmygpo-qt5/src/Podcast.h diff --git a/3rdparty/libmygpo-qt/PodcastList.cpp b/3rdparty/libmygpo-qt5/src/PodcastList.cpp similarity index 100% rename from 3rdparty/libmygpo-qt/PodcastList.cpp rename to 3rdparty/libmygpo-qt5/src/PodcastList.cpp diff --git a/3rdparty/libmygpo-qt/PodcastList.h b/3rdparty/libmygpo-qt5/src/PodcastList.h similarity index 100% rename from 3rdparty/libmygpo-qt/PodcastList.h rename to 3rdparty/libmygpo-qt5/src/PodcastList.h diff --git a/3rdparty/libmygpo-qt/PodcastList_p.h b/3rdparty/libmygpo-qt5/src/PodcastList_p.h similarity index 100% rename from 3rdparty/libmygpo-qt/PodcastList_p.h rename to 3rdparty/libmygpo-qt5/src/PodcastList_p.h diff --git a/3rdparty/libmygpo-qt/Podcast_p.h b/3rdparty/libmygpo-qt5/src/Podcast_p.h similarity index 100% rename from 3rdparty/libmygpo-qt/Podcast_p.h rename to 3rdparty/libmygpo-qt5/src/Podcast_p.h diff --git a/3rdparty/libmygpo-qt/RequestHandler.cpp b/3rdparty/libmygpo-qt5/src/RequestHandler.cpp similarity index 100% rename from 3rdparty/libmygpo-qt/RequestHandler.cpp rename to 3rdparty/libmygpo-qt5/src/RequestHandler.cpp diff --git a/3rdparty/libmygpo-qt/RequestHandler.h b/3rdparty/libmygpo-qt5/src/RequestHandler.h similarity index 100% rename from 3rdparty/libmygpo-qt/RequestHandler.h rename to 3rdparty/libmygpo-qt5/src/RequestHandler.h diff --git a/3rdparty/libmygpo-qt/Settings.cpp b/3rdparty/libmygpo-qt5/src/Settings.cpp similarity index 100% rename from 3rdparty/libmygpo-qt/Settings.cpp rename to 3rdparty/libmygpo-qt5/src/Settings.cpp diff --git a/3rdparty/libmygpo-qt/Settings.h b/3rdparty/libmygpo-qt5/src/Settings.h similarity index 100% rename from 3rdparty/libmygpo-qt/Settings.h rename to 3rdparty/libmygpo-qt5/src/Settings.h diff --git a/3rdparty/libmygpo-qt/Settings_p.h b/3rdparty/libmygpo-qt5/src/Settings_p.h similarity index 100% rename from 3rdparty/libmygpo-qt/Settings_p.h rename to 3rdparty/libmygpo-qt5/src/Settings_p.h diff --git a/3rdparty/libmygpo-qt/Tag.cpp b/3rdparty/libmygpo-qt5/src/Tag.cpp similarity index 100% rename from 3rdparty/libmygpo-qt/Tag.cpp rename to 3rdparty/libmygpo-qt5/src/Tag.cpp diff --git a/3rdparty/libmygpo-qt/Tag.h b/3rdparty/libmygpo-qt5/src/Tag.h similarity index 100% rename from 3rdparty/libmygpo-qt/Tag.h rename to 3rdparty/libmygpo-qt5/src/Tag.h diff --git a/3rdparty/libmygpo-qt/TagList.cpp b/3rdparty/libmygpo-qt5/src/TagList.cpp similarity index 100% rename from 3rdparty/libmygpo-qt/TagList.cpp rename to 3rdparty/libmygpo-qt5/src/TagList.cpp diff --git a/3rdparty/libmygpo-qt/TagList.h b/3rdparty/libmygpo-qt5/src/TagList.h similarity index 100% rename from 3rdparty/libmygpo-qt/TagList.h rename to 3rdparty/libmygpo-qt5/src/TagList.h diff --git a/3rdparty/libmygpo-qt/TagList_p.h b/3rdparty/libmygpo-qt5/src/TagList_p.h similarity index 100% rename from 3rdparty/libmygpo-qt/TagList_p.h rename to 3rdparty/libmygpo-qt5/src/TagList_p.h diff --git a/3rdparty/libmygpo-qt/Tag_p.h b/3rdparty/libmygpo-qt5/src/Tag_p.h similarity index 100% rename from 3rdparty/libmygpo-qt/Tag_p.h rename to 3rdparty/libmygpo-qt5/src/Tag_p.h diff --git a/3rdparty/libmygpo-qt/UrlBuilder.cpp b/3rdparty/libmygpo-qt5/src/UrlBuilder.cpp similarity index 100% rename from 3rdparty/libmygpo-qt/UrlBuilder.cpp rename to 3rdparty/libmygpo-qt5/src/UrlBuilder.cpp diff --git a/3rdparty/libmygpo-qt/UrlBuilder.h b/3rdparty/libmygpo-qt5/src/UrlBuilder.h similarity index 100% rename from 3rdparty/libmygpo-qt/UrlBuilder.h rename to 3rdparty/libmygpo-qt5/src/UrlBuilder.h diff --git a/3rdparty/libmygpo-qt/Version.h.in b/3rdparty/libmygpo-qt5/src/Version.h.in similarity index 100% rename from 3rdparty/libmygpo-qt/Version.h.in rename to 3rdparty/libmygpo-qt5/src/Version.h.in diff --git a/3rdparty/libmygpo-qt/mygpo_export.h b/3rdparty/libmygpo-qt5/src/mygpo_export.h similarity index 97% rename from 3rdparty/libmygpo-qt/mygpo_export.h rename to 3rdparty/libmygpo-qt5/src/mygpo_export.h index d2a8c3a58..28980e2c6 100644 --- a/3rdparty/libmygpo-qt/mygpo_export.h +++ b/3rdparty/libmygpo-qt5/src/mygpo_export.h @@ -25,7 +25,7 @@ #include -#ifndef MYGPO_EXPORT +#ifndef MYGPO_STATIC # if defined(MYGPO_MAKEDLL) /* We are building this library */ # define MYGPO_EXPORT Q_DECL_EXPORT @@ -33,6 +33,8 @@ /* We are using this library */ # define MYGPO_EXPORT Q_DECL_IMPORT # endif +#else +# define MYGPO_EXPORT #endif #endif // MYGPO_EXPORT_H diff --git a/3rdparty/libmygpo-qt5/src/qjsonwrapper/Json.cpp b/3rdparty/libmygpo-qt5/src/qjsonwrapper/Json.cpp new file mode 100644 index 000000000..4a8c2ac36 --- /dev/null +++ b/3rdparty/libmygpo-qt5/src/qjsonwrapper/Json.cpp @@ -0,0 +1,123 @@ +/* Copyright 2014, Uwe L. Korn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "Json.h" + +// Qt version specific includes +#if QT_VERSION >= QT_VERSION_CHECK( 5, 0, 0 ) + #include + #include +#else + #include + #include + #include +#endif + +namespace QJsonWrapper +{ + +QVariantMap +qobject2qvariant( const QObject* object ) +{ +#if QT_VERSION >= QT_VERSION_CHECK( 5, 0, 0 ) + QVariantMap map; + if ( object == NULL ) + { + return map; + } + + const QMetaObject* metaObject = object->metaObject(); + for ( int i = 0; i < metaObject->propertyCount(); ++i ) + { + QMetaProperty metaproperty = metaObject->property( i ); + if ( metaproperty.isReadable() ) + { + map[ QLatin1String( metaproperty.name() ) ] = object->property( metaproperty.name() ); + } + } + return map; +#else + return QJson::QObjectHelper::qobject2qvariant( object ); +#endif +} + + +void +qvariant2qobject( const QVariantMap& variant, QObject* object ) +{ +#if QT_VERSION >= QT_VERSION_CHECK( 5, 0, 0 ) + for ( QVariantMap::const_iterator iter = variant.begin(); iter != variant.end(); ++iter ) + { + QVariant property = object->property( iter.key().toLatin1() ); + Q_ASSERT( property.isValid() ); + if ( property.isValid() ) + { + QVariant value = iter.value(); + if ( value.canConvert( property.type() ) ) + { + value.convert( property.type() ); + object->setProperty( iter.key().toLatin1(), value ); + } else if ( QString( QLatin1String("QVariant") ).compare( QLatin1String( property.typeName() ) ) == 0 ) { + object->setProperty( iter.key().toLatin1(), value ); + } + } + } +#else + QJson::QObjectHelper::qvariant2qobject( variant, object ); +#endif +} + + +QVariant +parseJson( const QByteArray& jsonData, bool* ok ) +{ +#if QT_VERSION >= QT_VERSION_CHECK( 5, 0, 0 ) + QJsonParseError error; + QJsonDocument doc = QJsonDocument::fromJson( jsonData, &error ); + if ( ok != NULL ) + { + *ok = ( error.error == QJsonParseError::NoError ); + } + return doc.toVariant(); +#else + QJson::Parser p; + return p.parse( jsonData, ok ); +#endif +} + + +QByteArray +toJson( const QVariant &variant, bool* ok ) +{ +#if QT_VERSION >= QT_VERSION_CHECK( 5, 0, 0 ) + QJsonDocument doc = QJsonDocument::fromVariant( variant ); + if ( ok != NULL ) + { + *ok = !doc.isNull(); + } + return doc.toJson( QJsonDocument::Compact ); +#else + QJson::Serializer serializer; + return serializer.serialize( variant, ok ); +#endif +} + +} diff --git a/3rdparty/libmygpo-qt5/src/qjsonwrapper/Json.h b/3rdparty/libmygpo-qt5/src/qjsonwrapper/Json.h new file mode 100644 index 000000000..36d53a0f9 --- /dev/null +++ b/3rdparty/libmygpo-qt5/src/qjsonwrapper/Json.h @@ -0,0 +1,36 @@ +/* Copyright 2014, Uwe L. Korn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#pragma once +#ifndef QJSONWRAPPER_JSON_H +#define QJSONWRAPPER_JSON_H + +#include + +namespace QJsonWrapper +{ + QVariantMap qobject2qvariant( const QObject* object ); + void qvariant2qobject( const QVariantMap& variant, QObject* object ); + QVariant parseJson( const QByteArray& jsonData, bool* ok = 0 ); + QByteArray toJson( const QVariant &variant, bool* ok = 0 ); +} + +#endif // QJSONWRAPPER_JSON_H diff --git a/3rdparty/qocoa/CMakeLists.txt b/3rdparty/qocoa/CMakeLists.txt index 92ac7ce29..df6ec7c5c 100644 --- a/3rdparty/qocoa/CMakeLists.txt +++ b/3rdparty/qocoa/CMakeLists.txt @@ -6,7 +6,7 @@ set(HEADERS qprogressindicatorspinning.h ) -qt4_wrap_cpp(MOC_SOURCES ${HEADERS}) +qt5_wrap_cpp(MOC_SOURCES ${HEADERS}) if(APPLE) list(APPEND SOURCES @@ -23,10 +23,15 @@ else() set(RESOURCES qprogressindicatorspinning_nonmac.qrc ) - qt4_add_resources(RESOURCES_SOURCES ${RESOURCES}) + qt5_add_resources(RESOURCES_SOURCES ${RESOURCES}) endif() add_library(Qocoa STATIC ${SOURCES} ${MOC_SOURCES} ${RESOURCES_SOURCES} ) -target_link_libraries(Qocoa ${QT_LIBRARIES}) + +if(APPLE) + target_link_libraries(Qocoa Qt5::Widgets Qt5::MacExtras) +else() + target_link_libraries(Qocoa Qt5::Widgets) +endif() diff --git a/3rdparty/qocoa/qbutton_mac.mm b/3rdparty/qocoa/qbutton_mac.mm index 93f7c7c8b..b7e1bc0c5 100644 --- a/3rdparty/qocoa/qbutton_mac.mm +++ b/3rdparty/qocoa/qbutton_mac.mm @@ -37,7 +37,9 @@ public: switch(bezelStyle) { case QButton::Disclosure: case QButton::Circular: +#ifdef __MAC_10_7 case QButton::Inline: +#endif case QButton::RoundedDisclosure: case QButton::HelpButton: [nsButton setTitle:@""]; @@ -55,7 +57,7 @@ public: font = [NSFont fontWithName:@"Lucida Grande Bold" size:12]; break; -#ifdef MAC_OS_X_VERSION_10_7 +#ifdef __MAC_10_7 case QButton::Inline: font = [NSFont boldSystemFontOfSize:[NSFont systemFontSizeForControlSize:NSSmallControlSize]]; break; @@ -112,7 +114,7 @@ public: qButton->setFixedHeight(22); qButton->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed); break; -#ifdef MAC_OS_X_VERSION_10_7 +#ifdef __MAC_10_7 case QButton::Inline: qButton->setMinimumWidth(10); qButton->setFixedHeight(16); @@ -130,7 +132,7 @@ public: [nsButton setButtonType:NSMomentaryPushInButton]; } - [nsButton setBezelStyle:bezelStyle]; + [nsButton setBezelStyle:(__bridge NSBezelStyle)bezelStyle]; } void clicked() diff --git a/3rdparty/qocoa/qocoa_mac.h b/3rdparty/qocoa/qocoa_mac.h index ced431173..35a9deb1d 100644 --- a/3rdparty/qocoa/qocoa_mac.h +++ b/3rdparty/qocoa/qocoa_mac.h @@ -20,10 +20,12 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +#include #include +#include #include #include -#include +#include static inline NSString* fromQString(const QString &string) { @@ -41,14 +43,13 @@ static inline QString toQString(NSString *string) static inline NSImage* fromQPixmap(const QPixmap &pixmap) { - CGImageRef cgImage = pixmap.toMacCGImageRef(); - return [[NSImage alloc] initWithCGImage:cgImage size:NSZeroSize]; + CGImageRef cgImage = QtMac::toCGImageRef(pixmap); + return [[NSImage alloc] initWithCGImage:cgImage size:NSZeroSize]; } -static inline void setupLayout(void *cocoaView, QWidget *parent) -{ - parent->setAttribute(Qt::WA_NativeWindow); - QVBoxLayout *layout = new QVBoxLayout(parent); - layout->setMargin(0); - layout->addWidget(new QMacCocoaViewContainer(cocoaView, parent)); +static inline void setupLayout(NSView* cocoaView, QWidget* parent) { + parent->setAttribute(Qt::WA_NativeWindow); + QVBoxLayout* layout = new QVBoxLayout(parent); + layout->setMargin(0); + layout->addWidget(new QMacCocoaViewContainer(cocoaView, parent)); } diff --git a/3rdparty/qsqlite/CMakeLists.txt b/3rdparty/qsqlite/CMakeLists.txt index 48ac16161..19e6bf7bf 100644 --- a/3rdparty/qsqlite/CMakeLists.txt +++ b/3rdparty/qsqlite/CMakeLists.txt @@ -1,22 +1,23 @@ -cmake_minimum_required(VERSION 2.6) +cmake_minimum_required(VERSION 2.8.11) add_definitions(-DQT_STATICPLUGIN) # Source files set(SQLITE-SOURCES qsql_sqlite.cpp - smain.cpp clementinesqlcachedresult.cpp + smain.cpp ) # Header files that have Q_OBJECT in set(SQLITE-MOC-HEADERS qsql_sqlite.h + smain.h ) set(SQLITE-WIN32-RESOURCES qsqlite_resource.rc) -qt4_wrap_cpp(SQLITE-SOURCES-MOC ${SQLITE-MOC-HEADERS}) +qt5_wrap_cpp(SQLITE-SOURCES-MOC ${SQLITE-MOC-HEADERS}) include_directories(${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}) @@ -40,7 +41,10 @@ add_library(qsqlite STATIC ${SQLITE-SOURCES-MOC} ${SQLITE-WIN32-RESOURCES} ) + +set_property(TARGET qsqlite PROPERTY QT_STATICPLUGIN 1) + target_link_libraries(qsqlite + Qt5::Core Qt5::Sql ${SQLITE_LIBRARIES} - ${QT_LIBRARIES} ) diff --git a/3rdparty/qsqlite/clementinesqlcachedresult.cpp b/3rdparty/qsqlite/clementinesqlcachedresult.cpp index adca3ffec..5b3d4c1f7 100644 --- a/3rdparty/qsqlite/clementinesqlcachedresult.cpp +++ b/3rdparty/qsqlite/clementinesqlcachedresult.cpp @@ -1,17 +1,18 @@ /**************************************************************************** ** -** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal ** ** This file is part of the QtSql module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser @@ -21,30 +22,31 @@ ** ensure the GNU Lesser General Public License version 2.1 requirements ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -** -** -** -** -** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. ** ** ** $QT_END_LICENSE$ ** ****************************************************************************/ -#include "clementinesqlcachedresult.h" - #include #include #include +#include "clementinesqlcachedresult.h" + +QT_BEGIN_NAMESPACE + /* ClementineSqlCachedResult is a convenience class for databases that only allow forward only fetching. It will cache all the results so we can iterate @@ -302,12 +304,19 @@ ClementineSqlCachedResult::ValueCache &ClementineSqlCachedResult::cache() void ClementineSqlCachedResult::virtual_hook(int id, void *data) { - switch (id) { - case QSqlResult::DetachFromResultSet: - case QSqlResult::SetNumericalPrecision: - cleanup(); - break; - default: - QSqlResult::virtual_hook(id, data); - } + QSqlResult::virtual_hook(id, data); } + +void ClementineSqlCachedResult::detachFromResultSet() +{ + cleanup(); +} + +void ClementineSqlCachedResult::setNumericalPrecisionPolicy(QSql::NumericalPrecisionPolicy policy) +{ + QSqlResult::setNumericalPrecisionPolicy(policy); + cleanup(); +} + + +QT_END_NAMESPACE diff --git a/3rdparty/qsqlite/clementinesqlcachedresult.h b/3rdparty/qsqlite/clementinesqlcachedresult.h index 1951789da..c170270ae 100644 --- a/3rdparty/qsqlite/clementinesqlcachedresult.h +++ b/3rdparty/qsqlite/clementinesqlcachedresult.h @@ -1,17 +1,18 @@ /**************************************************************************** ** -** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal ** ** This file is part of the QtSql module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser @@ -21,28 +22,40 @@ ** ensure the GNU Lesser General Public License version 2.1 requirements ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -** -** -** -** -** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. ** ** ** $QT_END_LICENSE$ ** ****************************************************************************/ -#ifndef CLEMENTINECACHEDRESULT_P_H -#define CLEMENTINECACHEDRESULT_P_H +#ifndef QSQLCACHEDRESULT_P_H +#define QSQLCACHEDRESULT_P_H -#include +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +QT_BEGIN_NAMESPACE class QVariant; template class QVector; @@ -77,9 +90,13 @@ protected: ValueCache &cache(); void virtual_hook(int id, void *data); + void detachFromResultSet(); + void setNumericalPrecisionPolicy(QSql::NumericalPrecisionPolicy policy); private: bool cacheNext(); ClementineSqlCachedResultPrivate *d; }; -#endif // CLEMENTINESQLCACHEDRESULT_P_H +QT_END_NAMESPACE + +#endif // QSQLCACHEDRESULT_P_H diff --git a/3rdparty/qsqlite/qsql_sqlite.cpp b/3rdparty/qsqlite/qsql_sqlite.cpp index c7caae1b1..33d022848 100644 --- a/3rdparty/qsqlite/qsql_sqlite.cpp +++ b/3rdparty/qsqlite/qsql_sqlite.cpp @@ -1,17 +1,18 @@ /**************************************************************************** ** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal ** ** This file is part of the QtSql module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ -** Commercial Usage -** Licensees holding valid Qt Commercial licenses may use this file in -** accordance with the Qt Commercial License Agreement provided with the +** 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 Nokia. +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser @@ -21,8 +22,8 @@ ** ensure the GNU Lesser General Public License version 2.1 requirements ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** GNU General Public License Usage @@ -33,8 +34,7 @@ ** ensure the GNU General Public License version 3.0 requirements will be ** met: http://www.gnu.org/copyleft/gpl.html. ** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. +** ** $QT_END_LICENSE$ ** ****************************************************************************/ @@ -59,7 +59,10 @@ #include +Q_DECLARE_OPAQUE_POINTER(sqlite3*) Q_DECLARE_METATYPE(sqlite3*) + +Q_DECLARE_OPAQUE_POINTER(sqlite3_stmt*) Q_DECLARE_METATYPE(sqlite3_stmt*) QT_BEGIN_NAMESPACE @@ -84,10 +87,14 @@ static QVariant::Type qGetColumnType(const QString &tpName) return QVariant::Int; if (typeName == QLatin1String("double") || typeName == QLatin1String("float") + || typeName == QLatin1String("real") || typeName.startsWith(QLatin1String("numeric"))) return QVariant::Double; if (typeName == QLatin1String("blob")) return QVariant::ByteArray; + if (typeName == QLatin1String("boolean") + || typeName == QLatin1String("bool")) + return QVariant::Bool; return QVariant::String; } @@ -95,7 +102,7 @@ static QSqlError qMakeError(sqlite3 *access, const QString &descr, QSqlError::Er int errorCode = -1) { return QSqlError(descr, - QString::fromUtf16(static_cast(sqlite3_errmsg16(access))), + QString(reinterpret_cast(sqlite3_errmsg16(access))), type, errorCode); } @@ -104,6 +111,7 @@ class QSQLiteDriverPrivate public: inline QSQLiteDriverPrivate() : access(0) {} sqlite3 *access; + QList results; }; @@ -162,19 +170,44 @@ void QSQLiteResultPrivate::initColumns(bool emptyResultset) q->init(nCols); for (int i = 0; i < nCols; ++i) { - QString colName = QString::fromUtf16( - static_cast(sqlite3_column_name16(stmt, i)) + QString colName = QString(reinterpret_cast( + sqlite3_column_name16(stmt, i)) ).remove(QLatin1Char('"')); // must use typeName for resolving the type to match QSqliteDriver::record - QString typeName = QString::fromUtf16( - static_cast(sqlite3_column_decltype16(stmt, i))); - - int dotIdx = colName.lastIndexOf(QLatin1Char('.')); - QSqlField fld(colName.mid(dotIdx == -1 ? 0 : dotIdx + 1), qGetColumnType(typeName)); - + QString typeName = QString(reinterpret_cast( + sqlite3_column_decltype16(stmt, i))); // sqlite3_column_type is documented to have undefined behavior if the result set is empty int stp = emptyResultset ? -1 : sqlite3_column_type(stmt, i); + + QVariant::Type fieldType; + + if (!typeName.isEmpty()) { + fieldType = qGetColumnType(typeName); + } else { + // Get the proper type for the field based on stp value + switch (stp) { + case SQLITE_INTEGER: + fieldType = QVariant::Int; + break; + case SQLITE_FLOAT: + fieldType = QVariant::Double; + break; + case SQLITE_BLOB: + fieldType = QVariant::ByteArray; + break; + case SQLITE_TEXT: + fieldType = QVariant::String; + break; + case SQLITE_NULL: + default: + fieldType = QVariant::Invalid; + break; + } + } + + int dotIdx = colName.lastIndexOf(QLatin1Char('.')); + QSqlField fld(colName.mid(dotIdx == -1 ? 0 : dotIdx + 1), fieldType); fld.setSqlType(stp); rInf.append(fld); } @@ -245,9 +278,9 @@ bool QSQLiteResultPrivate::fetchNext(ClementineSqlCachedResult::ValueCache &valu values[i + idx] = QVariant(QVariant::String); break; default: - values[i + idx] = QString::fromUtf16(static_cast( + values[i + idx] = QString(reinterpret_cast( sqlite3_column_text16(stmt, i)), - sqlite3_column_bytes16(stmt, i) / sizeof(ushort)); + sqlite3_column_bytes16(stmt, i) / sizeof(QChar)); break; } } @@ -259,6 +292,7 @@ bool QSQLiteResultPrivate::fetchNext(ClementineSqlCachedResult::ValueCache &valu q->setAt(QSql::AfterLastRow); sqlite3_reset(stmt); return false; + case SQLITE_CONSTRAINT: case SQLITE_ERROR: // SQLITE_ERROR is a generic error code and we must call sqlite3_reset() // to get the specific error message. @@ -285,24 +319,21 @@ QSQLiteResult::QSQLiteResult(const QSQLiteDriver* db) { d = new QSQLiteResultPrivate(this); d->access = db->d->access; + db->d->results.append(this); } QSQLiteResult::~QSQLiteResult() { + const QSqlDriver *sqlDriver = driver(); + if (sqlDriver) + qobject_cast(sqlDriver)->d->results.removeOne(this); d->cleanup(); delete d; } void QSQLiteResult::virtual_hook(int id, void *data) { - switch (id) { - case QSqlResult::DetachFromResultSet: - if (d->stmt) - sqlite3_reset(d->stmt); - break; - default: - ClementineSqlCachedResult::virtual_hook(id, data); - } + ClementineSqlCachedResult::virtual_hook(id, data); } bool QSQLiteResult::reset(const QString &query) @@ -321,12 +352,14 @@ bool QSQLiteResult::prepare(const QString &query) setSelect(false); + const void *pzTail = NULL; + #if (SQLITE_VERSION_NUMBER >= 3003011) int res = sqlite3_prepare16_v2(d->access, query.constData(), (query.size() + 1) * sizeof(QChar), - &d->stmt, 0); + &d->stmt, &pzTail); #else int res = sqlite3_prepare16(d->access, query.constData(), (query.size() + 1) * sizeof(QChar), - &d->stmt, 0); + &d->stmt, &pzTail); #endif if (res != SQLITE_OK) { @@ -334,6 +367,11 @@ bool QSQLiteResult::prepare(const QString &query) "Unable to execute statement"), QSqlError::StatementError, res)); d->finalize(); return false; + } else if (pzTail && !QString(reinterpret_cast(pzTail)).trimmed().isEmpty()) { + setLastError(qMakeError(d->access, QCoreApplication::translate("QSQLiteResult", + "Unable to execute multiple statements at a time"), QSqlError::StatementError, SQLITE_MISUSE)); + d->finalize(); + return false; } return true; } @@ -371,6 +409,7 @@ bool QSQLiteResult::exec() ba->size(), SQLITE_STATIC); break; } case QVariant::Int: + case QVariant::Bool: res = sqlite3_bind_int(d->stmt, i + 1, value.toInt()); break; case QVariant::Double: @@ -403,7 +442,7 @@ bool QSQLiteResult::exec() } } else { setLastError(QSqlError(QCoreApplication::translate("QSQLiteResult", - "Parameter count mismatch"), QString(), QSqlError::StatementError)); + "Parameter count mismatch") + QString::number(paramCount, 10) + "/" + QString::number(values.count(), 10), QString(), QSqlError::StatementError)); return false; } d->skippedStatus = d->fetchNext(d->firstRow, 0, true); @@ -449,9 +488,15 @@ QSqlRecord QSQLiteResult::record() const return d->rInf; } +void QSQLiteResult::detachFromResultSet() +{ + if (d->stmt) + sqlite3_reset(d->stmt); +} + QVariant QSQLiteResult::handle() const { - return qVariantFromValue(d->stmt); + return QVariant::fromValue(d->stmt); } ///////////////////////////////////////////////////////// @@ -500,32 +545,6 @@ bool QSQLiteDriver::hasFeature(DriverFeature f) const return false; } -static int qGetSqliteTimeout(QString opts) -{ - enum { DefaultTimeout = 5000 }; - - opts.remove(QLatin1Char(' ')); - foreach(QString option, opts.split(QLatin1Char(';'))) { - if (option.startsWith(QLatin1String("QSQLITE_BUSY_TIMEOUT="))) { - bool ok; - int nt = option.mid(21).toInt(&ok); - if (ok) - return nt; - } - } - return DefaultTimeout; -} - -static int qGetSqliteOpenMode(QString opts) -{ - opts.remove(QLatin1Char(' ')); - foreach(QString option, opts.split(QLatin1Char(';'))) { - if (option == QLatin1String("QSQLITE_OPEN_READONLY")) - return SQLITE_OPEN_READONLY; - } - return SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE; -} - /* SQLite dbs have no user name, passwords, hosts or ports. just file names. @@ -537,13 +556,35 @@ bool QSQLiteDriver::open(const QString & db, const QString &, const QString &, c if (db.isEmpty()) return false; + bool sharedCache = false; + int openMode = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, timeOut=5000; + QStringList opts=QString(conOpts).remove(QLatin1Char(' ')).split(QLatin1Char(';')); + foreach(const QString &option, opts) { + if (option.startsWith(QLatin1String("QSQLITE_BUSY_TIMEOUT="))) { + bool ok; + int nt = option.mid(21).toInt(&ok); + if (ok) + timeOut = nt; + } + if (option == QLatin1String("QSQLITE_OPEN_READONLY")) + openMode = SQLITE_OPEN_READONLY; + if (option == QLatin1String("QSQLITE_ENABLE_SHARED_CACHE")) + sharedCache = true; + } - if (sqlite3_open_v2(db.toUtf8().constData(), &d->access, qGetSqliteOpenMode(conOpts), NULL) == SQLITE_OK) { - sqlite3_busy_timeout(d->access, qGetSqliteTimeout(conOpts)); + sqlite3_enable_shared_cache(sharedCache); + + if (sqlite3_open_v2(db.toUtf8().constData(), &d->access, openMode, NULL) == SQLITE_OK) { + sqlite3_busy_timeout(d->access, timeOut); setOpen(true); setOpenError(false); return true; } else { + if (d->access) { + sqlite3_close(d->access); + d->access = 0; + } + setLastError(qMakeError(d->access, tr("Error opening database"), QSqlError::ConnectionError)); setOpenError(true); @@ -554,6 +595,10 @@ bool QSQLiteDriver::open(const QString & db, const QString &, const QString &, c void QSQLiteDriver::close() { if (isOpen()) { + foreach (QSQLiteResult *result, d->results) { + result->d->finalize(); + } + if (sqlite3_close(d->access) != SQLITE_OK) setLastError(qMakeError(d->access, tr("Error closing database"), QSqlError::ConnectionError)); @@ -705,7 +750,7 @@ QSqlRecord QSQLiteDriver::record(const QString &tbl) const QVariant QSQLiteDriver::handle() const { - return qVariantFromValue(d->access); + return QVariant::fromValue(d->access); } QString QSQLiteDriver::escapeIdentifier(const QString &identifier, IdentifierType type) const diff --git a/3rdparty/qsqlite/qsql_sqlite.h b/3rdparty/qsqlite/qsql_sqlite.h index f949aefe8..78db7303b 100644 --- a/3rdparty/qsqlite/qsql_sqlite.h +++ b/3rdparty/qsqlite/qsql_sqlite.h @@ -1,17 +1,18 @@ /**************************************************************************** ** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal ** ** This file is part of the QtSql module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ -** Commercial Usage -** Licensees holding valid Qt Commercial licenses may use this file in -** accordance with the Qt Commercial License Agreement provided with the +** 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 Nokia. +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser @@ -21,8 +22,8 @@ ** ensure the GNU Lesser General Public License version 2.1 requirements ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** GNU General Public License Usage @@ -33,8 +34,7 @@ ** ensure the GNU General Public License version 3.0 requirements will be ** met: http://www.gnu.org/copyleft/gpl.html. ** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. +** ** $QT_END_LICENSE$ ** ****************************************************************************/ @@ -42,8 +42,8 @@ #ifndef QSQL_SQLITE_H #define QSQL_SQLITE_H -#include -#include +#include +#include #include "clementinesqlcachedresult.h" struct sqlite3; @@ -79,6 +79,7 @@ protected: int numRowsAffected(); QVariant lastInsertId() const; QSqlRecord record() const; + void detachFromResultSet(); void virtual_hook(int id, void *data); private: diff --git a/3rdparty/qsqlite/qsqlite.json b/3rdparty/qsqlite/qsqlite.json new file mode 100644 index 000000000..0c105eade --- /dev/null +++ b/3rdparty/qsqlite/qsqlite.json @@ -0,0 +1,3 @@ +{ + "Keys": [ "QSQLITE" ] +} diff --git a/3rdparty/qsqlite/smain.cpp b/3rdparty/qsqlite/smain.cpp index 4fb132b5e..35b6b5d71 100644 --- a/3rdparty/qsqlite/smain.cpp +++ b/3rdparty/qsqlite/smain.cpp @@ -1,59 +1,40 @@ /**************************************************************************** ** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal ** ** This file is part of the plugins of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial Usage -** Licensees holding valid Qt Commercial licenses may use this file in -** accordance with the Qt Commercial License Agreement provided with the +** $QT_BEGIN_LICENSE:LGPL21$ +** 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 Nokia. +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. ** $QT_END_LICENSE$ ** ****************************************************************************/ -#include -#include -#include "qsql_sqlite.h" +#include "smain.h" QT_BEGIN_NAMESPACE -class QSQLiteDriverPlugin : public QSqlDriverPlugin -{ -public: - QSQLiteDriverPlugin(); - - QSqlDriver* create(const QString &); - QStringList keys() const; -}; - QSQLiteDriverPlugin::QSQLiteDriverPlugin() : QSqlDriverPlugin() { @@ -68,14 +49,4 @@ QSqlDriver* QSQLiteDriverPlugin::create(const QString &name) return 0; } -QStringList QSQLiteDriverPlugin::keys() const -{ - QStringList l; - l << QLatin1String("QSQLITE"); - return l; -} - -Q_EXPORT_STATIC_PLUGIN(QSQLiteDriverPlugin) -Q_EXPORT_PLUGIN2(qsqlite, QSQLiteDriverPlugin) - QT_END_NAMESPACE diff --git a/3rdparty/qsqlite/smain.h b/3rdparty/qsqlite/smain.h new file mode 100644 index 000000000..1d91a4544 --- /dev/null +++ b/3rdparty/qsqlite/smain.h @@ -0,0 +1,51 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include "qsql_sqlite.h" + +QT_BEGIN_NAMESPACE + +class QSQLiteDriverPlugin : public QSqlDriverPlugin +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QSqlDriverFactoryInterface" FILE "qsqlite.json") + +public: + QSQLiteDriverPlugin(); + + QSqlDriver* create(const QString &); +}; + +QT_END_NAMESPACE diff --git a/3rdparty/qsqlite/smain.patch b/3rdparty/qsqlite/smain.patch deleted file mode 100644 index e5e596ecc..000000000 --- a/3rdparty/qsqlite/smain.patch +++ /dev/null @@ -1,11 +0,0 @@ ---- smain.cpp.old 2010-03-22 17:34:03.000000000 +0000 -+++ smain.cpp 2010-03-22 17:34:08.000000000 +0000 -@@ -41,7 +41,7 @@ - - #include - #include --#include "../../../../src/sql/drivers/sqlite/qsql_sqlite.h" -+#include "qsql_sqlite.h" - - QT_BEGIN_NAMESPACE - diff --git a/3rdparty/qtiocompressor/CMakeLists.txt b/3rdparty/qtiocompressor/CMakeLists.txt index f339daba9..bbead7d9e 100644 --- a/3rdparty/qtiocompressor/CMakeLists.txt +++ b/3rdparty/qtiocompressor/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 2.6) +cmake_minimum_required(VERSION 2.8.11) set(IOCOMPRESSOR-SOURCES qtiocompressor.cpp @@ -8,9 +8,11 @@ set(IOCOMPRESSOR-MOC-HEADERS qtiocompressor.h ) -QT4_WRAP_CPP(IOCOMPRESSOR-SOURCES-MOC ${IOCOMPRESSOR-MOC-HEADERS}) +QT5_WRAP_CPP(IOCOMPRESSOR-SOURCES-MOC ${IOCOMPRESSOR-MOC-HEADERS}) ADD_LIBRARY(qtiocompressor STATIC ${IOCOMPRESSOR-SOURCES} ${IOCOMPRESSOR-SOURCES-MOC} ) + +target_link_libraries(qtiocompressor Qt5::Core) diff --git a/3rdparty/qtiocompressor/qtiocompressor.h b/3rdparty/qtiocompressor/qtiocompressor.h index 61284a5dc..eea9b6dfa 100644 --- a/3rdparty/qtiocompressor/qtiocompressor.h +++ b/3rdparty/qtiocompressor/qtiocompressor.h @@ -49,7 +49,7 @@ #include -#if defined(Q_WS_WIN) +#if defined(Q_OS_WIN) # if !defined(QT_QTIOCOMPRESSOR_EXPORT) && !defined(QT_QTIOCOMPRESSOR_IMPORT) # define QT_QTIOCOMPRESSOR_EXPORT # elif defined(QT_QTIOCOMPRESSOR_IMPORT) diff --git a/3rdparty/qtsingleapplication/CMakeLists.txt b/3rdparty/qtsingleapplication/CMakeLists.txt index 29f7844d5..e04ade978 100644 --- a/3rdparty/qtsingleapplication/CMakeLists.txt +++ b/3rdparty/qtsingleapplication/CMakeLists.txt @@ -1,9 +1,8 @@ -cmake_minimum_required(VERSION 2.6) +cmake_minimum_required(VERSION 2.8.11) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --std=c++0x") set(SINGLEAPP-SOURCES qtlocalpeer.cpp - qtlockedfile.cpp qtsingleapplication.cpp qtsinglecoreapplication.cpp ) @@ -20,9 +19,11 @@ elseif(WIN32) set(SINGLEAPP-SOURCES ${SINGLEAPP-SOURCES} qtlockedfile_unix.cpp) endif(WIN32) -QT4_WRAP_CPP(SINGLEAPP-SOURCES-MOC ${SINGLEAPP-MOC-HEADERS}) +QT5_WRAP_CPP(SINGLEAPP-SOURCES-MOC ${SINGLEAPP-MOC-HEADERS}) ADD_LIBRARY(qtsingleapplication STATIC ${SINGLEAPP-SOURCES} ${SINGLEAPP-SOURCES-MOC} ) + +target_link_libraries(qtsingleapplication Qt5::Core Qt5::Widgets Qt5::Network) diff --git a/3rdparty/qtsingleapplication/QtLockedFile b/3rdparty/qtsingleapplication/QtLockedFile deleted file mode 100644 index 16b48ba9d..000000000 --- a/3rdparty/qtsingleapplication/QtLockedFile +++ /dev/null @@ -1 +0,0 @@ -#include "qtlockedfile.h" diff --git a/3rdparty/qtsingleapplication/QtSingleApplication b/3rdparty/qtsingleapplication/QtSingleApplication deleted file mode 100644 index d111bf72d..000000000 --- a/3rdparty/qtsingleapplication/QtSingleApplication +++ /dev/null @@ -1 +0,0 @@ -#include "qtsingleapplication.h" diff --git a/3rdparty/qtsingleapplication/qtlocalpeer.cpp b/3rdparty/qtsingleapplication/qtlocalpeer.cpp index bb205eaf0..d65dda3ee 100644 --- a/3rdparty/qtsingleapplication/qtlocalpeer.cpp +++ b/3rdparty/qtsingleapplication/qtlocalpeer.cpp @@ -1,58 +1,52 @@ /**************************************************************************** -** -** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. +** ** Contact: Nokia Corporation (qt-info@nokia.com) -** +** ** This file is part of a Qt Solutions component. ** -** Commercial Usage -** Licensees holding valid Qt Commercial licenses may use this file in -** accordance with the Qt Solutions Commercial License Agreement provided -** with the Software or, alternatively, in accordance with the terms -** contained in a written agreement between you and Nokia. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain -** additional rights. These rights are described in the Nokia Qt LGPL -** Exception version 1.1, included in the file LGPL_EXCEPTION.txt in this -** package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** Please note Third Party Software included with Qt Solutions may impose -** additional restrictions and it is the user's responsibility to ensure -** that they have met the licensing requirements of the GPL, LGPL, or Qt -** Solutions Commercial license and the relevant license of the Third -** Party Software they are using. -** -** If you are unsure which license is appropriate for your use, please -** contact Nokia at qt-info@nokia.com. -** +** 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 Nokia Corporation and its Subsidiary(-ies) 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." +** ****************************************************************************/ #include "qtlocalpeer.h" -#include -#include -#include +#include +#include +#include +#include #if defined(Q_OS_WIN) -#include -#include +#include +#include typedef BOOL(WINAPI*PProcessIdToSessionId)(DWORD,DWORD*); static PProcessIdToSessionId pProcessIdToSessionId = 0; #endif @@ -107,7 +101,6 @@ QtLocalPeer::QtLocalPeer(QObject* parent, const QString &appId) + QLatin1Char('/') + socketName + QLatin1String("-lockfile"); lockFile.setFileName(lockName); - lockFileCreated = !lockFile.exists(); lockFile.open(QIODevice::ReadWrite); } @@ -118,8 +111,7 @@ bool QtLocalPeer::isClient() if (lockFile.isLocked()) return false; - if (!lockFile.lock(QtLockedFile::WriteLock, false)) - return true; + if (!lockFile.lock(QtLockedFile::WriteLock, false)) return true; bool res = server->listen(socketName); #if defined(Q_OS_UNIX) && (QT_VERSION >= QT_VERSION_CHECK(4,5,0)) @@ -137,16 +129,6 @@ bool QtLocalPeer::isClient() bool QtLocalPeer::sendMessage(const QString &message, int timeout) -{ - return sendMessage(message.toUtf8(), timeout); -} - -bool QtLocalPeer::sendMessage(const char* message, int timeout) -{ - return sendMessage(QByteArray(message), timeout); -} - -bool QtLocalPeer::sendMessage(const QByteArray &message, int timeout) { if (!isClient()) return false; @@ -170,11 +152,15 @@ bool QtLocalPeer::sendMessage(const QByteArray &message, int timeout) if (!connOk) return false; + QByteArray uMsg(message.toUtf8()); QDataStream ds(&socket); - ds.writeBytes(message.constData(), message.size()); + ds.writeBytes(uMsg.constData(), uMsg.size()); bool res = socket.waitForBytesWritten(timeout); - res &= socket.waitForReadyRead(timeout); // wait for ack - res &= (socket.read(qstrlen(ack)) == ack); + if (res) { + res &= socket.waitForReadyRead(timeout); // wait for ack + if (res) + res &= (socket.read(qstrlen(ack)) == ack); + } return res; } @@ -200,19 +186,13 @@ void QtLocalPeer::receiveConnection() uMsgBuf += got; } while (remaining && got >= 0 && socket->waitForReadyRead(2000)); if (got < 0) { - qWarning() << "QtLocalPeer: Message reception failed" << socket->errorString(); + qWarning("QtLocalPeer: Message reception failed %s", socket->errorString().toLatin1().constData()); delete socket; return; } + QString message(QString::fromUtf8(uMsg)); socket->write(ack, qstrlen(ack)); socket->waitForBytesWritten(1000); delete socket; - emit messageReceived(uMsg); //### (might take a long time to return) - emit messageReceived(QString::fromUtf8(uMsg)); -} - -QtLocalPeer::~QtLocalPeer () -{ - if (lockFileCreated) - lockFile.remove(); + emit messageReceived(message); //### (might take a long time to return) } diff --git a/3rdparty/qtsingleapplication/qtlocalpeer.h b/3rdparty/qtsingleapplication/qtlocalpeer.h index 82b894633..8b1945b6a 100644 --- a/3rdparty/qtsingleapplication/qtlocalpeer.h +++ b/3rdparty/qtsingleapplication/qtlocalpeer.h @@ -1,53 +1,48 @@ /**************************************************************************** -** -** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. +** ** Contact: Nokia Corporation (qt-info@nokia.com) -** +** ** This file is part of a Qt Solutions component. ** -** Commercial Usage -** Licensees holding valid Qt Commercial licenses may use this file in -** accordance with the Qt Solutions Commercial License Agreement provided -** with the Software or, alternatively, in accordance with the terms -** contained in a written agreement between you and Nokia. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain -** additional rights. These rights are described in the Nokia Qt LGPL -** Exception version 1.1, included in the file LGPL_EXCEPTION.txt in this -** package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** Please note Third Party Software included with Qt Solutions may impose -** additional restrictions and it is the user's responsibility to ensure -** that they have met the licensing requirements of the GPL, LGPL, or Qt -** Solutions Commercial license and the relevant license of the Third -** Party Software they are using. -** -** If you are unsure which license is appropriate for your use, please -** contact Nokia at qt-info@nokia.com. -** +** 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 Nokia Corporation and its Subsidiary(-ies) 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." +** ****************************************************************************/ +#ifndef QTLOCALPEER_H +#define QTLOCALPEER_H -#include -#include -#include +#include +#include +#include #include "qtlockedfile.h" @@ -57,18 +52,13 @@ class QtLocalPeer : public QObject public: QtLocalPeer(QObject *parent = 0, const QString &appId = QString()); - ~QtLocalPeer (); bool isClient(); bool sendMessage(const QString &message, int timeout); - bool sendMessage(const QByteArray &message, int timeout); - bool sendMessage(const char* message, int timeout); QString applicationId() const { return id; } Q_SIGNALS: void messageReceived(const QString &message); - void messageReceived(const QByteArray &message); - void messageReceived(const char* message); protected Q_SLOTS: void receiveConnection(); @@ -79,7 +69,8 @@ protected: QLocalServer* server; QtLockedFile lockFile; -private: + private: static const char* ack; - bool lockFileCreated; }; + +#endif // QTLOCALPEER_H diff --git a/3rdparty/qtsingleapplication/qtlockedfile.cpp b/3rdparty/qtsingleapplication/qtlockedfile.cpp index 2cf080584..3e73ba652 100644 --- a/3rdparty/qtsingleapplication/qtlockedfile.cpp +++ b/3rdparty/qtsingleapplication/qtlockedfile.cpp @@ -1,47 +1,40 @@ /**************************************************************************** -** -** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. +** ** Contact: Nokia Corporation (qt-info@nokia.com) -** +** ** This file is part of a Qt Solutions component. ** -** Commercial Usage -** Licensees holding valid Qt Commercial licenses may use this file in -** accordance with the Qt Solutions Commercial License Agreement provided -** with the Software or, alternatively, in accordance with the terms -** contained in a written agreement between you and Nokia. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain -** additional rights. These rights are described in the Nokia Qt LGPL -** Exception version 1.1, included in the file LGPL_EXCEPTION.txt in this -** package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** Please note Third Party Software included with Qt Solutions may impose -** additional restrictions and it is the user's responsibility to ensure -** that they have met the licensing requirements of the GPL, LGPL, or Qt -** Solutions Commercial license and the relevant license of the Third -** Party Software they are using. -** -** If you are unsure which license is appropriate for your use, please -** contact Nokia at qt-info@nokia.com. -** +** 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 Nokia Corporation and its Subsidiary(-ies) 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." +** ****************************************************************************/ #include "qtlockedfile.h" diff --git a/3rdparty/qtsingleapplication/qtlockedfile.h b/3rdparty/qtsingleapplication/qtlockedfile.h index 1d3b918ec..37e013ec1 100644 --- a/3rdparty/qtsingleapplication/qtlockedfile.h +++ b/3rdparty/qtsingleapplication/qtlockedfile.h @@ -1,58 +1,51 @@ /**************************************************************************** -** -** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. +** ** Contact: Nokia Corporation (qt-info@nokia.com) -** +** ** This file is part of a Qt Solutions component. ** -** Commercial Usage -** Licensees holding valid Qt Commercial licenses may use this file in -** accordance with the Qt Solutions Commercial License Agreement provided -** with the Software or, alternatively, in accordance with the terms -** contained in a written agreement between you and Nokia. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain -** additional rights. These rights are described in the Nokia Qt LGPL -** Exception version 1.1, included in the file LGPL_EXCEPTION.txt in this -** package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** Please note Third Party Software included with Qt Solutions may impose -** additional restrictions and it is the user's responsibility to ensure -** that they have met the licensing requirements of the GPL, LGPL, or Qt -** Solutions Commercial license and the relevant license of the Third -** Party Software they are using. -** -** If you are unsure which license is appropriate for your use, please -** contact Nokia at qt-info@nokia.com. -** +** 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 Nokia Corporation and its Subsidiary(-ies) 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." +** ****************************************************************************/ #ifndef QTLOCKEDFILE_H #define QTLOCKEDFILE_H -#include +#include #ifdef Q_OS_WIN #include #endif -#if defined(Q_WS_WIN) +#if defined(Q_OS_WIN) # if !defined(QT_QTLOCKEDFILE_EXPORT) && !defined(QT_QTLOCKEDFILE_IMPORT) # define QT_QTLOCKEDFILE_EXPORT # elif defined(QT_QTLOCKEDFILE_IMPORT) diff --git a/3rdparty/qtsingleapplication/qtlockedfile_unix.cpp b/3rdparty/qtsingleapplication/qtlockedfile_unix.cpp index 2881bdd2c..715c7d9b1 100644 --- a/3rdparty/qtsingleapplication/qtlockedfile_unix.cpp +++ b/3rdparty/qtsingleapplication/qtlockedfile_unix.cpp @@ -1,47 +1,40 @@ /**************************************************************************** -** -** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. +** ** Contact: Nokia Corporation (qt-info@nokia.com) -** +** ** This file is part of a Qt Solutions component. ** -** Commercial Usage -** Licensees holding valid Qt Commercial licenses may use this file in -** accordance with the Qt Solutions Commercial License Agreement provided -** with the Software or, alternatively, in accordance with the terms -** contained in a written agreement between you and Nokia. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain -** additional rights. These rights are described in the Nokia Qt LGPL -** Exception version 1.1, included in the file LGPL_EXCEPTION.txt in this -** package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** Please note Third Party Software included with Qt Solutions may impose -** additional restrictions and it is the user's responsibility to ensure -** that they have met the licensing requirements of the GPL, LGPL, or Qt -** Solutions Commercial license and the relevant license of the Third -** Party Software they are using. -** -** If you are unsure which license is appropriate for your use, please -** contact Nokia at qt-info@nokia.com. -** +** 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 Nokia Corporation and its Subsidiary(-ies) 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." +** ****************************************************************************/ #include diff --git a/3rdparty/qtsingleapplication/qtlockedfile_win.cpp b/3rdparty/qtsingleapplication/qtlockedfile_win.cpp index eb7c72029..7f37a94e3 100644 --- a/3rdparty/qtsingleapplication/qtlockedfile_win.cpp +++ b/3rdparty/qtsingleapplication/qtlockedfile_win.cpp @@ -1,52 +1,45 @@ /**************************************************************************** -** -** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. +** ** Contact: Nokia Corporation (qt-info@nokia.com) -** +** ** This file is part of a Qt Solutions component. ** -** Commercial Usage -** Licensees holding valid Qt Commercial licenses may use this file in -** accordance with the Qt Solutions Commercial License Agreement provided -** with the Software or, alternatively, in accordance with the terms -** contained in a written agreement between you and Nokia. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain -** additional rights. These rights are described in the Nokia Qt LGPL -** Exception version 1.1, included in the file LGPL_EXCEPTION.txt in this -** package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** Please note Third Party Software included with Qt Solutions may impose -** additional restrictions and it is the user's responsibility to ensure -** that they have met the licensing requirements of the GPL, LGPL, or Qt -** Solutions Commercial license and the relevant license of the Third -** Party Software they are using. -** -** If you are unsure which license is appropriate for your use, please -** contact Nokia at qt-info@nokia.com. -** +** 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 Nokia Corporation and its Subsidiary(-ies) 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." +** ****************************************************************************/ #include "qtlockedfile.h" #include -#include +#include #define MUTEX_PREFIX "QtLockedFile mutex " // Maximum number of concurrent read locks. Must not be greater than MAXIMUM_WAIT_OBJECTS @@ -65,19 +58,35 @@ Qt::HANDLE QtLockedFile::getMutexHandle(int idx, bool doCreate) Qt::HANDLE mutex; if (doCreate) { +#if (QT_VERSION < 0x050000) QT_WA({ mutex = CreateMutexW(nullptr, FALSE, (WCHAR*)mname.utf16()); }, { mutex = CreateMutexA(nullptr, FALSE, mname.toLocal8Bit().constData()); }); - if (!mutex) { - qErrnoWarning("QtLockedFile::lock(): CreateMutex failed"); - return 0; +#else + mutex = CreateMutexW(nullptr, FALSE, (WCHAR*)mname.utf16()); +#endif + if (!mutex) { + qErrnoWarning("QtLockedFile::lock(): CreateMutex failed"); + return 0; } } else { - QT_WA( { mutex = OpenMutexW(SYNCHRONIZE | MUTEX_MODIFY_STATE, FALSE, (WCHAR*)mname.utf16()); }, - { mutex = OpenMutexA(SYNCHRONIZE | MUTEX_MODIFY_STATE, FALSE, mname.toLocal8Bit().constData()); } ); +#if (QT_VERSION < 0x050000) + QT_WA( + { + mutex = OpenMutexW(SYNCHRONIZE | MUTEX_MODIFY_STATE, FALSE, + (WCHAR*)mname.utf16()); + }, + { + mutex = OpenMutexA(SYNCHRONIZE | MUTEX_MODIFY_STATE, FALSE, + mname.toLocal8Bit().constData()); + }); +#else + mutex = OpenMutexW(SYNCHRONIZE | MUTEX_MODIFY_STATE, FALSE, + (WCHAR*)mname.utf16()); +#endif if (!mutex) { if (GetLastError() != ERROR_FILE_NOT_FOUND) qErrnoWarning("QtLockedFile::lock(): OpenMutex failed"); diff --git a/3rdparty/qtsingleapplication/qtsingleapplication.cpp b/3rdparty/qtsingleapplication/qtsingleapplication.cpp index a7e19eed1..a28074a93 100644 --- a/3rdparty/qtsingleapplication/qtsingleapplication.cpp +++ b/3rdparty/qtsingleapplication/qtsingleapplication.cpp @@ -1,54 +1,46 @@ /**************************************************************************** -** -** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. +** ** Contact: Nokia Corporation (qt-info@nokia.com) -** +** ** This file is part of a Qt Solutions component. ** -** Commercial Usage -** Licensees holding valid Qt Commercial licenses may use this file in -** accordance with the Qt Solutions Commercial License Agreement provided -** with the Software or, alternatively, in accordance with the terms -** contained in a written agreement between you and Nokia. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain -** additional rights. These rights are described in the Nokia Qt LGPL -** Exception version 1.1, included in the file LGPL_EXCEPTION.txt in this -** package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** Please note Third Party Software included with Qt Solutions may impose -** additional restrictions and it is the user's responsibility to ensure -** that they have met the licensing requirements of the GPL, LGPL, or Qt -** Solutions Commercial license and the relevant license of the Third -** Party Software they are using. -** -** If you are unsure which license is appropriate for your use, please -** contact Nokia at qt-info@nokia.com. -** +** 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 Nokia Corporation and its Subsidiary(-ies) 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." +** ****************************************************************************/ #include "qtsingleapplication.h" #include "qtlocalpeer.h" -#include - +#include /*! \class QtSingleApplication qtsingleapplication.h @@ -68,28 +60,31 @@ that will be compared instead. The application should create the QtSingleApplication object early - in the startup phase, and call isRunning() or sendMessage() to - find out if another instance of this application is already - running. Startup parameters (e.g. the name of the file the user - wanted this new instance to open) can be passed to the running - instance in the sendMessage() function. + in the startup phase, and call isRunning() to find out if another + instance of this application is already running. If isRunning() + returns false, it means that no other instance is running, and + this instance has assumed the role as the running instance. In + this case, the application should continue with the initialization + of the application user interface before entering the event loop + with exec(), as normal. - If isRunning() or sendMessage() returns false, it means that no - other instance is running, and this instance has assumed the role - as the running instance. The application should continue with the - initialization of the application user interface before entering - the event loop with exec(), as normal. The messageReceived() - signal will be emitted when the application receives messages from - another instance of the same application. + The messageReceived() signal will be emitted when the running + application receives messages from another instance of the same + application. When a message is received it might be helpful to the + user to raise the application so that it becomes visible. To + facilitate this, QtSingleApplication provides the + setActivationWindow() function and the activateWindow() slot. - If isRunning() or sendMessage() returns true, another instance is - already running, and the application should terminate or enter - client mode. + If isRunning() returns true, another instance is already + running. It may be alerted to the fact that another instance has + started by using the sendMessage() function. Also data such as + startup parameters (e.g. the name of the file the user wanted this + new instance to open) can be passed to the running instance with + this function. Then, the application should terminate (or enter + client mode). - If a message is received it might be helpful to the user to raise - the application so that it becomes visible. To facilitate this, - QtSingleApplication provides the setActivationWindow() function - and the activateWindow() slot. + If isRunning() returns true, but sendMessage() fails, that is an + indication that the running instance is frozen. Here's an example that shows how to convert an existing application to use QtSingleApplication. It is very simple and does @@ -103,7 +98,6 @@ QApplication app(argc, argv); MyMainWidget mmw; - mmw.show(); return app.exec(); } @@ -114,19 +108,17 @@ QtSingleApplication app(argc, argv); if (app.isRunning()) - return 0; + return !app.sendMessage(someDataString); MyMainWidget mmw; - app.setActivationWindow(&mmw); - mmw.show(); return app.exec(); } \endcode - Once this QtSingleApplication instance is destroyed(for example, - when the user quits), when the user next attempts to run the + Once this QtSingleApplication instance is destroyed (normally when + the process exits or crashes), when the user next attempts to run the application this instance will not, of course, be encountered. The next instance to call isRunning() or sendMessage() will assume the role as the new running instance. @@ -144,8 +136,6 @@ void QtSingleApplication::sysInit(const QString &appId) actWin = 0; peer = new QtLocalPeer(this, appId); connect(peer, SIGNAL(messageReceived(const QString&)), SIGNAL(messageReceived(const QString&))); - connect(peer, SIGNAL(messageReceived(const QByteArray&)), SIGNAL(messageReceived(const QByteArray&))); - connect(peer, SIGNAL(messageReceived(const char*)), SIGNAL(messageReceived(const char*))); } @@ -179,59 +169,6 @@ QtSingleApplication::QtSingleApplication(const QString &appId, int &argc, char * } -/*! - Creates a QtSingleApplication object. The application identifier - will be QCoreApplication::applicationFilePath(). \a argc, \a - argv, and \a type are passed on to the QAppliation constructor. -*/ -QtSingleApplication::QtSingleApplication(int &argc, char **argv, Type type) - : QApplication(argc, argv, type) -{ - sysInit(); -} - - -#if defined(Q_WS_X11) -/*! - Special constructor for X11, ref. the documentation of - QApplication's corresponding constructor. The application identifier - will be QCoreApplication::applicationFilePath(). \a dpy, \a visual, - and \a cmap are passed on to the QApplication constructor. -*/ -QtSingleApplication::QtSingleApplication(Display* dpy, Qt::HANDLE visual, Qt::HANDLE cmap) - : QApplication(dpy, visual, cmap) -{ - sysInit(); -} - -/*! - Special constructor for X11, ref. the documentation of - QApplication's corresponding constructor. The application identifier - will be QCoreApplication::applicationFilePath(). \a dpy, \a argc, \a - argv, \a visual, and \a cmap are passed on to the QApplication - constructor. -*/ -QtSingleApplication::QtSingleApplication(Display *dpy, int &argc, char **argv, Qt::HANDLE visual, Qt::HANDLE cmap) - : QApplication(dpy, argc, argv, visual, cmap) -{ - sysInit(); -} - -/*! - Special constructor for X11, ref. the documentation of - QApplication's corresponding constructor. The application identifier - will be \a appId. \a dpy, \a argc, \a - argv, \a visual, and \a cmap are passed on to the QApplication - constructor. -*/ -QtSingleApplication::QtSingleApplication(Display* dpy, const QString &appId, int argc, char **argv, Qt::HANDLE visual, Qt::HANDLE cmap) - : QApplication(dpy, argc, argv, visual, cmap) -{ - sysInit(appId); -} -#endif - - /*! Returns true if another instance of this application is running; otherwise false. @@ -267,16 +204,6 @@ bool QtSingleApplication::sendMessage(const QString &message, int timeout) return peer->sendMessage(message, timeout); } -bool QtSingleApplication::sendMessage(const QByteArray &message, int timeout) -{ - return peer->sendMessage(message, timeout); -} - -bool QtSingleApplication::sendMessage(const char* message, int timeout) -{ - return peer->sendMessage(message, timeout); -} - /*! Returns the application identifier. Two processes with the same @@ -303,16 +230,10 @@ QString QtSingleApplication::id() const void QtSingleApplication::setActivationWindow(QWidget* aw, bool activateOnMessage) { actWin = aw; - if (activateOnMessage) { + if (activateOnMessage) connect(peer, SIGNAL(messageReceived(const QString&)), this, SLOT(activateWindow())); - connect(peer, SIGNAL(messageReceived(const QByteArray&)), this, SLOT(activateWindow())); - connect(peer, SIGNAL(messageReceived(const char*)), this, SLOT(activateWindow())); - } - else { + else disconnect(peer, SIGNAL(messageReceived(const QString&)), this, SLOT(activateWindow())); - disconnect(peer, SIGNAL(messageReceived(const QByteArray&)), this, SLOT(activateWindow())); - disconnect(peer, SIGNAL(messageReceived(const char*)), this, SLOT(activateWindow())); - } } diff --git a/3rdparty/qtsingleapplication/qtsingleapplication.h b/3rdparty/qtsingleapplication/qtsingleapplication.h index ba0507cb8..5d2ae46f3 100644 --- a/3rdparty/qtsingleapplication/qtsingleapplication.h +++ b/3rdparty/qtsingleapplication/qtsingleapplication.h @@ -1,55 +1,50 @@ /**************************************************************************** -** -** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. +** ** Contact: Nokia Corporation (qt-info@nokia.com) -** +** ** This file is part of a Qt Solutions component. ** -** Commercial Usage -** Licensees holding valid Qt Commercial licenses may use this file in -** accordance with the Qt Solutions Commercial License Agreement provided -** with the Software or, alternatively, in accordance with the terms -** contained in a written agreement between you and Nokia. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain -** additional rights. These rights are described in the Nokia Qt LGPL -** Exception version 1.1, included in the file LGPL_EXCEPTION.txt in this -** package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** Please note Third Party Software included with Qt Solutions may impose -** additional restrictions and it is the user's responsibility to ensure -** that they have met the licensing requirements of the GPL, LGPL, or Qt -** Solutions Commercial license and the relevant license of the Third -** Party Software they are using. -** -** If you are unsure which license is appropriate for your use, please -** contact Nokia at qt-info@nokia.com. -** +** 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 Nokia Corporation and its Subsidiary(-ies) 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." +** ****************************************************************************/ +#ifndef QTSINGLEAPPLICATION_H +#define QTSINGLEAPPLICATION_H -#include +#include class QtLocalPeer; -#if defined(Q_WS_WIN) +#if defined(Q_OS_WIN) || defined(Q_OS_WIN32) # if !defined(QT_QTSINGLEAPPLICATION_EXPORT) && !defined(QT_QTSINGLEAPPLICATION_IMPORT) # define QT_QTSINGLEAPPLICATION_EXPORT # elif defined(QT_QTSINGLEAPPLICATION_IMPORT) @@ -72,12 +67,6 @@ class QT_QTSINGLEAPPLICATION_EXPORT QtSingleApplication : public QApplication public: QtSingleApplication(int &argc, char **argv, bool GUIenabled = true); QtSingleApplication(const QString &id, int &argc, char **argv); - QtSingleApplication(int &argc, char **argv, Type type); -#if defined(Q_WS_X11) - QtSingleApplication(Display* dpy, Qt::HANDLE visual = 0, Qt::HANDLE colormap = 0); - QtSingleApplication(Display *dpy, int &argc, char **argv, Qt::HANDLE visual = 0, Qt::HANDLE cmap= 0); - QtSingleApplication(Display* dpy, const QString &appId, int argc, char **argv, Qt::HANDLE visual = 0, Qt::HANDLE colormap = 0); -#endif bool isRunning(); QString id() const; @@ -91,15 +80,11 @@ public: public Q_SLOTS: bool sendMessage(const QString &message, int timeout = 5000); - bool sendMessage(const QByteArray &message, int timeout = 5000); - bool sendMessage(const char* message, int timeout = 5000); void activateWindow(); Q_SIGNALS: void messageReceived(const QString &message); - void messageReceived(const QByteArray &message); - void messageReceived(const char* message); private: @@ -107,3 +92,5 @@ private: QtLocalPeer *peer; QWidget *actWin; }; + +#endif // QTSINGLEAPPLICATION_H diff --git a/3rdparty/qtsingleapplication/qtsingleapplication.patch b/3rdparty/qtsingleapplication/qtsingleapplication.patch deleted file mode 100644 index a65e64ac7..000000000 --- a/3rdparty/qtsingleapplication/qtsingleapplication.patch +++ /dev/null @@ -1,231 +0,0 @@ -diff -ur /home/david/qtsingleapplication-2.6_1-opensource/src/qtlocalpeer.cpp qtsingleapplication/qtlocalpeer.cpp ---- /home/david/qtsingleapplication-2.6_1-opensource/src/qtlocalpeer.cpp 2009-12-16 10:43:33.000000000 +0000 -+++ qtsingleapplication/qtlocalpeer.cpp 2010-07-10 16:26:50.000000000 +0100 -@@ -48,6 +48,7 @@ - #include "qtlocalpeer.h" - #include - #include -+#include - - #if defined(Q_OS_WIN) - #include -@@ -59,14 +60,12 @@ - #include - #endif - --namespace QtLP_Private { - #include "qtlockedfile.cpp" - #if defined(Q_OS_WIN) - #include "qtlockedfile_win.cpp" - #else - #include "qtlockedfile_unix.cpp" - #endif --} - - const char* QtLocalPeer::ack = "ack"; - -@@ -118,7 +117,7 @@ - if (lockFile.isLocked()) - return false; - -- if (!lockFile.lock(QtLP_Private::QtLockedFile::WriteLock, false)) -+ if (!lockFile.lock(QtLockedFile::WriteLock, false)) - return true; - - bool res = server->listen(socketName); -@@ -138,6 +137,11 @@ - - bool QtLocalPeer::sendMessage(const QString &message, int timeout) - { -+ return sendMessage(message.toUtf8(), timeout); -+} -+ -+bool QtLocalPeer::sendMessage(const QByteArray &message, int timeout) -+{ - if (!isClient()) - return false; - -@@ -160,9 +164,8 @@ - if (!connOk) - return false; - -- QByteArray uMsg(message.toUtf8()); - QDataStream ds(&socket); -- ds.writeBytes(uMsg.constData(), uMsg.size()); -+ ds.writeBytes(message.constData(), message.size()); - bool res = socket.waitForBytesWritten(timeout); - res &= socket.waitForReadyRead(timeout); // wait for ack - res &= (socket.read(qstrlen(ack)) == ack); -@@ -195,9 +198,9 @@ - delete socket; - return; - } -- QString message(QString::fromUtf8(uMsg)); - socket->write(ack, qstrlen(ack)); - socket->waitForBytesWritten(1000); - delete socket; -- emit messageReceived(message); //### (might take a long time to return) -+ emit messageReceived(uMsg); //### (might take a long time to return) -+ emit messageReceived(QString::fromUtf8(uMsg)); - } -diff -ur /home/david/qtsingleapplication-2.6_1-opensource/src/qtlocalpeer.h qtsingleapplication/qtlocalpeer.h ---- /home/david/qtsingleapplication-2.6_1-opensource/src/qtlocalpeer.h 2009-12-16 10:43:33.000000000 +0000 -+++ qtsingleapplication/qtlocalpeer.h 2010-07-10 16:26:16.000000000 +0100 -@@ -49,9 +49,7 @@ - #include - #include - --namespace QtLP_Private { - #include "qtlockedfile.h" --} - - class QtLocalPeer : public QObject - { -@@ -61,11 +59,13 @@ - QtLocalPeer(QObject *parent = 0, const QString &appId = QString()); - bool isClient(); - bool sendMessage(const QString &message, int timeout); -+ bool sendMessage(const QByteArray &message, int timeout); - QString applicationId() const - { return id; } - - Q_SIGNALS: - void messageReceived(const QString &message); -+ void messageReceived(const QByteArray &message); - - protected Q_SLOTS: - void receiveConnection(); -@@ -74,7 +74,7 @@ - QString id; - QString socketName; - QLocalServer* server; -- QtLP_Private::QtLockedFile lockFile; -+ QtLockedFile lockFile; - - private: - static const char* ack; -diff -ur /home/david/qtsingleapplication-2.6_1-opensource/src/qtlockedfile_win.cpp qtsingleapplication/qtlockedfile_win.cpp ---- /home/david/qtsingleapplication-2.6_1-opensource/src/qtlockedfile_win.cpp 2009-12-16 10:43:33.000000000 +0000 -+++ qtsingleapplication/qtlockedfile_win.cpp 2010-07-10 16:26:33.000000000 +0100 -@@ -65,7 +65,7 @@ - - Qt::HANDLE mutex; - if (doCreate) { -- QT_WA( { mutex = CreateMutexW(NULL, FALSE, (TCHAR*)mname.utf16()); }, -+ QT_WA( { mutex = CreateMutexW(NULL, FALSE, (WCHAR*)mname.utf16()); }, - { mutex = CreateMutexA(NULL, FALSE, mname.toLocal8Bit().constData()); } ); - if (!mutex) { - qErrnoWarning("QtLockedFile::lock(): CreateMutex failed"); -@@ -73,7 +73,7 @@ - } - } - else { -- QT_WA( { mutex = OpenMutexW(SYNCHRONIZE | MUTEX_MODIFY_STATE, FALSE, (TCHAR*)mname.utf16()); }, -+ QT_WA( { mutex = OpenMutexW(SYNCHRONIZE | MUTEX_MODIFY_STATE, FALSE, (WCHAR*)mname.utf16()); }, - { mutex = OpenMutexA(SYNCHRONIZE | MUTEX_MODIFY_STATE, FALSE, mname.toLocal8Bit().constData()); } ); - if (!mutex) { - if (GetLastError() != ERROR_FILE_NOT_FOUND) -diff -ur /home/david/qtsingleapplication-2.6_1-opensource/src/qtsingleapplication.cpp qtsingleapplication/qtsingleapplication.cpp ---- /home/david/qtsingleapplication-2.6_1-opensource/src/qtsingleapplication.cpp 2009-12-16 10:43:33.000000000 +0000 -+++ qtsingleapplication/qtsingleapplication.cpp 2010-07-10 16:23:53.000000000 +0100 -@@ -144,6 +144,7 @@ - actWin = 0; - peer = new QtLocalPeer(this, appId); - connect(peer, SIGNAL(messageReceived(const QString&)), SIGNAL(messageReceived(const QString&))); -+ connect(peer, SIGNAL(messageReceived(const QByteArray&)), SIGNAL(messageReceived(const QByteArray&))); - } - - -@@ -265,6 +266,11 @@ - return peer->sendMessage(message, timeout); - } - -+bool QtSingleApplication::sendMessage(const QByteArray &message, int timeout) -+{ -+ return peer->sendMessage(message, timeout); -+} -+ - - /*! - Returns the application identifier. Two processes with the same -@@ -291,10 +297,14 @@ - void QtSingleApplication::setActivationWindow(QWidget* aw, bool activateOnMessage) - { - actWin = aw; -- if (activateOnMessage) -+ if (activateOnMessage) { - connect(peer, SIGNAL(messageReceived(const QString&)), this, SLOT(activateWindow())); -- else -+ connect(peer, SIGNAL(messageReceived(const QByteArray&)), this, SLOT(activateWindow())); -+ } -+ else { - disconnect(peer, SIGNAL(messageReceived(const QString&)), this, SLOT(activateWindow())); -+ disconnect(peer, SIGNAL(messageReceived(const QByteArray&)), this, SLOT(activateWindow())); -+ } - } - - -diff -ur /home/david/qtsingleapplication-2.6_1-opensource/src/qtsingleapplication.h qtsingleapplication/qtsingleapplication.h ---- /home/david/qtsingleapplication-2.6_1-opensource/src/qtsingleapplication.h 2009-12-16 10:43:33.000000000 +0000 -+++ qtsingleapplication/qtsingleapplication.h 2010-07-10 16:23:53.000000000 +0100 -@@ -91,11 +91,13 @@ - - public Q_SLOTS: - bool sendMessage(const QString &message, int timeout = 5000); -+ bool sendMessage(const QByteArray &message, int timeout = 5000); - void activateWindow(); - - - Q_SIGNALS: - void messageReceived(const QString &message); -+ void messageReceived(const QByteArray &message); - - - private: -diff -ur /home/david/qtsingleapplication-2.6_1-opensource/src/qtsinglecoreapplication.cpp qtsingleapplication/qtsinglecoreapplication.cpp ---- /home/david/qtsingleapplication-2.6_1-opensource/src/qtsinglecoreapplication.cpp 2009-12-16 10:43:33.000000000 +0000 -+++ qtsingleapplication/qtsinglecoreapplication.cpp 2010-07-10 16:32:33.000000000 +0100 -@@ -81,6 +81,7 @@ - { - peer = new QtLocalPeer(this); - connect(peer, SIGNAL(messageReceived(const QString&)), SIGNAL(messageReceived(const QString&))); -+ connect(peer, SIGNAL(messageReceived(const QByteArray&)), SIGNAL(messageReceived(const QByteArray&))); - } - - -@@ -94,6 +95,7 @@ - { - peer = new QtLocalPeer(this, appId); - connect(peer, SIGNAL(messageReceived(const QString&)), SIGNAL(messageReceived(const QString&))); -+ connect(peer, SIGNAL(messageReceived(const QByteArray&)), SIGNAL(messageReceived(const QByteArray&))); - } - - -@@ -133,6 +135,11 @@ - return peer->sendMessage(message, timeout); - } - -+bool QtSingleCoreApplication::sendMessage(const QByteArray &message, int timeout) -+{ -+ return peer->sendMessage(message, timeout); -+} -+ - - /*! - Returns the application identifier. Two processes with the same -diff -ur /home/david/qtsingleapplication-2.6_1-opensource/src/qtsinglecoreapplication.h qtsingleapplication/qtsinglecoreapplication.h ---- /home/david/qtsingleapplication-2.6_1-opensource/src/qtsinglecoreapplication.h 2009-12-16 10:43:33.000000000 +0000 -+++ qtsingleapplication/qtsinglecoreapplication.h 2010-07-10 16:32:33.000000000 +0100 -@@ -62,10 +62,12 @@ - - public Q_SLOTS: - bool sendMessage(const QString &message, int timeout = 5000); -+ bool sendMessage(const QByteArray &message, int timeout = 5000); - - - Q_SIGNALS: - void messageReceived(const QString &message); -+ void messageReceived(const QByteArray &message); - - - private: diff --git a/3rdparty/qtsingleapplication/qtsinglecoreapplication.cpp b/3rdparty/qtsingleapplication/qtsinglecoreapplication.cpp index 38e16584a..cf607710e 100644 --- a/3rdparty/qtsingleapplication/qtsinglecoreapplication.cpp +++ b/3rdparty/qtsingleapplication/qtsinglecoreapplication.cpp @@ -1,47 +1,40 @@ /**************************************************************************** -** -** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. +** ** Contact: Nokia Corporation (qt-info@nokia.com) -** +** ** This file is part of a Qt Solutions component. ** -** Commercial Usage -** Licensees holding valid Qt Commercial licenses may use this file in -** accordance with the Qt Solutions Commercial License Agreement provided -** with the Software or, alternatively, in accordance with the terms -** contained in a written agreement between you and Nokia. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain -** additional rights. These rights are described in the Nokia Qt LGPL -** Exception version 1.1, included in the file LGPL_EXCEPTION.txt in this -** package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** Please note Third Party Software included with Qt Solutions may impose -** additional restrictions and it is the user's responsibility to ensure -** that they have met the licensing requirements of the GPL, LGPL, or Qt -** Solutions Commercial license and the relevant license of the Third -** Party Software they are using. -** -** If you are unsure which license is appropriate for your use, please -** contact Nokia at qt-info@nokia.com. -** +** 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 Nokia Corporation and its Subsidiary(-ies) 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." +** ****************************************************************************/ @@ -81,8 +74,6 @@ QtSingleCoreApplication::QtSingleCoreApplication(int &argc, char **argv) { peer = new QtLocalPeer(this); connect(peer, SIGNAL(messageReceived(const QString&)), SIGNAL(messageReceived(const QString&))); - connect(peer, SIGNAL(messageReceived(const QByteArray&)), SIGNAL(messageReceived(const QByteArray&))); - connect(peer, SIGNAL(messageReceived(const char*)), SIGNAL(messageReceived(const char*))); } @@ -96,8 +87,6 @@ QtSingleCoreApplication::QtSingleCoreApplication(const QString &appId, int &argc { peer = new QtLocalPeer(this, appId); connect(peer, SIGNAL(messageReceived(const QString&)), SIGNAL(messageReceived(const QString&))); - connect(peer, SIGNAL(messageReceived(const QByteArray&)), SIGNAL(messageReceived(const QByteArray&))); - connect(peer, SIGNAL(messageReceived(const char*)), SIGNAL(messageReceived(const char*))); } @@ -137,16 +126,6 @@ bool QtSingleCoreApplication::sendMessage(const QString &message, int timeout) return peer->sendMessage(message, timeout); } -bool QtSingleCoreApplication::sendMessage(const QByteArray &message, int timeout) -{ - return peer->sendMessage(message, timeout); -} - -bool QtSingleCoreApplication::sendMessage(const char* message, int timeout) -{ - return peer->sendMessage(message, timeout); -} - /*! Returns the application identifier. Two processes with the same diff --git a/3rdparty/qtsingleapplication/qtsinglecoreapplication.h b/3rdparty/qtsingleapplication/qtsinglecoreapplication.h index f80946da5..549d49f53 100644 --- a/3rdparty/qtsingleapplication/qtsinglecoreapplication.h +++ b/3rdparty/qtsingleapplication/qtsinglecoreapplication.h @@ -1,51 +1,46 @@ /**************************************************************************** -** -** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. +** ** Contact: Nokia Corporation (qt-info@nokia.com) -** +** ** This file is part of a Qt Solutions component. ** -** Commercial Usage -** Licensees holding valid Qt Commercial licenses may use this file in -** accordance with the Qt Solutions Commercial License Agreement provided -** with the Software or, alternatively, in accordance with the terms -** contained in a written agreement between you and Nokia. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain -** additional rights. These rights are described in the Nokia Qt LGPL -** Exception version 1.1, included in the file LGPL_EXCEPTION.txt in this -** package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** Please note Third Party Software included with Qt Solutions may impose -** additional restrictions and it is the user's responsibility to ensure -** that they have met the licensing requirements of the GPL, LGPL, or Qt -** Solutions Commercial license and the relevant license of the Third -** Party Software they are using. -** -** If you are unsure which license is appropriate for your use, please -** contact Nokia at qt-info@nokia.com. -** +** 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 Nokia Corporation and its Subsidiary(-ies) 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." +** ****************************************************************************/ +#ifndef QTSINGLECOREAPPLICATION_H +#define QTSINGLECOREAPPLICATION_H -#include +#include class QtLocalPeer; @@ -62,16 +57,14 @@ public: public Q_SLOTS: bool sendMessage(const QString &message, int timeout = 5000); - bool sendMessage(const QByteArray &message, int timeout = 5000); - bool sendMessage(const char* message, int timeout = 5000); Q_SIGNALS: void messageReceived(const QString &message); - void messageReceived(const QByteArray &message); - void messageReceived(const char* message); private: QtLocalPeer* peer; }; + +#endif // QTSINGLECOREAPPLICATION_H diff --git a/3rdparty/qtwin/CMakeLists.txt b/3rdparty/qtwin/CMakeLists.txt deleted file mode 100644 index c2df87bfc..000000000 --- a/3rdparty/qtwin/CMakeLists.txt +++ /dev/null @@ -1,9 +0,0 @@ -cmake_minimum_required(VERSION 2.6) - -set(QTWIN-SOURCES - qtwin.cpp -) - -ADD_LIBRARY(qtwin STATIC - ${QTWIN-SOURCES} -) diff --git a/3rdparty/qtwin/qtwin.cpp b/3rdparty/qtwin/qtwin.cpp deleted file mode 100644 index 69a24a9d5..000000000 --- a/3rdparty/qtwin/qtwin.cpp +++ /dev/null @@ -1,229 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** -** Use, modification and distribution is allowed without limitation, -** warranty, liability or support of any kind. -** -****************************************************************************/ - -#include "qtwin.h" -#include -#include -#include -#include -#include - -#ifdef Q_WS_WIN - -#include - -// Blur behind data structures -#define DWM_BB_ENABLE 0x00000001 // fEnable has been specified -#define DWM_BB_BLURREGION 0x00000002 // hRgnBlur has been specified -#define DWM_BB_TRANSITIONONMAXIMIZED 0x00000004 // fTransitionOnMaximized has been specified -#define WM_DWMCOMPOSITIONCHANGED 0x031E // Composition changed window message - -typedef struct _DWM_BLURBEHIND -{ - DWORD dwFlags; - BOOL fEnable; - HRGN hRgnBlur; - BOOL fTransitionOnMaximized; -} DWM_BLURBEHIND, *PDWM_BLURBEHIND; - -typedef struct _MARGINS -{ - int cxLeftWidth; - int cxRightWidth; - int cyTopHeight; - int cyBottomHeight; -} MARGINS, *PMARGINS; - -typedef HRESULT (WINAPI *PtrDwmIsCompositionEnabled)(BOOL* pfEnabled); -typedef HRESULT (WINAPI *PtrDwmExtendFrameIntoClientArea)(HWND hWnd, const MARGINS* pMarInset); -typedef HRESULT (WINAPI *PtrDwmEnableBlurBehindWindow)(HWND hWnd, const DWM_BLURBEHIND* pBlurBehind); -typedef HRESULT (WINAPI *PtrDwmGetColorizationColor)(DWORD *pcrColorization, BOOL *pfOpaqueBlend); - -static PtrDwmIsCompositionEnabled pDwmIsCompositionEnabled= 0; -static PtrDwmEnableBlurBehindWindow pDwmEnableBlurBehindWindow = 0; -static PtrDwmExtendFrameIntoClientArea pDwmExtendFrameIntoClientArea = 0; -static PtrDwmGetColorizationColor pDwmGetColorizationColor = 0; - - -/* - * Internal helper class that notifies windows if the - * DWM compositing state changes and updates the widget - * flags correspondingly. - */ -class WindowNotifier : public QWidget -{ -public: - WindowNotifier() { winId(); } - void addWidget(QWidget *widget) { widgets.append(widget); } - void removeWidget(QWidget *widget) { widgets.removeAll(widget); } - bool winEvent(MSG *message, long *result); - -private: - QWidgetList widgets; -}; - -static bool resolveLibs() -{ - if (!pDwmIsCompositionEnabled) { - QLibrary dwmLib(QString::fromAscii("dwmapi")); - pDwmIsCompositionEnabled =(PtrDwmIsCompositionEnabled)dwmLib.resolve("DwmIsCompositionEnabled"); - pDwmExtendFrameIntoClientArea = (PtrDwmExtendFrameIntoClientArea)dwmLib.resolve("DwmExtendFrameIntoClientArea"); - pDwmEnableBlurBehindWindow = (PtrDwmEnableBlurBehindWindow)dwmLib.resolve("DwmEnableBlurBehindWindow"); - pDwmGetColorizationColor = (PtrDwmGetColorizationColor)dwmLib.resolve("DwmGetColorizationColor"); - } - return pDwmIsCompositionEnabled != 0; -} - -#endif - -/*! - * Chekcs and returns true if Windows DWM composition - * is currently enabled on the system. - * - * To get live notification on the availability of - * this feature, you will currently have to - * reimplement winEvent() on your widget and listen - * for the WM_DWMCOMPOSITIONCHANGED event to occur. - * - */ -bool QtWin::isCompositionEnabled() -{ -#ifdef Q_WS_WIN - if (resolveLibs()) { - HRESULT hr = S_OK; - BOOL isEnabled = false; - hr = pDwmIsCompositionEnabled(&isEnabled); - if (SUCCEEDED(hr)) - return isEnabled; - } -#endif - return false; -} - -/*! - * Enables Blur behind on a Widget. - * - * \a enable tells if the blur should be enabled or not - */ -bool QtWin::enableBlurBehindWindow(QWidget *widget, bool enable, - const QRegion ®ion) -{ - Q_ASSERT(widget); - bool result = false; -#ifdef Q_WS_WIN - if (resolveLibs()) { - DWM_BLURBEHIND bb = {0}; - HRESULT hr = S_OK; - bb.fEnable = enable; - bb.dwFlags = DWM_BB_ENABLE; - bb.hRgnBlur = NULL; - - if (!region.isEmpty()) { - bb.dwFlags |= DWM_BB_BLURREGION; - bb.hRgnBlur = region.handle(); - } - - widget->setAttribute(Qt::WA_TranslucentBackground, enable); - widget->setAttribute(Qt::WA_NoSystemBackground, enable); - hr = pDwmEnableBlurBehindWindow(widget->winId(), &bb); - if (SUCCEEDED(hr)) { - result = true; - windowNotifier()->addWidget(widget); - } - } -#endif - return result; -} - -/*! - * ExtendFrameIntoClientArea. - * - * This controls the rendering of the frame inside the window. - * Note that passing margins of -1 (the default value) will completely - * remove the frame from the window. - * - * \note you should not call enableBlurBehindWindow before calling - * this functions - * - * \a enable tells if the blur should be enabled or not - */ -bool QtWin::extendFrameIntoClientArea(QWidget *widget, int left, int top, int right, int bottom) -{ - - Q_ASSERT(widget); - Q_UNUSED(left); - Q_UNUSED(top); - Q_UNUSED(right); - Q_UNUSED(bottom); - - bool result = false; -#ifdef Q_WS_WIN - if (resolveLibs()) { - QLibrary dwmLib(QString::fromAscii("dwmapi")); - HRESULT hr = S_OK; - MARGINS m = {left, top, right, bottom}; - hr = pDwmExtendFrameIntoClientArea(widget->winId(), &m); - if (SUCCEEDED(hr)) { - result = true; - windowNotifier()->addWidget(widget); - } - widget->setAttribute(Qt::WA_TranslucentBackground, result); - } -#endif - return result; -} - -/*! - * Returns the current colorizationColor for the window. - * - * \a enable tells if the blur should be enabled or not - */ -QColor QtWin::colorizatinColor() -{ - QColor resultColor = QApplication::palette().window().color(); - -#ifdef Q_WS_WIN - if (resolveLibs()) { - DWORD color = 0; - BOOL opaque = FALSE; - QLibrary dwmLib(QString::fromAscii("dwmapi")); - HRESULT hr = S_OK; - hr = pDwmGetColorizationColor(&color, &opaque); - if (SUCCEEDED(hr)) - resultColor = QColor(color); - } -#endif - return resultColor; -} - -#ifdef Q_WS_WIN -WindowNotifier *QtWin::windowNotifier() -{ - static WindowNotifier *windowNotifierInstance = 0; - if (!windowNotifierInstance) - windowNotifierInstance = new WindowNotifier; - return windowNotifierInstance; -} - - -/* Notify all enabled windows that the DWM state changed */ -bool WindowNotifier::winEvent(MSG *message, long *result) -{ - if (message && message->message == WM_DWMCOMPOSITIONCHANGED) { - bool compositionEnabled = QtWin::isCompositionEnabled(); - foreach(QWidget * widget, widgets) { - if (widget) { - widget->setAttribute(Qt::WA_NoSystemBackground, compositionEnabled); - } - widget->update(); - } - } - return QWidget::winEvent(message, result); -} -#endif diff --git a/3rdparty/qtwin/qtwin.h b/3rdparty/qtwin/qtwin.h deleted file mode 100644 index a40185853..000000000 --- a/3rdparty/qtwin/qtwin.h +++ /dev/null @@ -1,38 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** -** Use, modification and distribution is allowed without limitation, -** warranty, liability or support of any kind. -** -****************************************************************************/ - -#ifndef QTWIN_H -#define QTWIN_H - -#include -#include -/** - * This is a helper class for using the Desktop Window Manager - * functionality on Windows 7 and Windows Vista. On other platforms - * these functions will simply not do anything. - */ - -class WindowNotifier; - -class QtWin -{ -public: - static bool enableBlurBehindWindow(QWidget *widget, bool enable = true, - const QRegion& region = QRegion()); - static bool extendFrameIntoClientArea(QWidget *widget, - int left = -1, int top = -1, - int right = -1, int bottom = -1); - static bool isCompositionEnabled(); - static QColor colorizatinColor(); - -private: - static WindowNotifier *windowNotifier(); -}; - -#endif // QTWIN_H diff --git a/3rdparty/qxt/CMakeLists.txt b/3rdparty/qxt/CMakeLists.txt index 1db05ca69..73c67a9fa 100644 --- a/3rdparty/qxt/CMakeLists.txt +++ b/3rdparty/qxt/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 2.6) +cmake_minimum_required(VERSION 2.8.11) set(CMAKE_CXX_STANDARD 11) set(QXT-SOURCES @@ -10,8 +10,8 @@ set(QXT-MOC-HEADERS qxtglobalshortcut.h ) -find_package(X11) include_directories(${X11_INCLUDE_DIR}) +include_directories(${Qt5Gui_PRIVATE_INCLUDE_DIRS}) if(WIN32) set(QXT-SOURCES ${QXT-SOURCES} qxtglobalshortcut_win.cpp) @@ -21,9 +21,15 @@ else(WIN32) set(QXT-SOURCES ${QXT-SOURCES} qxtglobalshortcut_x11.cpp) endif(WIN32) -QT4_WRAP_CPP(QXT-SOURCES-MOC ${QXT-MOC-HEADERS}) +QT5_WRAP_CPP(QXT-SOURCES-MOC ${QXT-MOC-HEADERS}) ADD_LIBRARY(qxt STATIC ${QXT-SOURCES} ${QXT-SOURCES-MOC} ) + +if(WIN32) + target_link_libraries(qxt Qt5::Core Qt5::Widgets) +else(WIN32) + target_link_libraries(qxt Qt5::Core Qt5::Widgets Qt5::X11Extras) +endif(WIN32) diff --git a/3rdparty/qxt/media-keys.patch b/3rdparty/qxt/media-keys.patch deleted file mode 100644 index 31e52f3da..000000000 --- a/3rdparty/qxt/media-keys.patch +++ /dev/null @@ -1,432 +0,0 @@ -diff -ru libqxt-old/src/gui/keymapper_x11.h libqxt/src/gui/keymapper_x11.h ---- libqxt-old/src/gui/keymapper_x11.h 2010-04-21 15:17:56.000000000 +0100 -+++ libqxt/src/gui/keymapper_x11.h 2010-04-21 15:18:16.000000000 +0100 -@@ -0,0 +1,364 @@ -+#ifndef KEYMAPPER_X11_H -+#define KEYMAPPER_X11_H -+ -+// (davidsansome) Nicked from qkeymapper_x11.cpp -+ -+#include -+ -+#define XK_MISCELLANY -+#define XK_LATIN1 -+#define XK_KOREAN -+#define XK_XKB_KEYS -+#include -+ -+// -+// Keyboard event translation -+// -+ -+#ifndef XK_ISO_Left_Tab -+#define XK_ISO_Left_Tab 0xFE20 -+#endif -+ -+#ifndef XK_dead_hook -+#define XK_dead_hook 0xFE61 -+#endif -+ -+#ifndef XK_dead_horn -+#define XK_dead_horn 0xFE62 -+#endif -+ -+#ifndef XK_Codeinput -+#define XK_Codeinput 0xFF37 -+#endif -+ -+#ifndef XK_Kanji_Bangou -+#define XK_Kanji_Bangou 0xFF37 /* same as codeinput */ -+#endif -+ -+// Fix old X libraries -+#ifndef XK_KP_Home -+#define XK_KP_Home 0xFF95 -+#endif -+#ifndef XK_KP_Left -+#define XK_KP_Left 0xFF96 -+#endif -+#ifndef XK_KP_Up -+#define XK_KP_Up 0xFF97 -+#endif -+#ifndef XK_KP_Right -+#define XK_KP_Right 0xFF98 -+#endif -+#ifndef XK_KP_Down -+#define XK_KP_Down 0xFF99 -+#endif -+#ifndef XK_KP_Prior -+#define XK_KP_Prior 0xFF9A -+#endif -+#ifndef XK_KP_Next -+#define XK_KP_Next 0xFF9B -+#endif -+#ifndef XK_KP_End -+#define XK_KP_End 0xFF9C -+#endif -+#ifndef XK_KP_Insert -+#define XK_KP_Insert 0xFF9E -+#endif -+#ifndef XK_KP_Delete -+#define XK_KP_Delete 0xFF9F -+#endif -+ -+// the next lines are taken from XFree > 4.0 (X11/XF86keysyms.h), defining some special -+// multimedia keys. They are included here as not every system has them. -+#define XF86XK_Standby 0x1008FF10 -+#define XF86XK_AudioLowerVolume 0x1008FF11 -+#define XF86XK_AudioMute 0x1008FF12 -+#define XF86XK_AudioRaiseVolume 0x1008FF13 -+#define XF86XK_AudioPlay 0x1008FF14 -+#define XF86XK_AudioStop 0x1008FF15 -+#define XF86XK_AudioPrev 0x1008FF16 -+#define XF86XK_AudioNext 0x1008FF17 -+#define XF86XK_HomePage 0x1008FF18 -+#define XF86XK_Calculator 0x1008FF1D -+#define XF86XK_Mail 0x1008FF19 -+#define XF86XK_Start 0x1008FF1A -+#define XF86XK_Search 0x1008FF1B -+#define XF86XK_AudioRecord 0x1008FF1C -+#define XF86XK_Back 0x1008FF26 -+#define XF86XK_Forward 0x1008FF27 -+#define XF86XK_Stop 0x1008FF28 -+#define XF86XK_Refresh 0x1008FF29 -+#define XF86XK_Favorites 0x1008FF30 -+#define XF86XK_AudioPause 0x1008FF31 -+#define XF86XK_AudioMedia 0x1008FF32 -+#define XF86XK_MyComputer 0x1008FF33 -+#define XF86XK_OpenURL 0x1008FF38 -+#define XF86XK_Launch0 0x1008FF40 -+#define XF86XK_Launch1 0x1008FF41 -+#define XF86XK_Launch2 0x1008FF42 -+#define XF86XK_Launch3 0x1008FF43 -+#define XF86XK_Launch4 0x1008FF44 -+#define XF86XK_Launch5 0x1008FF45 -+#define XF86XK_Launch6 0x1008FF46 -+#define XF86XK_Launch7 0x1008FF47 -+#define XF86XK_Launch8 0x1008FF48 -+#define XF86XK_Launch9 0x1008FF49 -+#define XF86XK_LaunchA 0x1008FF4A -+#define XF86XK_LaunchB 0x1008FF4B -+#define XF86XK_LaunchC 0x1008FF4C -+#define XF86XK_LaunchD 0x1008FF4D -+#define XF86XK_LaunchE 0x1008FF4E -+#define XF86XK_LaunchF 0x1008FF4F -+// end of XF86keysyms.h -+ -+// Special keys used by Qtopia, mapped into the X11 private keypad range. -+#define QTOPIAXK_Select 0x11000601 -+#define QTOPIAXK_Yes 0x11000602 -+#define QTOPIAXK_No 0x11000603 -+#define QTOPIAXK_Cancel 0x11000604 -+#define QTOPIAXK_Printer 0x11000605 -+#define QTOPIAXK_Execute 0x11000606 -+#define QTOPIAXK_Sleep 0x11000607 -+#define QTOPIAXK_Play 0x11000608 -+#define QTOPIAXK_Zoom 0x11000609 -+#define QTOPIAXK_Context1 0x1100060A -+#define QTOPIAXK_Context2 0x1100060B -+#define QTOPIAXK_Context3 0x1100060C -+#define QTOPIAXK_Context4 0x1100060D -+#define QTOPIAXK_Call 0x1100060E -+#define QTOPIAXK_Hangup 0x1100060F -+#define QTOPIAXK_Flip 0x11000610 -+ -+// keyboard mapping table -+static const unsigned int KeyTbl[] = { -+ -+ // misc keys -+ -+ XK_Escape, Qt::Key_Escape, -+ XK_Tab, Qt::Key_Tab, -+ XK_ISO_Left_Tab, Qt::Key_Backtab, -+ XK_BackSpace, Qt::Key_Backspace, -+ XK_Return, Qt::Key_Return, -+ XK_Insert, Qt::Key_Insert, -+ XK_Delete, Qt::Key_Delete, -+ XK_Clear, Qt::Key_Delete, -+ XK_Pause, Qt::Key_Pause, -+ XK_Print, Qt::Key_Print, -+ 0x1005FF60, Qt::Key_SysReq, // hardcoded Sun SysReq -+ 0x1007ff00, Qt::Key_SysReq, // hardcoded X386 SysReq -+ -+ // cursor movement -+ -+ XK_Home, Qt::Key_Home, -+ XK_End, Qt::Key_End, -+ XK_Left, Qt::Key_Left, -+ XK_Up, Qt::Key_Up, -+ XK_Right, Qt::Key_Right, -+ XK_Down, Qt::Key_Down, -+ XK_Prior, Qt::Key_PageUp, -+ XK_Next, Qt::Key_PageDown, -+ -+ // modifiers -+ -+ XK_Shift_L, Qt::Key_Shift, -+ XK_Shift_R, Qt::Key_Shift, -+ XK_Shift_Lock, Qt::Key_Shift, -+ XK_Control_L, Qt::Key_Control, -+ XK_Control_R, Qt::Key_Control, -+ XK_Meta_L, Qt::Key_Meta, -+ XK_Meta_R, Qt::Key_Meta, -+ XK_Alt_L, Qt::Key_Alt, -+ XK_Alt_R, Qt::Key_Alt, -+ XK_Caps_Lock, Qt::Key_CapsLock, -+ XK_Num_Lock, Qt::Key_NumLock, -+ XK_Scroll_Lock, Qt::Key_ScrollLock, -+ XK_Super_L, Qt::Key_Super_L, -+ XK_Super_R, Qt::Key_Super_R, -+ XK_Menu, Qt::Key_Menu, -+ XK_Hyper_L, Qt::Key_Hyper_L, -+ XK_Hyper_R, Qt::Key_Hyper_R, -+ XK_Help, Qt::Key_Help, -+ 0x1000FF74, Qt::Key_Backtab, // hardcoded HP backtab -+ 0x1005FF10, Qt::Key_F11, // hardcoded Sun F36 (labeled F11) -+ 0x1005FF11, Qt::Key_F12, // hardcoded Sun F37 (labeled F12) -+ -+ // numeric and function keypad keys -+ -+ XK_KP_Space, Qt::Key_Space, -+ XK_KP_Tab, Qt::Key_Tab, -+ XK_KP_Enter, Qt::Key_Enter, -+ //XK_KP_F1, Qt::Key_F1, -+ //XK_KP_F2, Qt::Key_F2, -+ //XK_KP_F3, Qt::Key_F3, -+ //XK_KP_F4, Qt::Key_F4, -+ XK_KP_Home, Qt::Key_Home, -+ XK_KP_Left, Qt::Key_Left, -+ XK_KP_Up, Qt::Key_Up, -+ XK_KP_Right, Qt::Key_Right, -+ XK_KP_Down, Qt::Key_Down, -+ XK_KP_Prior, Qt::Key_PageUp, -+ XK_KP_Next, Qt::Key_PageDown, -+ XK_KP_End, Qt::Key_End, -+ XK_KP_Begin, Qt::Key_Clear, -+ XK_KP_Insert, Qt::Key_Insert, -+ XK_KP_Delete, Qt::Key_Delete, -+ XK_KP_Equal, Qt::Key_Equal, -+ XK_KP_Multiply, Qt::Key_Asterisk, -+ XK_KP_Add, Qt::Key_Plus, -+ XK_KP_Separator, Qt::Key_Comma, -+ XK_KP_Subtract, Qt::Key_Minus, -+ XK_KP_Decimal, Qt::Key_Period, -+ XK_KP_Divide, Qt::Key_Slash, -+ -+ // International input method support keys -+ -+ // International & multi-key character composition -+ XK_ISO_Level3_Shift, Qt::Key_AltGr, -+ XK_Multi_key, Qt::Key_Multi_key, -+ XK_Codeinput, Qt::Key_Codeinput, -+ XK_SingleCandidate, Qt::Key_SingleCandidate, -+ XK_MultipleCandidate, Qt::Key_MultipleCandidate, -+ XK_PreviousCandidate, Qt::Key_PreviousCandidate, -+ -+ // Misc Functions -+ XK_Mode_switch, Qt::Key_Mode_switch, -+ XK_script_switch, Qt::Key_Mode_switch, -+ -+ // Japanese keyboard support -+ XK_Kanji, Qt::Key_Kanji, -+ XK_Muhenkan, Qt::Key_Muhenkan, -+ //XK_Henkan_Mode, Qt::Key_Henkan_Mode, -+ XK_Henkan_Mode, Qt::Key_Henkan, -+ XK_Henkan, Qt::Key_Henkan, -+ XK_Romaji, Qt::Key_Romaji, -+ XK_Hiragana, Qt::Key_Hiragana, -+ XK_Katakana, Qt::Key_Katakana, -+ XK_Hiragana_Katakana, Qt::Key_Hiragana_Katakana, -+ XK_Zenkaku, Qt::Key_Zenkaku, -+ XK_Hankaku, Qt::Key_Hankaku, -+ XK_Zenkaku_Hankaku, Qt::Key_Zenkaku_Hankaku, -+ XK_Touroku, Qt::Key_Touroku, -+ XK_Massyo, Qt::Key_Massyo, -+ XK_Kana_Lock, Qt::Key_Kana_Lock, -+ XK_Kana_Shift, Qt::Key_Kana_Shift, -+ XK_Eisu_Shift, Qt::Key_Eisu_Shift, -+ XK_Eisu_toggle, Qt::Key_Eisu_toggle, -+ //XK_Kanji_Bangou, Qt::Key_Kanji_Bangou, -+ //XK_Zen_Koho, Qt::Key_Zen_Koho, -+ //XK_Mae_Koho, Qt::Key_Mae_Koho, -+ XK_Kanji_Bangou, Qt::Key_Codeinput, -+ XK_Zen_Koho, Qt::Key_MultipleCandidate, -+ XK_Mae_Koho, Qt::Key_PreviousCandidate, -+ -+#ifdef XK_KOREAN -+ // Korean keyboard support -+ XK_Hangul, Qt::Key_Hangul, -+ XK_Hangul_Start, Qt::Key_Hangul_Start, -+ XK_Hangul_End, Qt::Key_Hangul_End, -+ XK_Hangul_Hanja, Qt::Key_Hangul_Hanja, -+ XK_Hangul_Jamo, Qt::Key_Hangul_Jamo, -+ XK_Hangul_Romaja, Qt::Key_Hangul_Romaja, -+ //XK_Hangul_Codeinput, Qt::Key_Hangul_Codeinput, -+ XK_Hangul_Codeinput, Qt::Key_Codeinput, -+ XK_Hangul_Jeonja, Qt::Key_Hangul_Jeonja, -+ XK_Hangul_Banja, Qt::Key_Hangul_Banja, -+ XK_Hangul_PreHanja, Qt::Key_Hangul_PreHanja, -+ XK_Hangul_PostHanja, Qt::Key_Hangul_PostHanja, -+ //XK_Hangul_SingleCandidate,Qt::Key_Hangul_SingleCandidate, -+ //XK_Hangul_MultipleCandidate,Qt::Key_Hangul_MultipleCandidate, -+ //XK_Hangul_PreviousCandidate,Qt::Key_Hangul_PreviousCandidate, -+ XK_Hangul_SingleCandidate, Qt::Key_SingleCandidate, -+ XK_Hangul_MultipleCandidate,Qt::Key_MultipleCandidate, -+ XK_Hangul_PreviousCandidate,Qt::Key_PreviousCandidate, -+ XK_Hangul_Special, Qt::Key_Hangul_Special, -+ //XK_Hangul_switch, Qt::Key_Hangul_switch, -+ XK_Hangul_switch, Qt::Key_Mode_switch, -+#endif // XK_KOREAN -+ -+ // dead keys -+ XK_dead_grave, Qt::Key_Dead_Grave, -+ XK_dead_acute, Qt::Key_Dead_Acute, -+ XK_dead_circumflex, Qt::Key_Dead_Circumflex, -+ XK_dead_tilde, Qt::Key_Dead_Tilde, -+ XK_dead_macron, Qt::Key_Dead_Macron, -+ XK_dead_breve, Qt::Key_Dead_Breve, -+ XK_dead_abovedot, Qt::Key_Dead_Abovedot, -+ XK_dead_diaeresis, Qt::Key_Dead_Diaeresis, -+ XK_dead_abovering, Qt::Key_Dead_Abovering, -+ XK_dead_doubleacute, Qt::Key_Dead_Doubleacute, -+ XK_dead_caron, Qt::Key_Dead_Caron, -+ XK_dead_cedilla, Qt::Key_Dead_Cedilla, -+ XK_dead_ogonek, Qt::Key_Dead_Ogonek, -+ XK_dead_iota, Qt::Key_Dead_Iota, -+ XK_dead_voiced_sound, Qt::Key_Dead_Voiced_Sound, -+ XK_dead_semivoiced_sound, Qt::Key_Dead_Semivoiced_Sound, -+ XK_dead_belowdot, Qt::Key_Dead_Belowdot, -+ XK_dead_hook, Qt::Key_Dead_Hook, -+ XK_dead_horn, Qt::Key_Dead_Horn, -+ -+ // Special multimedia keys -+ // currently only tested with MS internet keyboard -+ -+ // browsing keys -+ XF86XK_Back, Qt::Key_Back, -+ XF86XK_Forward, Qt::Key_Forward, -+ XF86XK_Stop, Qt::Key_Stop, -+ XF86XK_Refresh, Qt::Key_Refresh, -+ XF86XK_Favorites, Qt::Key_Favorites, -+ XF86XK_AudioMedia, Qt::Key_LaunchMedia, -+ XF86XK_OpenURL, Qt::Key_OpenUrl, -+ XF86XK_HomePage, Qt::Key_HomePage, -+ XF86XK_Search, Qt::Key_Search, -+ -+ // media keys -+ XF86XK_AudioLowerVolume, Qt::Key_VolumeDown, -+ XF86XK_AudioMute, Qt::Key_VolumeMute, -+ XF86XK_AudioRaiseVolume, Qt::Key_VolumeUp, -+ XF86XK_AudioPlay, Qt::Key_MediaPlay, -+ XF86XK_AudioStop, Qt::Key_MediaStop, -+ XF86XK_AudioPrev, Qt::Key_MediaPrevious, -+ XF86XK_AudioNext, Qt::Key_MediaNext, -+ XF86XK_AudioRecord, Qt::Key_MediaRecord, -+ -+ // launch keys -+ XF86XK_Mail, Qt::Key_LaunchMail, -+ XF86XK_MyComputer, Qt::Key_Launch0, -+ XF86XK_Calculator, Qt::Key_Launch1, -+ XF86XK_Standby, Qt::Key_Standby, -+ -+ XF86XK_Launch0, Qt::Key_Launch2, -+ XF86XK_Launch1, Qt::Key_Launch3, -+ XF86XK_Launch2, Qt::Key_Launch4, -+ XF86XK_Launch3, Qt::Key_Launch5, -+ XF86XK_Launch4, Qt::Key_Launch6, -+ XF86XK_Launch5, Qt::Key_Launch7, -+ XF86XK_Launch6, Qt::Key_Launch8, -+ XF86XK_Launch7, Qt::Key_Launch9, -+ XF86XK_Launch8, Qt::Key_LaunchA, -+ XF86XK_Launch9, Qt::Key_LaunchB, -+ XF86XK_LaunchA, Qt::Key_LaunchC, -+ XF86XK_LaunchB, Qt::Key_LaunchD, -+ XF86XK_LaunchC, Qt::Key_LaunchE, -+ XF86XK_LaunchD, Qt::Key_LaunchF, -+ -+ // Qtopia keys -+ QTOPIAXK_Select, Qt::Key_Select, -+ QTOPIAXK_Yes, Qt::Key_Yes, -+ QTOPIAXK_No, Qt::Key_No, -+ QTOPIAXK_Cancel, Qt::Key_Cancel, -+ QTOPIAXK_Printer, Qt::Key_Printer, -+ QTOPIAXK_Execute, Qt::Key_Execute, -+ QTOPIAXK_Sleep, Qt::Key_Sleep, -+ QTOPIAXK_Play, Qt::Key_Play, -+ QTOPIAXK_Zoom, Qt::Key_Zoom, -+ QTOPIAXK_Context1, Qt::Key_Context1, -+ QTOPIAXK_Context2, Qt::Key_Context2, -+ QTOPIAXK_Context3, Qt::Key_Context3, -+ QTOPIAXK_Context4, Qt::Key_Context4, -+ QTOPIAXK_Call, Qt::Key_Call, -+ QTOPIAXK_Hangup, Qt::Key_Hangup, -+ QTOPIAXK_Flip, Qt::Key_Flip, -+ -+ 0, 0 -+}; -+ -+#endif // KEYMAPPER_X11_H -diff -ru libqxt-old/src/gui/qxtglobalshortcut_win.cpp libqxt/src/gui/qxtglobalshortcut_win.cpp ---- libqxt-old/src/gui/qxtglobalshortcut_win.cpp 2010-04-21 15:17:56.000000000 +0100 -+++ libqxt/src/gui/qxtglobalshortcut_win.cpp 2010-04-21 15:18:16.000000000 +0100 -@@ -156,6 +156,21 @@ - case Qt::Key_Slash: - return VK_DIVIDE; - -+ case Qt::Key_MediaNext: -+ return VK_MEDIA_NEXT_TRACK; -+ case Qt::Key_MediaPrevious: -+ return VK_MEDIA_PREV_TRACK; -+ case Qt::Key_MediaStop: -+ return VK_MEDIA_STOP; -+ case Qt::Key_MediaPlay: -+ return VK_MEDIA_PLAY_PAUSE; -+ case Qt::Key_VolumeDown: -+ return VK_VOLUME_DOWN; -+ case Qt::Key_VolumeUp: -+ return VK_VOLUME_UP; -+ case Qt::Key_VolumeMute: -+ return VK_VOLUME_MUTE; -+ - // numbers - case Qt::Key_0: - case Qt::Key_1: -diff -ru libqxt-old/src/gui/qxtglobalshortcut_x11.cpp libqxt/src/gui/qxtglobalshortcut_x11.cpp ---- libqxt-old/src/gui/qxtglobalshortcut_x11.cpp 2010-04-21 15:17:56.000000000 +0100 -+++ libqxt/src/gui/qxtglobalshortcut_x11.cpp 2010-04-21 15:18:16.000000000 +0100 -@@ -26,6 +26,8 @@ - #include - #include - -+#include "keymapper_x11.h" -+ - static int (*original_x_errhandler)(Display* display, XErrorEvent* event); - - static int qxt_x_errhandler(Display* display, XErrorEvent *event) -@@ -81,8 +83,25 @@ - - quint32 QxtGlobalShortcutPrivate::nativeKeycode(Qt::Key key) - { -+ // (davidsansome) Try the table from QKeyMapper first - this seems to be -+ // the only way to get Keysyms for the media keys. -+ unsigned int keysym = 0; -+ int i = 0; -+ while (KeyTbl[i]) { -+ if (KeyTbl[i+1] == static_cast(key)) { -+ keysym = KeyTbl[i]; -+ break; -+ } -+ i += 2; -+ } -+ -+ // If that didn't work then fall back on XStringToKeysym -+ if (!keysym) { -+ keysym = XStringToKeysym(QKeySequence(key).toString().toLatin1().data()); -+ } -+ - Display* display = QX11Info::display(); -- return XKeysymToKeycode(display, XStringToKeysym(QKeySequence(key).toString().toLatin1().data())); -+ return XKeysymToKeycode(display, keysym); - } - - bool QxtGlobalShortcutPrivate::registerShortcut(quint32 nativeKey, quint32 nativeMods) diff --git a/3rdparty/qxt/meta-modifier.patch b/3rdparty/qxt/meta-modifier.patch deleted file mode 100644 index f77b97a57..000000000 --- a/3rdparty/qxt/meta-modifier.patch +++ /dev/null @@ -1,15 +0,0 @@ -Index: qxtglobalshortcut_x11.cpp -=================================================================== ---- qxtglobalshortcut_x11.cpp (revision 1208) -+++ qxtglobalshortcut_x11.cpp (working copy) -@@ -74,8 +74,9 @@ - native |= ControlMask; - if (modifiers & Qt::AltModifier) - native |= Mod1Mask; -+ if (modifiers & Qt::MetaModifier) -+ native |= Mod4Mask; - // TODO: resolve these? -- //if (modifiers & Qt::MetaModifier) - //if (modifiers & Qt::KeypadModifier) - //if (modifiers & Qt::GroupSwitchModifier) - return native; diff --git a/3rdparty/qxt/qxtglobal.cpp b/3rdparty/qxt/qxtglobal.cpp index fe7b9e782..3da47c146 100644 --- a/3rdparty/qxt/qxtglobal.cpp +++ b/3rdparty/qxt/qxtglobal.cpp @@ -1,27 +1,33 @@ + /**************************************************************************** - ** - ** Copyright (C) Qxt Foundation. Some rights reserved. - ** - ** This file is part of the QxtCore module of the Qxt library. - ** - ** This library is free software; you can redistribute it and/or modify it - ** under the terms of the Common Public License, version 1.0, as published - ** by IBM, and/or under the terms of the GNU Lesser General Public License, - ** version 2.1, as published by the Free Software Foundation. - ** - ** This file is provided "AS IS", without WARRANTIES OR CONDITIONS OF ANY - ** KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY - ** WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR - ** FITNESS FOR A PARTICULAR PURPOSE. - ** - ** You should have received a copy of the CPL and the LGPL along with this - ** file. See the LICENSE file and the cpl1.0.txt/lgpl-2.1.txt files - ** included with the source distribution for more information. - ** If you did not receive a copy of the licenses, contact the Qxt Foundation. - ** - ** - ** - ****************************************************************************/ +** Copyright (c) 2006 - 2011, the LibQxt project. +** See the Qxt AUTHORS file for a list of authors and copyright holders. +** All rights reserved. +** +** 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 LibQxt project 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 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. +** +** +*****************************************************************************/ #include "qxtglobal.h" @@ -74,7 +80,7 @@ \sa QXT_VERSION_STR */ -const char* qxtVersion() +const char * qxtVersion() { return QXT_VERSION_STR; } @@ -170,13 +176,14 @@ void MyTestPrivate::doQuux() { * \relates * Declares that a public class has a related private class. * - * This shuold be put in the private section of the public class. The parameter is the name of the public class. + * This shuold be put in the private section of the public class. The + * parameter \a PUB must be the name of the public class. */ /*! * \macro QXT_DECLARE_PUBLIC(PUB) * \relates - * Declares that a private class has a related public class. + * Declares that a private class has a related public class named \a PUB. * * This may be put anywhere in the declaration of the private class. The parameter is the name of the public class. */ @@ -187,23 +194,26 @@ void MyTestPrivate::doQuux() { * Initializes resources owned by the private class. * * This should be called from the public class's constructor, - * before qxt_d() is used for the first time. The parameter is the name of the public class. + * before qxt_d() is used for the first time. The parameter \a PUB must be + * the name of the public class. */ /*! * \macro QXT_D(PUB) * \relates - * Returns a reference in the current scope named "d" to the private class. + * Returns a reference in the current scope named "d" to the private class + * associated with the public class \a PUB. * - * This function is only available in a class using \a QXT_DECLARE_PRIVATE. + * This function is only available in a class using QXT_DECLARE_PRIVATE(). */ /*! * \macro QXT_P(PUB) * \relates - * Creates a reference in the current scope named "q" to the public class. + * Creates a reference in the current scope named "q" to the public class + * named \a PUB. * - * This macro only works in a class using \a QXT_DECLARE_PUBLIC. + * This macro only works in a class using QXT_DECLARE_PUBLIC(). */ /*! @@ -228,7 +238,7 @@ void MyTestPrivate::doQuux() { * \relates * Returns a reference to the public class. * - * This function is only available in a class using \a QXT_DECLARE_PUBLIC. + * This function is only available in a class using QXT_DECLARE_PUBLIC(). */ /*! @@ -236,6 +246,6 @@ void MyTestPrivate::doQuux() { * \relates * Returns a const reference to the public class. * - * This function is only available in a class using \a QXT_DECLARE_PUBLIC. + * This function is only available in a class using QXT_DECLARE_PUBLIC(). * This overload will be automatically used in const functions. */ diff --git a/3rdparty/qxt/qxtglobal.h b/3rdparty/qxt/qxtglobal.h index 575372dcd..7d5abfbe0 100644 --- a/3rdparty/qxt/qxtglobal.h +++ b/3rdparty/qxt/qxtglobal.h @@ -1,47 +1,57 @@ + /**************************************************************************** - ** - ** Copyright (C) Qxt Foundation. Some rights reserved. - ** - ** This file is part of the QxtCore module of the Qxt library. - ** - ** This library is free software; you can redistribute it and/or modify it - ** under the terms of the Common Public License, version 1.0, as published - ** by IBM, and/or under the terms of the GNU Lesser General Public License, - ** version 2.1, as published by the Free Software Foundation. - ** - ** This file is provided "AS IS", without WARRANTIES OR CONDITIONS OF ANY - ** KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY - ** WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR - ** FITNESS FOR A PARTICULAR PURPOSE. - ** - ** You should have received a copy of the CPL and the LGPL along with this - ** file. See the LICENSE file and the cpl1.0.txt/lgpl-2.1.txt files - ** included with the source distribution for more information. - ** If you did not receive a copy of the licenses, contact the Qxt Foundation. - ** - ** - ** - ****************************************************************************/ +** Copyright (c) 2006 - 2011, the LibQxt project. +** See the Qxt AUTHORS file for a list of authors and copyright holders. +** All rights reserved. +** +** 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 LibQxt project 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 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. +** +** +*****************************************************************************/ #ifndef QXTGLOBAL_H #define QXTGLOBAL_H #include -#define QXT_VERSION 0x000600 -#define QXT_VERSION_STR "0.6.0" +#define QXT_VERSION 0x000700 +#define QXT_VERSION_STR "0.7.0" //--------------------------global macros------------------------------ #ifndef QXT_NO_MACROS +#ifndef _countof +#define _countof(x) (sizeof(x)/sizeof(*x)) +#endif + #endif // QXT_NO_MACROS //--------------------------export macros------------------------------ #define QXT_DLLEXPORT DO_NOT_USE_THIS_ANYMORE -#if !defined(QXT_STATIC) +#if !defined(QXT_STATIC) && !defined(QXT_DOXYGEN_RUN) # if defined(BUILD_QXT_CORE) # define QXT_CORE_EXPORT Q_DECL_EXPORT # else @@ -51,7 +61,7 @@ # define QXT_CORE_EXPORT #endif // BUILD_QXT_CORE -#if !defined(QXT_STATIC) +#if !defined(QXT_STATIC) && !defined(QXT_DOXYGEN_RUN) # if defined(BUILD_QXT_GUI) # define QXT_GUI_EXPORT Q_DECL_EXPORT # else @@ -61,7 +71,7 @@ # define QXT_GUI_EXPORT #endif // BUILD_QXT_GUI -#if !defined(QXT_STATIC) +#if !defined(QXT_STATIC) && !defined(QXT_DOXYGEN_RUN) # if defined(BUILD_QXT_NETWORK) # define QXT_NETWORK_EXPORT Q_DECL_EXPORT # else @@ -71,7 +81,7 @@ # define QXT_NETWORK_EXPORT #endif // BUILD_QXT_NETWORK -#if !defined(QXT_STATIC) +#if !defined(QXT_STATIC) && !defined(QXT_DOXYGEN_RUN) # if defined(BUILD_QXT_SQL) # define QXT_SQL_EXPORT Q_DECL_EXPORT # else @@ -81,7 +91,7 @@ # define QXT_SQL_EXPORT #endif // BUILD_QXT_SQL -#if !defined(QXT_STATIC) +#if !defined(QXT_STATIC) && !defined(QXT_DOXYGEN_RUN) # if defined(BUILD_QXT_WEB) # define QXT_WEB_EXPORT Q_DECL_EXPORT # else @@ -91,7 +101,7 @@ # define QXT_WEB_EXPORT #endif // BUILD_QXT_WEB -#if !defined(QXT_STATIC) +#if !defined(QXT_STATIC) && !defined(QXT_DOXYGEN_RUN) # if defined(BUILD_QXT_BERKELEY) # define QXT_BERKELEY_EXPORT Q_DECL_EXPORT # else @@ -101,7 +111,7 @@ # define QXT_BERKELEY_EXPORT #endif // BUILD_QXT_BERKELEY -#if !defined(QXT_STATIC) +#if !defined(QXT_STATIC) && !defined(QXT_DOXYGEN_RUN) # if defined(BUILD_QXT_ZEROCONF) # define QXT_ZEROCONF_EXPORT Q_DECL_EXPORT # else @@ -111,7 +121,7 @@ # define QXT_ZEROCONF_EXPORT #endif // QXT_ZEROCONF_EXPORT -#if defined BUILD_QXT_CORE || defined BUILD_QXT_GUI || defined BUILD_QXT_SQL || defined BUILD_QXT_NETWORK || defined BUILD_QXT_WEB || defined BUILD_QXT_BERKELEY || defined BUILD_QXT_ZEROCONF +#if defined(BUILD_QXT_CORE) || defined(BUILD_QXT_GUI) || defined(BUILD_QXT_SQL) || defined(BUILD_QXT_NETWORK) || defined(BUILD_QXT_WEB) || defined(BUILD_QXT_BERKELEY) || defined(BUILD_QXT_ZEROCONF) # define BUILD_QXT #endif @@ -167,6 +177,14 @@ protected: { return *qxt_p_ptr; } + inline PUB* qxt_ptr() + { + return qxt_p_ptr; + } + inline const PUB* qxt_ptr() const + { + return qxt_p_ptr; + } private: PUB* qxt_p_ptr; @@ -198,6 +216,14 @@ public: { return *static_cast(pvt); } + inline PVT * operator->() + { + return static_cast(pvt); + } + inline const PVT * operator->() const + { + return static_cast(pvt); + } private: QxtPrivateInterface(const QxtPrivateInterface&) { } QxtPrivateInterface& operator=(const QxtPrivateInterface&) { } diff --git a/3rdparty/qxt/qxtglobalshortcut.cpp b/3rdparty/qxt/qxtglobalshortcut.cpp index ef378f965..cfc8bfbc4 100644 --- a/3rdparty/qxt/qxtglobalshortcut.cpp +++ b/3rdparty/qxt/qxtglobalshortcut.cpp @@ -1,47 +1,69 @@ -/**************************************************************************** - ** - ** Copyright (C) Qxt Foundation. Some rights reserved. - ** - ** This file is part of the QxtGui module of the Qxt library. - ** - ** This library is free software; you can redistribute it and/or modify it - ** under the terms of the Common Public License, version 1.0, as published - ** by IBM, and/or under the terms of the GNU Lesser General Public License, - ** version 2.1, as published by the Free Software Foundation. - ** - ** This file is provided "AS IS", without WARRANTIES OR CONDITIONS OF ANY - ** KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY - ** WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR - ** FITNESS FOR A PARTICULAR PURPOSE. - ** - ** You should have received a copy of the CPL and the LGPL along with this - ** file. See the LICENSE file and the cpl1.0.txt/lgpl-2.1.txt files - ** included with the source distribution for more information. - ** If you did not receive a copy of the licenses, contact the Qxt Foundation. - ** - ** - ** - ****************************************************************************/ #include "qxtglobalshortcut.h" +/**************************************************************************** +** Copyright (c) 2006 - 2011, the LibQxt project. +** See the Qxt AUTHORS file for a list of authors and copyright holders. +** All rights reserved. +** +** 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 LibQxt project 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 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. +** +** +*****************************************************************************/ + #include "qxtglobalshortcut_p.h" #include #include bool QxtGlobalShortcutPrivate::error = false; +#ifndef Q_OS_MAC int QxtGlobalShortcutPrivate::ref = 0; +#if QT_VERSION < QT_VERSION_CHECK(5,0,0) QAbstractEventDispatcher::EventFilter QxtGlobalShortcutPrivate::prevEventFilter = 0; +#endif +#endif // Q_OS_MAC QHash, QxtGlobalShortcut*> QxtGlobalShortcutPrivate::shortcuts; QxtGlobalShortcutPrivate::QxtGlobalShortcutPrivate() : enabled(true), key(Qt::Key(0)), mods(Qt::NoModifier) { - if (!ref++) +#ifndef Q_OS_MAC + if (!ref++) +#if QT_VERSION < QT_VERSION_CHECK(5,0,0) prevEventFilter = QAbstractEventDispatcher::instance()->setEventFilter(eventFilter); +#else + QAbstractEventDispatcher::instance()->installNativeEventFilter(this); +#endif +#endif // Q_OS_MAC } QxtGlobalShortcutPrivate::~QxtGlobalShortcutPrivate() { - if (!--ref) +#ifndef Q_OS_MAC + if (!--ref) +#if QT_VERSION < QT_VERSION_CHECK(5,0,0) QAbstractEventDispatcher::instance()->setEventFilter(prevEventFilter); +#else + QAbstractEventDispatcher::instance()->removeNativeEventFilter(this); +#endif +#endif // Q_OS_MAC } bool QxtGlobalShortcutPrivate::setShortcut(const QKeySequence& shortcut) @@ -52,19 +74,23 @@ bool QxtGlobalShortcutPrivate::setShortcut(const QKeySequence& shortcut) const quint32 nativeKey = nativeKeycode(key); const quint32 nativeMods = nativeModifiers(mods); const bool res = registerShortcut(nativeKey, nativeMods); - shortcuts.insert(qMakePair(nativeKey, nativeMods), &qxt_p()); - if (!res) + if (res) + shortcuts.insert(qMakePair(nativeKey, nativeMods), &qxt_p()); + else qWarning() << "QxtGlobalShortcut failed to register:" << QKeySequence(key + mods).toString(); return res; } bool QxtGlobalShortcutPrivate::unsetShortcut() { + bool res = false; const quint32 nativeKey = nativeKeycode(key); const quint32 nativeMods = nativeModifiers(mods); - const bool res = unregisterShortcut(nativeKey, nativeMods); - shortcuts.remove(qMakePair(nativeKey, nativeMods)); - if (!res) + if (shortcuts.value(qMakePair(nativeKey, nativeMods)) == &qxt_p()) + res = unregisterShortcut(nativeKey, nativeMods); + if (res) + shortcuts.remove(qMakePair(nativeKey, nativeMods)); + else qWarning() << "QxtGlobalShortcut failed to unregister:" << QKeySequence(key + mods).toString(); key = Qt::Key(0); mods = Qt::KeyboardModifiers(0); @@ -80,7 +106,7 @@ void QxtGlobalShortcutPrivate::activateShortcut(quint32 nativeKey, quint32 nativ /*! \class QxtGlobalShortcut - \inmodule QxtGui + \inmodule QxtWidgets \brief The QxtGlobalShortcut class provides a global shortcut aka "hotkey". A global shortcut triggers even if the application is not active. This @@ -189,3 +215,4 @@ void QxtGlobalShortcut::setDisabled(bool disabled) { qxt_d().enabled = !disabled; } + diff --git a/3rdparty/qxt/qxtglobalshortcut.h b/3rdparty/qxt/qxtglobalshortcut.h index a97ba2ddb..907e04c5d 100644 --- a/3rdparty/qxt/qxtglobalshortcut.h +++ b/3rdparty/qxt/qxtglobalshortcut.h @@ -1,28 +1,34 @@ -/**************************************************************************** - ** - ** Copyright (C) Qxt Foundation. Some rights reserved. - ** - ** This file is part of the QxtGui module of the Qxt library. - ** - ** This library is free software; you can redistribute it and/or modify it - ** under the terms of the Common Public License, version 1.0, as published - ** by IBM, and/or under the terms of the GNU Lesser General Public License, - ** version 2.1, as published by the Free Software Foundation. - ** - ** This file is provided "AS IS", without WARRANTIES OR CONDITIONS OF ANY - ** KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY - ** WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR - ** FITNESS FOR A PARTICULAR PURPOSE. - ** - ** You should have received a copy of the CPL and the LGPL along with this - ** file. See the LICENSE file and the cpl1.0.txt/lgpl-2.1.txt files - ** included with the source distribution for more information. - ** If you did not receive a copy of the licenses, contact the Qxt Foundation. - ** - ** - ** - ****************************************************************************/ #ifndef QXTGLOBALSHORTCUT_H +/**************************************************************************** +** Copyright (c) 2006 - 2011, the LibQxt project. +** See the Qxt AUTHORS file for a list of authors and copyright holders. +** All rights reserved. +** +** 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 LibQxt project 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 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. +** +** +*****************************************************************************/ + #define QXTGLOBALSHORTCUT_H #include "qxtglobal.h" @@ -56,3 +62,4 @@ Q_SIGNALS: }; #endif // QXTGLOBALSHORTCUT_H + diff --git a/3rdparty/qxt/qxtglobalshortcut_mac.cpp b/3rdparty/qxt/qxtglobalshortcut_mac.cpp index 80fa01bc7..0b5137685 100644 --- a/3rdparty/qxt/qxtglobalshortcut_mac.cpp +++ b/3rdparty/qxt/qxtglobalshortcut_mac.cpp @@ -1,209 +1,259 @@ -/**************************************************************************** - ** - ** Copyright (C) Qxt Foundation. Some rights reserved. - ** - ** This file is part of the QxtGui module of the Qxt library. - ** - ** This library is free software; you can redistribute it and/or modify it - ** under the terms of the Common Public License, version 1.0, as published - ** by IBM, and/or under the terms of the GNU Lesser General Public License, - ** version 2.1, as published by the Free Software Foundation. - ** - ** This file is provided "AS IS", without WARRANTIES OR CONDITIONS OF ANY - ** KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY - ** WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR - ** FITNESS FOR A PARTICULAR PURPOSE. - ** - ** You should have received a copy of the CPL and the LGPL along with this - ** file. See the LICENSE file and the cpl1.0.txt/lgpl-2.1.txt files - ** included with the source distribution for more information. - ** If you did not receive a copy of the licenses, contact the Qxt Foundation. - ** - ** - ** - ****************************************************************************/ -#include -#include "qxtglobalshortcut_p.h" -#include -#include -#include -#include - -typedef QPair Identifier; -static QMap keyRefs; -static QHash keyIDs; -static quint32 hotKeySerial = 0; -static bool qxt_mac_handler_installed = false; - -OSStatus qxt_mac_handle_hot_key(EventHandlerCallRef nextHandler, EventRef event, void* data) -{ - // pass event to the app event filter - Q_UNUSED(data); - qApp->macEventFilter(nextHandler, event); - return noErr; -} - -bool QxtGlobalShortcutPrivate::eventFilter(void* message) -//bool QxtGlobalShortcutPrivate::macEventFilter(EventHandlerCallRef caller, EventRef event) -{ - EventRef event = (EventRef) message; - if (GetEventClass(event) == kEventClassKeyboard && GetEventKind(event) == kEventHotKeyPressed) - { - EventHotKeyID keyID; - GetEventParameter(event, kEventParamDirectObject, typeEventHotKeyID, - nullptr, sizeof(keyID), nullptr, &keyID); - Identifier id = keyIDs.key(keyID.id); - activateShortcut(id.second, id.first); - } - return false; -} - -quint32 QxtGlobalShortcutPrivate::nativeModifiers(Qt::KeyboardModifiers modifiers) -{ - quint32 native = 0; - if (modifiers & Qt::ShiftModifier) - native |= shiftKeyBit; - if (modifiers & Qt::ControlModifier) - native |= cmdKey; - if (modifiers & Qt::AltModifier) - native |= optionKey; - if (modifiers & Qt::MetaModifier) - native |= controlKey; - if (modifiers & Qt::KeypadModifier) - native |= kEventKeyModifierNumLockMask; - return native; -} - -quint32 QxtGlobalShortcutPrivate::nativeKeycode(Qt::Key key) -{ - UTF16Char ch; - // Constants found in NSEvent.h from AppKit.framework - if (key == Qt::Key_Up) ch = 0xF700; - else if (key == Qt::Key_Down) ch = 0xF701; - else if (key == Qt::Key_Left) ch = 0xF702; - else if (key == Qt::Key_Right) ch = 0xF703; - else if (key >= Qt::Key_F1 && key <= Qt::Key_F35) - ch = key - Qt::Key_F1 + 0xF704; - else if (key == Qt::Key_Insert) ch = 0xF727; - else if (key == Qt::Key_Delete) ch = 0xF728; - else if (key == Qt::Key_Home) ch = 0xF729; - else if (key == Qt::Key_End) ch = 0xF72B; - else if (key == Qt::Key_PageUp) ch = 0xF72C; - else if (key == Qt::Key_PageDown) ch = 0xF72D; - else if (key == Qt::Key_Print) ch = 0xF72E; - else if (key == Qt::Key_ScrollLock) ch = 0xF72F; - else if (key == Qt::Key_Pause) ch = 0xF730; - else if (key == Qt::Key_SysReq) ch = 0xF731; - else if (key == Qt::Key_Stop) ch = 0xF734; - else if (key == Qt::Key_Menu) ch = 0xF735; - else if (key == Qt::Key_Select) ch = 0xF741; - else if (key == Qt::Key_Execute) ch = 0xF742; - else if (key == Qt::Key_Help) ch = 0xF746; - else if (key == Qt::Key_Mode_switch) ch = 0xF747; - else if (key == Qt::Key_Escape) ch = 27; - else if (key == Qt::Key_Return) ch = 13; - else if (key == Qt::Key_Enter) ch = 3; - else if (key == Qt::Key_Tab) ch = 9; - else ch = key; - - KeyboardLayoutRef layout; - KeyboardLayoutKind layoutKind; - KLGetCurrentKeyboardLayout(&layout); - KLGetKeyboardLayoutProperty(layout, kKLKind, const_cast(reinterpret_cast(&layoutKind))); - - if (layoutKind == kKLKCHRKind) - { // no Unicode available - if (ch > 255) return 0; - - char* data; - KLGetKeyboardLayoutProperty(layout, kKLKCHRData, const_cast(reinterpret_cast(&data))); - int ct = *reinterpret_cast(data + 258); - for (int i = 0; i < ct; i++) - { - char* keyTable = data + 260 + 128 * i; - for (int j = 0; j < 128; j++) - { - if (keyTable[j] == ch) return j; - } - } - - return 0; - } - - char* data; - KLGetKeyboardLayoutProperty(layout, kKLuchrData, const_cast(reinterpret_cast(&data))); - UCKeyboardLayout* header = reinterpret_cast(data); - UCKeyboardTypeHeader* table = header->keyboardTypeList; - - for (quint32 i=0; i < header->keyboardTypeCount; i++) - { - UCKeyStateRecordsIndex* stateRec = 0; - if (table[i].keyStateRecordsIndexOffset != 0) - { - stateRec = reinterpret_cast(data + table[i].keyStateRecordsIndexOffset); - if (stateRec->keyStateRecordsIndexFormat != kUCKeyStateRecordsIndexFormat) stateRec = 0; - } - - UCKeyToCharTableIndex* charTable = reinterpret_cast(data + table[i].keyToCharTableIndexOffset); - if (charTable->keyToCharTableIndexFormat != kUCKeyToCharTableIndexFormat) continue; - - for (quint32 j=0; j < charTable->keyToCharTableCount; j++) - { - UCKeyOutput* keyToChar = reinterpret_cast(data + charTable->keyToCharTableOffsets[j]); - for (quint32 k=0; k < charTable->keyToCharTableSize; k++) - { - if (keyToChar[k] & kUCKeyOutputTestForIndexMask) - { - long idx = keyToChar[k] & kUCKeyOutputGetIndexMask; - if (stateRec && idx < stateRec->keyStateRecordCount) - { - UCKeyStateRecord* rec = reinterpret_cast(data + stateRec->keyStateRecordOffsets[idx]); - if (rec->stateZeroCharData == ch) return k; - } - } - else if (!(keyToChar[k] & kUCKeyOutputSequenceIndexMask) && keyToChar[k] < 0xFFFE) - { - if (keyToChar[k] == ch) return k; - } - } // for k - } // for j - } // for i - - return 0; -} - -bool QxtGlobalShortcutPrivate::registerShortcut(quint32 nativeKey, quint32 nativeMods) -{ - if (!qxt_mac_handler_installed) - { - EventTypeSpec t; - t.eventClass = kEventClassKeyboard; - t.eventKind = kEventHotKeyPressed; - InstallApplicationEventHandler(&qxt_mac_handle_hot_key, 1, &t, nullptr, - nullptr); - } - - EventHotKeyID keyID; - keyID.signature = 'cute'; - keyID.id = ++hotKeySerial; - - EventHotKeyRef ref = 0; - bool rv = !RegisterEventHotKey(nativeKey, nativeMods, keyID, GetApplicationEventTarget(), 0, &ref); - if (rv) - { - keyIDs.insert(Identifier(nativeMods, nativeKey), keyID.id); - keyRefs.insert(keyID.id, ref); - } - qDebug() << ref; - return rv; -} - -bool QxtGlobalShortcutPrivate::unregisterShortcut(quint32 nativeKey, quint32 nativeMods) -{ - Identifier id(nativeMods, nativeKey); - if (!keyIDs.contains(id)) return false; - - EventHotKeyRef ref = keyRefs.take(keyIDs[id]); - keyIDs.remove(id); - return !UnregisterEventHotKey(ref); -} +#include +/**************************************************************************** +** Copyright (c) 2006 - 2011, the LibQxt project. +** See the Qxt AUTHORS file for a list of authors and copyright holders. +** All rights reserved. +** +** 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 LibQxt project 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 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. +** +** +*****************************************************************************/ + +#include "qxtglobalshortcut_p.h" +#include +#include +#include +#include + +typedef QPair Identifier; +static QMap keyRefs; +static QHash keyIDs; +static quint32 hotKeySerial = 0; +static bool qxt_mac_handler_installed = false; + +OSStatus qxt_mac_handle_hot_key(EventHandlerCallRef nextHandler, EventRef event, void* data) +{ + Q_UNUSED(nextHandler); + Q_UNUSED(data); + if (GetEventClass(event) == kEventClassKeyboard && GetEventKind(event) == kEventHotKeyPressed) + { + EventHotKeyID keyID; + GetEventParameter(event, kEventParamDirectObject, typeEventHotKeyID, NULL, sizeof(keyID), NULL, &keyID); + Identifier id = keyIDs.key(keyID.id); + QxtGlobalShortcutPrivate::activateShortcut(id.second, id.first); + } + return noErr; +} + +quint32 QxtGlobalShortcutPrivate::nativeModifiers(Qt::KeyboardModifiers modifiers) +{ + quint32 native = 0; + if (modifiers & Qt::ShiftModifier) + native |= shiftKey; + if (modifiers & Qt::ControlModifier) + native |= cmdKey; + if (modifiers & Qt::AltModifier) + native |= optionKey; + if (modifiers & Qt::MetaModifier) + native |= controlKey; + if (modifiers & Qt::KeypadModifier) + native |= kEventKeyModifierNumLockMask; + return native; +} + +quint32 QxtGlobalShortcutPrivate::nativeKeycode(Qt::Key key) +{ + UTF16Char ch; + // Constants found in NSEvent.h from AppKit.framework + switch (key) + { + case Qt::Key_Return: + return kVK_Return; + case Qt::Key_Enter: + return kVK_ANSI_KeypadEnter; + case Qt::Key_Tab: + return kVK_Tab; + case Qt::Key_Space: + return kVK_Space; + case Qt::Key_Backspace: + return kVK_Delete; + case Qt::Key_Control: + return kVK_Command; + case Qt::Key_Shift: + return kVK_Shift; + case Qt::Key_CapsLock: + return kVK_CapsLock; + case Qt::Key_Option: + return kVK_Option; + case Qt::Key_Meta: + return kVK_Control; + case Qt::Key_F17: + return kVK_F17; + case Qt::Key_VolumeUp: + return kVK_VolumeUp; + case Qt::Key_VolumeDown: + return kVK_VolumeDown; + case Qt::Key_F18: + return kVK_F18; + case Qt::Key_F19: + return kVK_F19; + case Qt::Key_F20: + return kVK_F20; + case Qt::Key_F5: + return kVK_F5; + case Qt::Key_F6: + return kVK_F6; + case Qt::Key_F7: + return kVK_F7; + case Qt::Key_F3: + return kVK_F3; + case Qt::Key_F8: + return kVK_F8; + case Qt::Key_F9: + return kVK_F9; + case Qt::Key_F11: + return kVK_F11; + case Qt::Key_F13: + return kVK_F13; + case Qt::Key_F16: + return kVK_F16; + case Qt::Key_F14: + return kVK_F14; + case Qt::Key_F10: + return kVK_F10; + case Qt::Key_F12: + return kVK_F12; + case Qt::Key_F15: + return kVK_F15; + case Qt::Key_Help: + return kVK_Help; + case Qt::Key_Home: + return kVK_Home; + case Qt::Key_PageUp: + return kVK_PageUp; + case Qt::Key_Delete: + return kVK_ForwardDelete; + case Qt::Key_F4: + return kVK_F4; + case Qt::Key_End: + return kVK_End; + case Qt::Key_F2: + return kVK_F2; + case Qt::Key_PageDown: + return kVK_PageDown; + case Qt::Key_F1: + return kVK_F1; + case Qt::Key_Left: + return kVK_LeftArrow; + case Qt::Key_Right: + return kVK_RightArrow; + case Qt::Key_Down: + return kVK_DownArrow; + case Qt::Key_Up: + return kVK_UpArrow; + default: + ; + } + + if (key == Qt::Key_Escape) ch = 27; + else if (key == Qt::Key_Return) ch = 13; + else if (key == Qt::Key_Enter) ch = 3; + else if (key == Qt::Key_Tab) ch = 9; + else ch = key; + + CFDataRef currentLayoutData; + TISInputSourceRef currentKeyboard = TISCopyCurrentKeyboardInputSource(); + + if (currentKeyboard == NULL) + return 0; + + currentLayoutData = (CFDataRef)TISGetInputSourceProperty(currentKeyboard, kTISPropertyUnicodeKeyLayoutData); + CFRelease(currentKeyboard); + if (currentLayoutData == NULL) + return 0; + + UCKeyboardLayout* header = (UCKeyboardLayout*)CFDataGetBytePtr(currentLayoutData); + UCKeyboardTypeHeader* table = header->keyboardTypeList; + + uint8_t *data = (uint8_t*)header; + // God, would a little documentation for this shit kill you... + for (quint32 i=0; i < header->keyboardTypeCount; i++) + { + UCKeyStateRecordsIndex* stateRec = 0; + if (table[i].keyStateRecordsIndexOffset != 0) + { + stateRec = reinterpret_cast(data + table[i].keyStateRecordsIndexOffset); + if (stateRec->keyStateRecordsIndexFormat != kUCKeyStateRecordsIndexFormat) stateRec = 0; + } + + UCKeyToCharTableIndex* charTable = reinterpret_cast(data + table[i].keyToCharTableIndexOffset); + if (charTable->keyToCharTableIndexFormat != kUCKeyToCharTableIndexFormat) continue; + + for (quint32 j=0; j < charTable->keyToCharTableCount; j++) + { + UCKeyOutput* keyToChar = reinterpret_cast(data + charTable->keyToCharTableOffsets[j]); + for (quint32 k=0; k < charTable->keyToCharTableSize; k++) + { + if (keyToChar[k] & kUCKeyOutputTestForIndexMask) + { + long idx = keyToChar[k] & kUCKeyOutputGetIndexMask; + if (stateRec && idx < stateRec->keyStateRecordCount) + { + UCKeyStateRecord* rec = reinterpret_cast(data + stateRec->keyStateRecordOffsets[idx]); + if (rec->stateZeroCharData == ch) return k; + } + } + else if (!(keyToChar[k] & kUCKeyOutputSequenceIndexMask) && keyToChar[k] < 0xFFFE) + { + if (keyToChar[k] == ch) return k; + } + } // for k + } // for j + } // for i + return 0; +} + +bool QxtGlobalShortcutPrivate::registerShortcut(quint32 nativeKey, quint32 nativeMods) +{ + if (!qxt_mac_handler_installed) + { + EventTypeSpec t; + t.eventClass = kEventClassKeyboard; + t.eventKind = kEventHotKeyPressed; + InstallApplicationEventHandler(&qxt_mac_handle_hot_key, 1, &t, NULL, NULL); + } + + EventHotKeyID keyID; + keyID.signature = 'cute'; + keyID.id = ++hotKeySerial; + + EventHotKeyRef ref = 0; + bool rv = !RegisterEventHotKey(nativeKey, nativeMods, keyID, GetApplicationEventTarget(), 0, &ref); + if (rv) + { + keyIDs.insert(Identifier(nativeMods, nativeKey), keyID.id); + keyRefs.insert(keyID.id, ref); + } + return rv; +} + +bool QxtGlobalShortcutPrivate::unregisterShortcut(quint32 nativeKey, quint32 nativeMods) +{ + Identifier id(nativeMods, nativeKey); + if (!keyIDs.contains(id)) return false; + + EventHotKeyRef ref = keyRefs.take(keyIDs[id]); + keyIDs.remove(id); + return !UnregisterEventHotKey(ref); +} diff --git a/3rdparty/qxt/qxtglobalshortcut_p.h b/3rdparty/qxt/qxtglobalshortcut_p.h index 4570396fe..98c6cd543 100644 --- a/3rdparty/qxt/qxtglobalshortcut_p.h +++ b/3rdparty/qxt/qxtglobalshortcut_p.h @@ -1,63 +1,84 @@ -/**************************************************************************** - ** - ** Copyright (C) Qxt Foundation. Some rights reserved. - ** - ** This file is part of the QxtGui module of the Qxt library. - ** - ** This library is free software; you can redistribute it and/or modify it - ** under the terms of the Common Public License, version 1.0, as published - ** by IBM, and/or under the terms of the GNU Lesser General Public License, - ** version 2.1, as published by the Free Software Foundation. - ** - ** This file is provided "AS IS", without WARRANTIES OR CONDITIONS OF ANY - ** KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY - ** WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR - ** FITNESS FOR A PARTICULAR PURPOSE. - ** - ** You should have received a copy of the CPL and the LGPL along with this - ** file. See the LICENSE file and the cpl1.0.txt/lgpl-2.1.txt files - ** included with the source distribution for more information. - ** If you did not receive a copy of the licenses, contact the Qxt Foundation. - ** - ** - ** - ****************************************************************************/ -#ifndef QXTGLOBALSHORTCUT_P_H -#define QXTGLOBALSHORTCUT_P_H - -#include "qxtglobalshortcut.h" -#include -#include -#include - -class QxtGlobalShortcutPrivate : public QxtPrivate -{ -public: - QXT_DECLARE_PUBLIC(QxtGlobalShortcut) - QxtGlobalShortcutPrivate(); - ~QxtGlobalShortcutPrivate(); - - bool enabled; - Qt::Key key; - Qt::KeyboardModifiers mods; - - bool setShortcut(const QKeySequence& shortcut); - bool unsetShortcut(); - - static bool error; - static int ref; - static QAbstractEventDispatcher::EventFilter prevEventFilter; - static bool eventFilter(void* message); - -private: - static quint32 nativeKeycode(Qt::Key keycode); - static quint32 nativeModifiers(Qt::KeyboardModifiers modifiers); - - static bool registerShortcut(quint32 nativeKey, quint32 nativeMods); - static bool unregisterShortcut(quint32 nativeKey, quint32 nativeMods); - static void activateShortcut(quint32 nativeKey, quint32 nativeMods); - - static QHash, QxtGlobalShortcut*> shortcuts; -}; - -#endif // QXTGLOBALSHORTCUT_P_H +#ifndef QXTGLOBALSHORTCUT_P_H +/**************************************************************************** +** Copyright (c) 2006 - 2011, the LibQxt project. +** See the Qxt AUTHORS file for a list of authors and copyright holders. +** All rights reserved. +** +** 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 LibQxt project 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 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. +** +** +*****************************************************************************/ + +#define QXTGLOBALSHORTCUT_P_H + +#include "qxtglobalshortcut.h" +#include +#include +#include + +#if QT_VERSION >= QT_VERSION_CHECK(5,0,0) +#include +#endif + + +class QxtGlobalShortcutPrivate : public QxtPrivate +#if QT_VERSION >= QT_VERSION_CHECK(5,0,0) + ,public QAbstractNativeEventFilter +#endif +{ +public: + QXT_DECLARE_PUBLIC(QxtGlobalShortcut) + QxtGlobalShortcutPrivate(); + ~QxtGlobalShortcutPrivate(); + + bool enabled; + Qt::Key key; + Qt::KeyboardModifiers mods; + + bool setShortcut(const QKeySequence& shortcut); + bool unsetShortcut(); + + static bool error; +#ifndef Q_OS_MAC + static int ref; +#if QT_VERSION < QT_VERSION_CHECK(5,0,0) + static QAbstractEventDispatcher::EventFilter prevEventFilter; + static bool eventFilter(void* message); +#else + virtual bool nativeEventFilter(const QByteArray & eventType, void * message, long * result); +#endif // QT_VERSION < QT_VERSION_CHECK(5,0,0) +#endif // Q_OS_MAC + + static void activateShortcut(quint32 nativeKey, quint32 nativeMods); + +private: + static quint32 nativeKeycode(Qt::Key keycode); + static quint32 nativeModifiers(Qt::KeyboardModifiers modifiers); + + static bool registerShortcut(quint32 nativeKey, quint32 nativeMods); + static bool unregisterShortcut(quint32 nativeKey, quint32 nativeMods); + + static QHash, QxtGlobalShortcut*> shortcuts; +}; + +#endif // QXTGLOBALSHORTCUT_P_H diff --git a/3rdparty/qxt/qxtglobalshortcut_win.cpp b/3rdparty/qxt/qxtglobalshortcut_win.cpp index d81f1089d..1f4b611d9 100644 --- a/3rdparty/qxt/qxtglobalshortcut_win.cpp +++ b/3rdparty/qxt/qxtglobalshortcut_win.cpp @@ -1,229 +1,247 @@ -/**************************************************************************** - ** - ** Copyright (C) Qxt Foundation. Some rights reserved. - ** - ** This file is part of the QxtGui module of the Qxt library. - ** - ** This library is free software; you can redistribute it and/or modify it - ** under the terms of the Common Public License, version 1.0, as published - ** by IBM, and/or under the terms of the GNU Lesser General Public License, - ** version 2.1, as published by the Free Software Foundation. - ** - ** This file is provided "AS IS", without WARRANTIES OR CONDITIONS OF ANY - ** KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY - ** WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR - ** FITNESS FOR A PARTICULAR PURPOSE. - ** - ** You should have received a copy of the CPL and the LGPL along with this - ** file. See the LICENSE file and the cpl1.0.txt/lgpl-2.1.txt files - ** included with the source distribution for more information. - ** If you did not receive a copy of the licenses, contact the Qxt Foundation. - ** - ** - ** - ****************************************************************************/ -#include "qxtglobalshortcut_p.h" -#include - -bool QxtGlobalShortcutPrivate::eventFilter(void* message) -{ - MSG* msg = static_cast(message); - if (msg->message == WM_HOTKEY) - { - const quint32 keycode = HIWORD(msg->lParam); - const quint32 modifiers = LOWORD(msg->lParam); - activateShortcut(keycode, modifiers); - } - return false; -} - -quint32 QxtGlobalShortcutPrivate::nativeModifiers(Qt::KeyboardModifiers modifiers) -{ - // MOD_ALT, MOD_CONTROL, (MOD_KEYUP), MOD_SHIFT, MOD_WIN - quint32 native = 0; - if (modifiers & Qt::ShiftModifier) - native |= MOD_SHIFT; - if (modifiers & Qt::ControlModifier) - native |= MOD_CONTROL; - if (modifiers & Qt::AltModifier) - native |= MOD_ALT; - if (modifiers & Qt::MetaModifier) - native |= MOD_WIN; - // TODO: resolve these? - //if (modifiers & Qt::KeypadModifier) - //if (modifiers & Qt::GroupSwitchModifier) - return native; -} - -quint32 QxtGlobalShortcutPrivate::nativeKeycode(Qt::Key key) -{ - switch (key) - { - case Qt::Key_Escape: - return VK_ESCAPE; - case Qt::Key_Tab: - case Qt::Key_Backtab: - return VK_TAB; - case Qt::Key_Backspace: - return VK_BACK; - case Qt::Key_Return: - case Qt::Key_Enter: - return VK_RETURN; - case Qt::Key_Insert: - return VK_INSERT; - case Qt::Key_Delete: - return VK_DELETE; - case Qt::Key_Pause: - return VK_PAUSE; - case Qt::Key_Print: - return VK_PRINT; - case Qt::Key_Clear: - return VK_CLEAR; - case Qt::Key_Home: - return VK_HOME; - case Qt::Key_End: - return VK_END; - case Qt::Key_Left: - return VK_LEFT; - case Qt::Key_Up: - return VK_UP; - case Qt::Key_Right: - return VK_RIGHT; - case Qt::Key_Down: - return VK_DOWN; - case Qt::Key_PageUp: - return VK_PRIOR; - case Qt::Key_PageDown: - return VK_NEXT; - case Qt::Key_F1: - return VK_F1; - case Qt::Key_F2: - return VK_F2; - case Qt::Key_F3: - return VK_F3; - case Qt::Key_F4: - return VK_F4; - case Qt::Key_F5: - return VK_F5; - case Qt::Key_F6: - return VK_F6; - case Qt::Key_F7: - return VK_F7; - case Qt::Key_F8: - return VK_F8; - case Qt::Key_F9: - return VK_F9; - case Qt::Key_F10: - return VK_F10; - case Qt::Key_F11: - return VK_F11; - case Qt::Key_F12: - return VK_F12; - case Qt::Key_F13: - return VK_F13; - case Qt::Key_F14: - return VK_F14; - case Qt::Key_F15: - return VK_F15; - case Qt::Key_F16: - return VK_F16; - case Qt::Key_F17: - return VK_F17; - case Qt::Key_F18: - return VK_F18; - case Qt::Key_F19: - return VK_F19; - case Qt::Key_F20: - return VK_F20; - case Qt::Key_F21: - return VK_F21; - case Qt::Key_F22: - return VK_F22; - case Qt::Key_F23: - return VK_F23; - case Qt::Key_F24: - return VK_F24; - case Qt::Key_Space: - return VK_SPACE; - case Qt::Key_Asterisk: - return VK_MULTIPLY; - case Qt::Key_Plus: - return VK_ADD; - case Qt::Key_Comma: - return VK_SEPARATOR; - case Qt::Key_Minus: - return VK_SUBTRACT; - case Qt::Key_Slash: - return VK_DIVIDE; - - case Qt::Key_MediaNext: - return VK_MEDIA_NEXT_TRACK; - case Qt::Key_MediaPrevious: - return VK_MEDIA_PREV_TRACK; - case Qt::Key_MediaStop: - return VK_MEDIA_STOP; - case Qt::Key_MediaPlay: - return VK_MEDIA_PLAY_PAUSE; - case Qt::Key_VolumeDown: - return VK_VOLUME_DOWN; - case Qt::Key_VolumeUp: - return VK_VOLUME_UP; - case Qt::Key_VolumeMute: - return VK_VOLUME_MUTE; - - // numbers - case Qt::Key_0: - case Qt::Key_1: - case Qt::Key_2: - case Qt::Key_3: - case Qt::Key_4: - case Qt::Key_5: - case Qt::Key_6: - case Qt::Key_7: - case Qt::Key_8: - case Qt::Key_9: - return key; - - // letters - case Qt::Key_A: - case Qt::Key_B: - case Qt::Key_C: - case Qt::Key_D: - case Qt::Key_E: - case Qt::Key_F: - case Qt::Key_G: - case Qt::Key_H: - case Qt::Key_I: - case Qt::Key_J: - case Qt::Key_K: - case Qt::Key_L: - case Qt::Key_M: - case Qt::Key_N: - case Qt::Key_O: - case Qt::Key_P: - case Qt::Key_Q: - case Qt::Key_R: - case Qt::Key_S: - case Qt::Key_T: - case Qt::Key_U: - case Qt::Key_V: - case Qt::Key_W: - case Qt::Key_X: - case Qt::Key_Y: - case Qt::Key_Z: - return key; - - default: - return 0; - } -} - -bool QxtGlobalShortcutPrivate::registerShortcut(quint32 nativeKey, quint32 nativeMods) -{ - return RegisterHotKey(0, nativeMods ^ nativeKey, nativeMods, nativeKey); -} - -bool QxtGlobalShortcutPrivate::unregisterShortcut(quint32 nativeKey, quint32 nativeMods) -{ - return UnregisterHotKey(0, nativeMods ^ nativeKey); -} +#include "qxtglobalshortcut_p.h" +/**************************************************************************** +** Copyright (c) 2006 - 2011, the LibQxt project. +** See the Qxt AUTHORS file for a list of authors and copyright holders. +** All rights reserved. +** +** 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 LibQxt project 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 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. +** +** +*****************************************************************************/ + +#include + + +#if QT_VERSION < QT_VERSION_CHECK(5,0,0) +bool QxtGlobalShortcutPrivate::eventFilter(void* message) +{ +#else +bool QxtGlobalShortcutPrivate::nativeEventFilter(const QByteArray & eventType, + void * message, long * result) +{ + Q_UNUSED(eventType); + Q_UNUSED(result); +#endif + MSG* msg = static_cast(message); + if (msg->message == WM_HOTKEY) + { + const quint32 keycode = HIWORD(msg->lParam); + const quint32 modifiers = LOWORD(msg->lParam); + activateShortcut(keycode, modifiers); + } + return false; +} + + +quint32 QxtGlobalShortcutPrivate::nativeModifiers(Qt::KeyboardModifiers modifiers) +{ + // MOD_ALT, MOD_CONTROL, (MOD_KEYUP), MOD_SHIFT, MOD_WIN + quint32 native = 0; + if (modifiers & Qt::ShiftModifier) + native |= MOD_SHIFT; + if (modifiers & Qt::ControlModifier) + native |= MOD_CONTROL; + if (modifiers & Qt::AltModifier) + native |= MOD_ALT; + if (modifiers & Qt::MetaModifier) + native |= MOD_WIN; + // TODO: resolve these? + //if (modifiers & Qt::KeypadModifier) + //if (modifiers & Qt::GroupSwitchModifier) + return native; +} + +quint32 QxtGlobalShortcutPrivate::nativeKeycode(Qt::Key key) +{ + switch (key) + { + case Qt::Key_Escape: + return VK_ESCAPE; + case Qt::Key_Tab: + case Qt::Key_Backtab: + return VK_TAB; + case Qt::Key_Backspace: + return VK_BACK; + case Qt::Key_Return: + case Qt::Key_Enter: + return VK_RETURN; + case Qt::Key_Insert: + return VK_INSERT; + case Qt::Key_Delete: + return VK_DELETE; + case Qt::Key_Pause: + return VK_PAUSE; + case Qt::Key_Print: + return VK_PRINT; + case Qt::Key_Clear: + return VK_CLEAR; + case Qt::Key_Home: + return VK_HOME; + case Qt::Key_End: + return VK_END; + case Qt::Key_Left: + return VK_LEFT; + case Qt::Key_Up: + return VK_UP; + case Qt::Key_Right: + return VK_RIGHT; + case Qt::Key_Down: + return VK_DOWN; + case Qt::Key_PageUp: + return VK_PRIOR; + case Qt::Key_PageDown: + return VK_NEXT; + case Qt::Key_F1: + return VK_F1; + case Qt::Key_F2: + return VK_F2; + case Qt::Key_F3: + return VK_F3; + case Qt::Key_F4: + return VK_F4; + case Qt::Key_F5: + return VK_F5; + case Qt::Key_F6: + return VK_F6; + case Qt::Key_F7: + return VK_F7; + case Qt::Key_F8: + return VK_F8; + case Qt::Key_F9: + return VK_F9; + case Qt::Key_F10: + return VK_F10; + case Qt::Key_F11: + return VK_F11; + case Qt::Key_F12: + return VK_F12; + case Qt::Key_F13: + return VK_F13; + case Qt::Key_F14: + return VK_F14; + case Qt::Key_F15: + return VK_F15; + case Qt::Key_F16: + return VK_F16; + case Qt::Key_F17: + return VK_F17; + case Qt::Key_F18: + return VK_F18; + case Qt::Key_F19: + return VK_F19; + case Qt::Key_F20: + return VK_F20; + case Qt::Key_F21: + return VK_F21; + case Qt::Key_F22: + return VK_F22; + case Qt::Key_F23: + return VK_F23; + case Qt::Key_F24: + return VK_F24; + case Qt::Key_Space: + return VK_SPACE; + case Qt::Key_Asterisk: + return VK_MULTIPLY; + case Qt::Key_Plus: + return VK_ADD; + case Qt::Key_Comma: + return VK_SEPARATOR; + case Qt::Key_Minus: + return VK_SUBTRACT; + case Qt::Key_Slash: + return VK_DIVIDE; + case Qt::Key_MediaNext: + return VK_MEDIA_NEXT_TRACK; + case Qt::Key_MediaPrevious: + return VK_MEDIA_PREV_TRACK; + case Qt::Key_MediaPlay: + return VK_MEDIA_PLAY_PAUSE; + case Qt::Key_MediaStop: + return VK_MEDIA_STOP; + // couldn't find those in VK_* + //case Qt::Key_MediaLast: + //case Qt::Key_MediaRecord: + case Qt::Key_VolumeDown: + return VK_VOLUME_DOWN; + case Qt::Key_VolumeUp: + return VK_VOLUME_UP; + case Qt::Key_VolumeMute: + return VK_VOLUME_MUTE; + + // numbers + case Qt::Key_0: + case Qt::Key_1: + case Qt::Key_2: + case Qt::Key_3: + case Qt::Key_4: + case Qt::Key_5: + case Qt::Key_6: + case Qt::Key_7: + case Qt::Key_8: + case Qt::Key_9: + return key; + + // letters + case Qt::Key_A: + case Qt::Key_B: + case Qt::Key_C: + case Qt::Key_D: + case Qt::Key_E: + case Qt::Key_F: + case Qt::Key_G: + case Qt::Key_H: + case Qt::Key_I: + case Qt::Key_J: + case Qt::Key_K: + case Qt::Key_L: + case Qt::Key_M: + case Qt::Key_N: + case Qt::Key_O: + case Qt::Key_P: + case Qt::Key_Q: + case Qt::Key_R: + case Qt::Key_S: + case Qt::Key_T: + case Qt::Key_U: + case Qt::Key_V: + case Qt::Key_W: + case Qt::Key_X: + case Qt::Key_Y: + case Qt::Key_Z: + return key; + + default: + return 0; + } +} + +bool QxtGlobalShortcutPrivate::registerShortcut(quint32 nativeKey, quint32 nativeMods) +{ + return RegisterHotKey(0, nativeMods ^ nativeKey, nativeMods, nativeKey); +} + +bool QxtGlobalShortcutPrivate::unregisterShortcut(quint32 nativeKey, quint32 nativeMods) +{ + return UnregisterHotKey(0, nativeMods ^ nativeKey); +} diff --git a/3rdparty/qxt/qxtglobalshortcut_x11.cpp b/3rdparty/qxt/qxtglobalshortcut_x11.cpp index c22894dc1..5768a017f 100644 --- a/3rdparty/qxt/qxtglobalshortcut_x11.cpp +++ b/3rdparty/qxt/qxtglobalshortcut_x11.cpp @@ -1,135 +1,242 @@ -/**************************************************************************** - ** - ** Copyright (C) Qxt Foundation. Some rights reserved. - ** - ** This file is part of the QxtGui module of the Qxt library. - ** - ** This library is free software; you can redistribute it and/or modify it - ** under the terms of the Common Public License, version 1.0, as published - ** by IBM, and/or under the terms of the GNU Lesser General Public License, - ** version 2.1, as published by the Free Software Foundation. - ** - ** This file is provided "AS IS", without WARRANTIES OR CONDITIONS OF ANY - ** KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY - ** WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR - ** FITNESS FOR A PARTICULAR PURPOSE. - ** - ** You should have received a copy of the CPL and the LGPL along with this - ** file. See the LICENSE file and the cpl1.0.txt/lgpl-2.1.txt files - ** included with the source distribution for more information. - ** If you did not receive a copy of the licenses, contact the Qxt Foundation. - ** - ** - ** - ****************************************************************************/ -#include "qxtglobalshortcut_p.h" -#include -#include - -#include "keymapper_x11.h" - -static int (*original_x_errhandler)(Display* display, XErrorEvent* event); - -static int qxt_x_errhandler(Display* display, XErrorEvent *event) -{ - Q_UNUSED(display); - switch (event->error_code) - { - case BadAccess: - case BadValue: - case BadWindow: - if (event->request_code == 33 /* X_GrabKey */ || - event->request_code == 34 /* X_UngrabKey */) - { - QxtGlobalShortcutPrivate::error = true; - //TODO: - //char errstr[256]; - //XGetErrorText(dpy, err->error_code, errstr, 256); - } - default: - return 0; - } -} - -bool QxtGlobalShortcutPrivate::eventFilter(void* message) -{ - XEvent* event = static_cast(message); - if (event->type == KeyPress) - { - XKeyEvent* key = (XKeyEvent*) event; - activateShortcut(key->keycode, - // Mod1Mask == Alt, Mod4Mask == Meta - key->state & (ShiftMask | ControlMask | Mod1Mask | Mod4Mask)); - } - return false; -} - -quint32 QxtGlobalShortcutPrivate::nativeModifiers(Qt::KeyboardModifiers modifiers) -{ - // ShiftMask, LockMask, ControlMask, Mod1Mask, Mod2Mask, Mod3Mask, Mod4Mask, and Mod5Mask - quint32 native = 0; - if (modifiers & Qt::ShiftModifier) - native |= ShiftMask; - if (modifiers & Qt::ControlModifier) - native |= ControlMask; - if (modifiers & Qt::AltModifier) - native |= Mod1Mask; - if (modifiers & Qt::MetaModifier) - native |= Mod4Mask; - // TODO: resolve these? - //if (modifiers & Qt::KeypadModifier) - //if (modifiers & Qt::GroupSwitchModifier) - return native; -} - -quint32 QxtGlobalShortcutPrivate::nativeKeycode(Qt::Key key) -{ - // (davidsansome) Try the table from QKeyMapper first - this seems to be - // the only way to get Keysyms for the media keys. - unsigned int keysym = 0; - int i = 0; - while (KeyTbl[i]) { - if (KeyTbl[i+1] == static_cast(key)) { - keysym = KeyTbl[i]; - break; - } - i += 2; - } - - // If that didn't work then fall back on XStringToKeysym - if (!keysym) { - keysym = XStringToKeysym(QKeySequence(key).toString().toLatin1().data()); - } - - Display* display = QX11Info::display(); - return XKeysymToKeycode(display, keysym); -} - -bool QxtGlobalShortcutPrivate::registerShortcut(quint32 nativeKey, quint32 nativeMods) -{ - Display* display = QX11Info::display(); - Window window = QX11Info::appRootWindow(); - Bool owner = True; - int pointer = GrabModeAsync; - int keyboard = GrabModeAsync; - error = false; - original_x_errhandler = XSetErrorHandler(qxt_x_errhandler); - XGrabKey(display, nativeKey, nativeMods, window, owner, pointer, keyboard); - XGrabKey(display, nativeKey, nativeMods | Mod2Mask, window, owner, pointer, keyboard); // allow numlock - XSync(display, False); - XSetErrorHandler(original_x_errhandler); - return !error; -} - -bool QxtGlobalShortcutPrivate::unregisterShortcut(quint32 nativeKey, quint32 nativeMods) -{ - Display* display = QX11Info::display(); - Window window = QX11Info::appRootWindow(); - error = false; - original_x_errhandler = XSetErrorHandler(qxt_x_errhandler); - XUngrabKey(display, nativeKey, nativeMods, window); - XUngrabKey(display, nativeKey, nativeMods | Mod2Mask, window); // allow numlock - XSync(display, False); - XSetErrorHandler(original_x_errhandler); - return !error; -} +#include "qxtglobalshortcut_p.h" +/**************************************************************************** +** Copyright (c) 2006 - 2011, the LibQxt project. +** See the Qxt AUTHORS file for a list of authors and copyright holders. +** All rights reserved. +** +** 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 LibQxt project 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 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. +** +** +*****************************************************************************/ + +#include +#include +#include +#include +#include "keymapper_x11.h" + +namespace { + +const QVector maskModifiers = QVector() + << 0 << Mod2Mask << LockMask << (Mod2Mask | LockMask); + +typedef int (*X11ErrorHandler)(Display *display, XErrorEvent *event); + +class QxtX11ErrorHandler { +public: + static bool error; + + static int qxtX11ErrorHandler(Display *display, XErrorEvent *event) + { + Q_UNUSED(display); + switch (event->error_code) + { + case BadAccess: + case BadValue: + case BadWindow: + if (event->request_code == 33 /* X_GrabKey */ || + event->request_code == 34 /* X_UngrabKey */) + { + error = true; + //TODO: + //char errstr[256]; + //XGetErrorText(dpy, err->error_code, errstr, 256); + } + } + return 0; + } + + QxtX11ErrorHandler() + { + error = false; + m_previousErrorHandler = XSetErrorHandler(qxtX11ErrorHandler); + } + + ~QxtX11ErrorHandler() + { + XSetErrorHandler(m_previousErrorHandler); + } + +private: + X11ErrorHandler m_previousErrorHandler; +}; + +bool QxtX11ErrorHandler::error = false; + +class QxtX11Data { +public: + QxtX11Data() + { + m_display = QX11Info::display(); + } + + bool isValid() + { + return m_display != 0; + } + + Display *display() + { + Q_ASSERT(isValid()); + return m_display; + } + + Window rootWindow() + { + return DefaultRootWindow(display()); + } + + bool grabKey(quint32 keycode, quint32 modifiers, Window window) + { + QxtX11ErrorHandler errorHandler; + + for (int i = 0; !errorHandler.error && i < maskModifiers.size(); ++i) { + XGrabKey(display(), keycode, modifiers | maskModifiers[i], window, True, + GrabModeAsync, GrabModeAsync); + } + + if (errorHandler.error) { + ungrabKey(keycode, modifiers, window); + return false; + } + + return true; + } + + bool ungrabKey(quint32 keycode, quint32 modifiers, Window window) + { + QxtX11ErrorHandler errorHandler; + + foreach (quint32 maskMods, maskModifiers) { + XUngrabKey(display(), keycode, modifiers | maskMods, window); + } + + return !errorHandler.error; + } + +private: + Display *m_display; +}; + +} // namespace + +#if QT_VERSION < QT_VERSION_CHECK(5,0,0) +bool QxtGlobalShortcutPrivate::eventFilter(void *message) +{ + XEvent *event = static_cast(message); + if (event->type == KeyPress) + { + XKeyEvent *key = reinterpret_cast(event); + unsigned int keycode = key->keycode; + unsigned int keystate = key->state; +#else +bool QxtGlobalShortcutPrivate::nativeEventFilter(const QByteArray & eventType, + void *message, long *result) +{ + Q_UNUSED(result); + + xcb_key_press_event_t *kev = 0; + if (eventType == "xcb_generic_event_t") { + xcb_generic_event_t *ev = static_cast(message); + if ((ev->response_type & 127) == XCB_KEY_PRESS) + kev = static_cast(message); + } + + if (kev != 0) { + unsigned int keycode = kev->detail; + unsigned int keystate = 0; + if(kev->state & XCB_MOD_MASK_1) + keystate |= Mod1Mask; + if(kev->state & XCB_MOD_MASK_CONTROL) + keystate |= ControlMask; + if(kev->state & XCB_MOD_MASK_4) + keystate |= Mod4Mask; + if(kev->state & XCB_MOD_MASK_SHIFT) + keystate |= ShiftMask; +#endif + activateShortcut(keycode, + // Mod1Mask == Alt, Mod4Mask == Meta + keystate & (ShiftMask | ControlMask | Mod1Mask | Mod4Mask)); + } + return false; +} + +quint32 QxtGlobalShortcutPrivate::nativeModifiers(Qt::KeyboardModifiers modifiers) +{ + // ShiftMask, LockMask, ControlMask, Mod1Mask, Mod2Mask, Mod3Mask, Mod4Mask, and Mod5Mask + quint32 native = 0; + if (modifiers & Qt::ShiftModifier) + native |= ShiftMask; + if (modifiers & Qt::ControlModifier) + native |= ControlMask; + if (modifiers & Qt::AltModifier) + native |= Mod1Mask; + if (modifiers & Qt::MetaModifier) + native |= Mod4Mask; + + // TODO: resolve these? + //if (modifiers & Qt::MetaModifier) + //if (modifiers & Qt::KeypadModifier) + //if (modifiers & Qt::GroupSwitchModifier) + return native; +} + +quint32 QxtGlobalShortcutPrivate::nativeKeycode(Qt::Key key) +{ + // (davidsansome) Try the table from QKeyMapper first - this seems to be + // the only way to get Keysyms for the media keys. + unsigned int keysym = 0; + int i = 0; + while (KeyTbl[i]) { + if (KeyTbl[i+1] == static_cast(key)) { + keysym = KeyTbl[i]; + break; + } + i += 2; + } + + // If that didn't work then fall back on XStringToKeysym + if (!keysym) { + keysym = XStringToKeysym(QKeySequence(key).toString().toLatin1().data()); + if (keysym == NoSymbol) + keysym = static_cast(key); + } + + QxtX11Data x11; + if (!x11.isValid()) + return 0; + + return XKeysymToKeycode(x11.display(), keysym); +} + +bool QxtGlobalShortcutPrivate::registerShortcut(quint32 nativeKey, quint32 nativeMods) +{ + QxtX11Data x11; + return x11.isValid() && x11.grabKey(nativeKey, nativeMods, x11.rootWindow()); +} + +bool QxtGlobalShortcutPrivate::unregisterShortcut(quint32 nativeKey, quint32 nativeMods) +{ + QxtX11Data x11; + return x11.isValid() && x11.ungrabKey(nativeKey, nativeMods, x11.rootWindow()); +} diff --git a/3rdparty/sha2/CMakeLists.txt b/3rdparty/sha2/CMakeLists.txt deleted file mode 100644 index 3a5da0a2f..000000000 --- a/3rdparty/sha2/CMakeLists.txt +++ /dev/null @@ -1,3 +0,0 @@ -cmake_minimum_required(VERSION 2.6) - -add_library(sha2 STATIC sha2.cpp) diff --git a/3rdparty/sha2/sha2.cpp b/3rdparty/sha2/sha2.cpp deleted file mode 100644 index caeed14cf..000000000 --- a/3rdparty/sha2/sha2.cpp +++ /dev/null @@ -1,588 +0,0 @@ -/* - * FILE: sha2.c - * AUTHOR: Aaron D. Gifford - http://www.aarongifford.com/ - * - * Copyright (c) 2000-2001, Aaron D. Gifford - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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. - * 3. Neither the name of the copyright holder nor the names of contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTOR(S) ``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 AUTHOR OR CONTRIBUTOR(S) 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. - * - */ - -#include /* memcpy()/memset() or bcopy()/bzero() */ -#include /* assert() */ -#include "sha2.h" - -/* - * ASSERT NOTE: - * Some sanity checking code is included using assert(). On my FreeBSD - * system, this additional code can be removed by compiling with NDEBUG - * defined. Check your own systems manpage on assert() to see how to - * compile WITHOUT the sanity checking code on your system. - * - * UNROLLED TRANSFORM LOOP NOTE: - * You can define SHA2_UNROLL_TRANSFORM to use the unrolled transform - * loop version for the hash transform rounds (defined using macros - * later in this file). Either define on the command line, for example: - * - * cc -DSHA2_UNROLL_TRANSFORM -o sha2 sha2.c sha2prog.c - * - * or define below: - * - * #define SHA2_UNROLL_TRANSFORM - * - */ - - -/*** SHA-256/384/512 Machine Architecture Definitions *****************/ -/* - * BYTE_ORDER NOTE: - * - * Please make sure that your system defines BYTE_ORDER. If your - * architecture is little-endian, make sure it also defines - * LITTLE_ENDIAN and that the two (BYTE_ORDER and LITTLE_ENDIAN) are - * equivilent. - * - * If your system does not define the above, then you can do so by - * hand like this: - * - * #define LITTLE_ENDIAN 1234 - * #define BIG_ENDIAN 4321 - * - * And for little-endian machines, add: - * - * #define BYTE_ORDER LITTLE_ENDIAN - * - * Or for big-endian machines: - * - * #define BYTE_ORDER BIG_ENDIAN - * - * The FreeBSD machine this was written on defines BYTE_ORDER - * appropriately by including (which in turn includes - * where the appropriate definitions are actually - * made). - */ -#ifdef __MINGW32__ -#include -#endif - -#if !defined(BYTE_ORDER) || (BYTE_ORDER != LITTLE_ENDIAN && BYTE_ORDER != BIG_ENDIAN) -#error Define BYTE_ORDER to be equal to either LITTLE_ENDIAN or BIG_ENDIAN -#endif - -namespace clementine_sha2 { - -/* - * Define the followingsha2_* types to types of the correct length on - * the native archtecture. Most BSD systems and Linux define u_intXX_t - * types. Machines with very recent ANSI C headers, can use the - * uintXX_t definintions from inttypes.h by defining SHA2_USE_INTTYPES_H - * during compile or in the sha.h header file. - * - * Machines that support neither u_intXX_t nor inttypes.h's uintXX_t - * will need to define these three typedefs below (and the appropriate - * ones in sha.h too) by hand according to their system architecture. - * - * Thank you, Jun-ichiro itojun Hagino, for suggesting using u_intXX_t - * types and pointing out recent ANSI C support for uintXX_t in inttypes.h. - */ -#ifdef SHA2_USE_INTTYPES_H - -typedef uint8_t sha2_byte; /* Exactly 1 byte */ -typedef uint32_t sha2_word32; /* Exactly 4 bytes */ -typedef uint64_t sha2_word64; /* Exactly 8 bytes */ - -#else /* SHA2_USE_INTTYPES_H */ - -typedef u_int8_t sha2_byte; /* Exactly 1 byte */ -typedef u_int32_t sha2_word32; /* Exactly 4 bytes */ -typedef u_int64_t sha2_word64; /* Exactly 8 bytes */ - -#endif /* SHA2_USE_INTTYPES_H */ - - -/*** SHA-256/384/512 Various Length Definitions ***********************/ -/* NOTE: Most of these are in sha2.h */ -#define SHA256_SHORT_BLOCK_LENGTH (SHA256_BLOCK_LENGTH - 8) - - -/*** ENDIAN REVERSAL MACROS *******************************************/ -#if BYTE_ORDER == LITTLE_ENDIAN -#define REVERSE32(w,x) { \ - sha2_word32 tmp = (w); \ - tmp = (tmp >> 16) | (tmp << 16); \ - (x) = ((tmp & 0xff00ff00UL) >> 8) | ((tmp & 0x00ff00ffUL) << 8); \ -} -#define REVERSE64(w,x) { \ - sha2_word64 tmp = (w); \ - tmp = (tmp >> 32) | (tmp << 32); \ - tmp = ((tmp & 0xff00ff00ff00ff00ULL) >> 8) | \ - ((tmp & 0x00ff00ff00ff00ffULL) << 8); \ - (x) = ((tmp & 0xffff0000ffff0000ULL) >> 16) | \ - ((tmp & 0x0000ffff0000ffffULL) << 16); \ -} -#endif /* BYTE_ORDER == LITTLE_ENDIAN */ - -/* - * Macro for incrementally adding the unsigned 64-bit integer n to the - * unsigned 128-bit integer (represented using a two-element array of - * 64-bit words): - */ -#define ADDINC128(w,n) { \ - (w)[0] += (sha2_word64)(n); \ - if ((w)[0] < (n)) { \ - (w)[1]++; \ - } \ -} - -/* - * Macros for copying blocks of memory and for zeroing out ranges - * of memory. Using these macros makes it easy to switch from - * using memset()/memcpy() and using bzero()/bcopy(). - * - * Please define either SHA2_USE_MEMSET_MEMCPY or define - * SHA2_USE_BZERO_BCOPY depending on which function set you - * choose to use: - */ -#if !defined(SHA2_USE_MEMSET_MEMCPY) && !defined(SHA2_USE_BZERO_BCOPY) -/* Default to memset()/memcpy() if no option is specified */ -#define SHA2_USE_MEMSET_MEMCPY 1 -#endif -#if defined(SHA2_USE_MEMSET_MEMCPY) && defined(SHA2_USE_BZERO_BCOPY) -/* Abort with an error if BOTH options are defined */ -#error Define either SHA2_USE_MEMSET_MEMCPY or SHA2_USE_BZERO_BCOPY, not both! -#endif - -#ifdef SHA2_USE_MEMSET_MEMCPY -#define MEMSET_BZERO(p,l) memset((p), 0, (l)) -#define MEMCPY_BCOPY(d,s,l) memcpy((d), (s), (l)) -#endif -#ifdef SHA2_USE_BZERO_BCOPY -#define MEMSET_BZERO(p,l) bzero((p), (l)) -#define MEMCPY_BCOPY(d,s,l) bcopy((s), (d), (l)) -#endif - - -/*** THE SIX LOGICAL FUNCTIONS ****************************************/ -/* - * Bit shifting and rotation (used by the six SHA-XYZ logical functions: - * - * NOTE: The naming of R and S appears backwards here (R is a SHIFT and - * S is a ROTATION) because the SHA-256/384/512 description document - * (see http://csrc.nist.gov/cryptval/shs/sha256-384-512.pdf) uses this - * same "backwards" definition. - */ -/* Shift-right (used in SHA-256, SHA-384, and SHA-512): */ -#define R(b,x) ((x) >> (b)) -/* 32-bit Rotate-right (used in SHA-256): */ -#define S32(b,x) (((x) >> (b)) | ((x) << (32 - (b)))) - -/* Two of six logical functions used in SHA-256, SHA-384, and SHA-512: */ -#define Ch(x,y,z) (((x) & (y)) ^ ((~(x)) & (z))) -#define Maj(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) - -/* Four of six logical functions used in SHA-256: */ -#define Sigma0_256(x) (S32(2, (x)) ^ S32(13, (x)) ^ S32(22, (x))) -#define Sigma1_256(x) (S32(6, (x)) ^ S32(11, (x)) ^ S32(25, (x))) -#define sigma0_256(x) (S32(7, (x)) ^ S32(18, (x)) ^ R(3 , (x))) -#define sigma1_256(x) (S32(17, (x)) ^ S32(19, (x)) ^ R(10, (x))) - -/*** INTERNAL FUNCTION PROTOTYPES *************************************/ -/* NOTE: These should not be accessed directly from outside this - * library -- they are intended for private internal visibility/use - * only. - */ -void SHA256_Transform(SHA256_CTX*, const sha2_word32*); - - -/*** SHA-XYZ INITIAL HASH VALUES AND CONSTANTS ************************/ -/* Hash constant words K for SHA-256: */ -const static sha2_word32 K256[64] = { - 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, - 0x3956c25bUL, 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, - 0xd807aa98UL, 0x12835b01UL, 0x243185beUL, 0x550c7dc3UL, - 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, 0xc19bf174UL, - 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL, - 0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, - 0x983e5152UL, 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, - 0xc6e00bf3UL, 0xd5a79147UL, 0x06ca6351UL, 0x14292967UL, - 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, 0x53380d13UL, - 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL, - 0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, - 0xd192e819UL, 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, - 0x19a4c116UL, 0x1e376c08UL, 0x2748774cUL, 0x34b0bcb5UL, - 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, 0x682e6ff3UL, - 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL, - 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL -}; - -/* Initial hash value H for SHA-256: */ -const static sha2_word32 sha256_initial_hash_value[8] = { - 0x6a09e667UL, - 0xbb67ae85UL, - 0x3c6ef372UL, - 0xa54ff53aUL, - 0x510e527fUL, - 0x9b05688cUL, - 0x1f83d9abUL, - 0x5be0cd19UL -}; - - -/* - * Constant used by SHA256/384/512_End() functions for converting the - * digest to a readable hexadecimal character string: - */ -static const char *sha2_hex_digits = "0123456789abcdef"; - - -/*** SHA-256: *********************************************************/ -void SHA256_Init(SHA256_CTX* context) { - if (context == (SHA256_CTX*)0) { - return; - } - MEMCPY_BCOPY(context->state, sha256_initial_hash_value, SHA256_DIGEST_LENGTH); - MEMSET_BZERO(context->buffer, SHA256_BLOCK_LENGTH); - context->bitcount = 0; -} - -#ifdef SHA2_UNROLL_TRANSFORM - -/* Unrolled SHA-256 round macros: */ - -#if BYTE_ORDER == LITTLE_ENDIAN - -#define ROUND256_0_TO_15(a,b,c,d,e,f,g,h) \ - REVERSE32(*data++, W256[j]); \ - T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + \ - K256[j] + W256[j]; \ - (d) += T1; \ - (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \ - j++ - - -#else /* BYTE_ORDER == LITTLE_ENDIAN */ - -#define ROUND256_0_TO_15(a,b,c,d,e,f,g,h) \ - T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + \ - K256[j] + (W256[j] = *data++); \ - (d) += T1; \ - (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \ - j++ - -#endif /* BYTE_ORDER == LITTLE_ENDIAN */ - -#define ROUND256(a,b,c,d,e,f,g,h) \ - s0 = W256[(j+1)&0x0f]; \ - s0 = sigma0_256(s0); \ - s1 = W256[(j+14)&0x0f]; \ - s1 = sigma1_256(s1); \ - T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + K256[j] + \ - (W256[j&0x0f] += s1 + W256[(j+9)&0x0f] + s0); \ - (d) += T1; \ - (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \ - j++ - -void SHA256_Transform(SHA256_CTX* context, const sha2_word32* data) { - sha2_word32 a, b, c, d, e, f, g, h, s0, s1; - sha2_word32 T1, *W256; - int j; - - W256 = (sha2_word32*)context->buffer; - - /* Initialize registers with the prev. intermediate value */ - a = context->state[0]; - b = context->state[1]; - c = context->state[2]; - d = context->state[3]; - e = context->state[4]; - f = context->state[5]; - g = context->state[6]; - h = context->state[7]; - - j = 0; - do { - /* Rounds 0 to 15 (unrolled): */ - ROUND256_0_TO_15(a,b,c,d,e,f,g,h); - ROUND256_0_TO_15(h,a,b,c,d,e,f,g); - ROUND256_0_TO_15(g,h,a,b,c,d,e,f); - ROUND256_0_TO_15(f,g,h,a,b,c,d,e); - ROUND256_0_TO_15(e,f,g,h,a,b,c,d); - ROUND256_0_TO_15(d,e,f,g,h,a,b,c); - ROUND256_0_TO_15(c,d,e,f,g,h,a,b); - ROUND256_0_TO_15(b,c,d,e,f,g,h,a); - } while (j < 16); - - /* Now for the remaining rounds to 64: */ - do { - ROUND256(a,b,c,d,e,f,g,h); - ROUND256(h,a,b,c,d,e,f,g); - ROUND256(g,h,a,b,c,d,e,f); - ROUND256(f,g,h,a,b,c,d,e); - ROUND256(e,f,g,h,a,b,c,d); - ROUND256(d,e,f,g,h,a,b,c); - ROUND256(c,d,e,f,g,h,a,b); - ROUND256(b,c,d,e,f,g,h,a); - } while (j < 64); - - /* Compute the current intermediate hash value */ - context->state[0] += a; - context->state[1] += b; - context->state[2] += c; - context->state[3] += d; - context->state[4] += e; - context->state[5] += f; - context->state[6] += g; - context->state[7] += h; - - /* Clean up */ - a = b = c = d = e = f = g = h = T1 = 0; -} - -#else /* SHA2_UNROLL_TRANSFORM */ - -void SHA256_Transform(SHA256_CTX* context, const sha2_word32* data) { - sha2_word32 a, b, c, d, e, f, g, h, s0, s1; - sha2_word32 T1, T2, *W256; - int j; - - W256 = (sha2_word32*)context->buffer; - - /* Initialize registers with the prev. intermediate value */ - a = context->state[0]; - b = context->state[1]; - c = context->state[2]; - d = context->state[3]; - e = context->state[4]; - f = context->state[5]; - g = context->state[6]; - h = context->state[7]; - - j = 0; - do { -#if BYTE_ORDER == LITTLE_ENDIAN - /* Copy data while converting to host byte order */ - REVERSE32(*data++,W256[j]); - /* Apply the SHA-256 compression function to update a..h */ - T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + W256[j]; -#else /* BYTE_ORDER == LITTLE_ENDIAN */ - /* Apply the SHA-256 compression function to update a..h with copy */ - T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + (W256[j] = *data++); -#endif /* BYTE_ORDER == LITTLE_ENDIAN */ - T2 = Sigma0_256(a) + Maj(a, b, c); - h = g; - g = f; - f = e; - e = d + T1; - d = c; - c = b; - b = a; - a = T1 + T2; - - j++; - } while (j < 16); - - do { - /* Part of the message block expansion: */ - s0 = W256[(j+1)&0x0f]; - s0 = sigma0_256(s0); - s1 = W256[(j+14)&0x0f]; - s1 = sigma1_256(s1); - - /* Apply the SHA-256 compression function to update a..h */ - T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + - (W256[j&0x0f] += s1 + W256[(j+9)&0x0f] + s0); - T2 = Sigma0_256(a) + Maj(a, b, c); - h = g; - g = f; - f = e; - e = d + T1; - d = c; - c = b; - b = a; - a = T1 + T2; - - j++; - } while (j < 64); - - /* Compute the current intermediate hash value */ - context->state[0] += a; - context->state[1] += b; - context->state[2] += c; - context->state[3] += d; - context->state[4] += e; - context->state[5] += f; - context->state[6] += g; - context->state[7] += h; - - /* Clean up */ - a = b = c = d = e = f = g = h = T1 = T2 = 0; -} - -#endif /* SHA2_UNROLL_TRANSFORM */ - -void SHA256_Update(SHA256_CTX* context, const sha2_byte *data, size_t len) { - unsigned int freespace, usedspace; - - if (len == 0) { - /* Calling with no data is valid - we do nothing */ - return; - } - - /* Sanity check: */ - assert(context != (SHA256_CTX*)0 && data != (sha2_byte*)0); - - usedspace = (context->bitcount >> 3) % SHA256_BLOCK_LENGTH; - if (usedspace > 0) { - /* Calculate how much free space is available in the buffer */ - freespace = SHA256_BLOCK_LENGTH - usedspace; - - if (len >= freespace) { - /* Fill the buffer completely and process it */ - MEMCPY_BCOPY(&context->buffer[usedspace], data, freespace); - context->bitcount += freespace << 3; - len -= freespace; - data += freespace; - SHA256_Transform(context, (sha2_word32*)context->buffer); - } else { - /* The buffer is not yet full */ - MEMCPY_BCOPY(&context->buffer[usedspace], data, len); - context->bitcount += len << 3; - /* Clean up: */ - usedspace = freespace = 0; - return; - } - } - while (len >= SHA256_BLOCK_LENGTH) { - /* Process as many complete blocks as we can */ - SHA256_Transform(context, (sha2_word32*)data); - context->bitcount += SHA256_BLOCK_LENGTH << 3; - len -= SHA256_BLOCK_LENGTH; - data += SHA256_BLOCK_LENGTH; - } - if (len > 0) { - /* There's left-overs, so save 'em */ - MEMCPY_BCOPY(context->buffer, data, len); - context->bitcount += len << 3; - } - /* Clean up: */ - usedspace = freespace = 0; -} - -void SHA256_Final(sha2_byte digest[], SHA256_CTX* context) { - sha2_word32 *d = (sha2_word32*)digest; - unsigned int usedspace; - - /* Sanity check: */ - assert(context != (SHA256_CTX*)0); - - /* If no digest buffer is passed, we don't bother doing this: */ - if (digest != (sha2_byte*)0) { - usedspace = (context->bitcount >> 3) % SHA256_BLOCK_LENGTH; -#if BYTE_ORDER == LITTLE_ENDIAN - /* Convert FROM host byte order */ - REVERSE64(context->bitcount,context->bitcount); -#endif - if (usedspace > 0) { - /* Begin padding with a 1 bit: */ - context->buffer[usedspace++] = 0x80; - - if (usedspace <= SHA256_SHORT_BLOCK_LENGTH) { - /* Set-up for the last transform: */ - MEMSET_BZERO(&context->buffer[usedspace], SHA256_SHORT_BLOCK_LENGTH - usedspace); - } else { - if (usedspace < SHA256_BLOCK_LENGTH) { - MEMSET_BZERO(&context->buffer[usedspace], SHA256_BLOCK_LENGTH - usedspace); - } - /* Do second-to-last transform: */ - SHA256_Transform(context, (sha2_word32*)context->buffer); - - /* And set-up for the last transform: */ - MEMSET_BZERO(context->buffer, SHA256_SHORT_BLOCK_LENGTH); - } - } else { - /* Set-up for the last transform: */ - MEMSET_BZERO(context->buffer, SHA256_SHORT_BLOCK_LENGTH); - - /* Begin padding with a 1 bit: */ - *context->buffer = 0x80; - } - /* Set the bit count: */ - *(sha2_word64*)&context->buffer[SHA256_SHORT_BLOCK_LENGTH] = context->bitcount; - - /* Final transform: */ - SHA256_Transform(context, (sha2_word32*)context->buffer); - -#if BYTE_ORDER == LITTLE_ENDIAN - { - /* Convert TO host byte order */ - int j; - for (j = 0; j < 8; j++) { - REVERSE32(context->state[j],context->state[j]); - *d++ = context->state[j]; - } - } -#else - MEMCPY_BCOPY(d, context->state, SHA256_DIGEST_LENGTH); -#endif - } - - /* Clean up state data: */ - MEMSET_BZERO(context, sizeof(SHA256_CTX)); - usedspace = 0; -} - -char *SHA256_End(SHA256_CTX* context, char buffer[]) { - sha2_byte digest[SHA256_DIGEST_LENGTH], *d = digest; - int i; - - /* Sanity check: */ - assert(context != (SHA256_CTX*)0); - - if (buffer != (char*)0) { - SHA256_Final(digest, context); - - for (i = 0; i < SHA256_DIGEST_LENGTH; i++) { - *buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4]; - *buffer++ = sha2_hex_digits[*d & 0x0f]; - d++; - } - *buffer = (char)0; - } else { - MEMSET_BZERO(context, sizeof(SHA256_CTX)); - } - MEMSET_BZERO(digest, SHA256_DIGEST_LENGTH); - return buffer; -} - -char* SHA256_Data(const sha2_byte* data, size_t len, char digest[SHA256_DIGEST_STRING_LENGTH]) { - SHA256_CTX context; - - SHA256_Init(&context); - SHA256_Update(&context, data, len); - return SHA256_End(&context, digest); -} - -} // namespace clementine_sha2 diff --git a/3rdparty/sha2/sha2.h b/3rdparty/sha2/sha2.h deleted file mode 100644 index 836da77f6..000000000 --- a/3rdparty/sha2/sha2.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - * FILE: sha2.h - * AUTHOR: Aaron D. Gifford - http://www.aarongifford.com/ - * - * Copyright (c) 2000-2001, Aaron D. Gifford - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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. - * 3. Neither the name of the copyright holder nor the names of contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTOR(S) ``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 AUTHOR OR CONTRIBUTOR(S) 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. - * - * $Id: sha2.h,v 1.1 2001/11/08 00:02:01 adg Exp adg $ - */ - -#ifndef __CLEMENTINE_SHA2_H__ -#define __CLEMENTINE_SHA2_H__ - -/* - * Import u_intXX_t size_t type definitions from system headers. You - * may need to change this, or define these things yourself in this - * file. - */ -#include - -namespace clementine_sha2 { - -/*** SHA-256/384/512 Various Length Definitions ***********************/ -static const int SHA256_BLOCK_LENGTH = 64; -static const int SHA256_DIGEST_LENGTH = 32; -static const int SHA256_DIGEST_STRING_LENGTH = (SHA256_DIGEST_LENGTH * 2 + 1); - - -/*** SHA-256/384/512 Context Structures *******************************/ -/* NOTE: If your architecture does not define either u_intXX_t types or - * uintXX_t (from inttypes.h), you may need to define things by hand - * for your system: - */ -#ifdef __MINGW32__ -typedef unsigned char u_int8_t; /* 1-byte (8-bits) */ -typedef unsigned int u_int32_t; /* 4-bytes (32-bits) */ -typedef unsigned long long u_int64_t; /* 8-bytes (64-bits) */ -#endif - -typedef struct _SHA256_CTX { - u_int32_t state[8]; - u_int64_t bitcount; - u_int8_t buffer[SHA256_BLOCK_LENGTH]; -} SHA256_CTX; - - -void SHA256_Init(SHA256_CTX *); -void SHA256_Update(SHA256_CTX*, const u_int8_t*, size_t); -void SHA256_Final(u_int8_t[SHA256_DIGEST_LENGTH], SHA256_CTX*); -char* SHA256_End(SHA256_CTX*, char[SHA256_DIGEST_STRING_LENGTH]); -char* SHA256_Data(const u_int8_t*, size_t, char[SHA256_DIGEST_STRING_LENGTH]); - -} // namespace clementine_sha2 - -#endif /* __CLEMENTINE_SHA2_H__ */ diff --git a/3rdparty/tinysvcmdns/CMakeLists.txt b/3rdparty/tinysvcmdns/CMakeLists.txt index 1c16a138a..50dd1f573 100644 --- a/3rdparty/tinysvcmdns/CMakeLists.txt +++ b/3rdparty/tinysvcmdns/CMakeLists.txt @@ -7,7 +7,7 @@ set(TINYSVCMDNS-SOURCES ) find_library(PTHREAD - pthreadGC2 + pthread ) add_library(tinysvcmdns STATIC diff --git a/CMakeLists.txt b/CMakeLists.txt index 3bbb47012..cd772ac6b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,6 @@ -cmake_minimum_required(VERSION 2.6) +cmake_minimum_required(VERSION 2.8.11) cmake_policy(SET CMP0011 OLD) +cmake_policy(SET CMP0053 OLD) include(CheckCXXCompilerFlag) include(FindPkgConfig) @@ -46,7 +47,6 @@ find_package(PkgConfig REQUIRED) find_package(Protobuf REQUIRED) find_package(FFTW3) find_package(ALSA) -pkg_check_modules(DBUS dbus-1) if (NOT APPLE) find_package(X11) endif() @@ -70,39 +70,58 @@ pkg_check_modules(GSTREAMER_TAG REQUIRED gstreamer-tag-1.0) pkg_check_modules(GSTREAMER_PBUTILS REQUIRED gstreamer-pbutils-1.0) pkg_check_modules(LIBGPOD libgpod-1.0>=0.7.92) pkg_check_modules(LIBMTP libmtp>=1.0) -pkg_check_modules(LIBMYGPO_QT libmygpo-qt>=1.0.9) +pkg_check_modules(LIBMYGPO_QT5 libmygpo-qt5>=1.0.9) pkg_check_modules(LIBPULSE libpulse) pkg_check_modules(LIBXML libxml-2.0) -pkg_check_modules(QJSON REQUIRED QJson) pkg_check_modules(LIBSPOTIFY libspotify>=12.1.45) pkg_check_modules(TAGLIB taglib) if (WIN32) find_package(ZLIB REQUIRED) - find_library(QTSPARKLE_LIBRARIES qtsparkle) + find_library(QTSPARKLE_LIBRARIES qtsparkle-qt5) endif (WIN32) -find_library(LASTFM_LIBRARIES lastfm) -find_path(LASTFM_INCLUDE_DIRS lastfm/ws.h) -find_path(LASTFM1_INCLUDE_DIRS lastfm/Track.h) +find_library(LASTFM5_LIBRARIES lastfm5) +find_path(LASTFM5_INCLUDE_DIRS lastfm5/ws.h) +find_path(LASTFM51_INCLUDE_DIRS lastfm5/Track.h) find_path(SPARSEHASH_INCLUDE_DIRS google/sparsetable) # QT -find_package(Qt4 4.8.1 REQUIRED QtCore QtGui QtSql QtNetwork QtXml) -if (DBUS_FOUND) - find_package(Qt4 REQUIRED QtDbus) -endif () -if (OPENGL_FOUND) - find_package(Qt4 REQUIRED QtOpenGL) -endif(OPENGL_FOUND) +set(QT_MIN_VERSION 5.6.0) +find_package(Qt5 ${QT_MIN_VERSION} REQUIRED COMPONENTS Core Concurrent Widgets Network Sql Xml OpenGL Test) +find_package(Qt5DBus ${QT_MIN_VERSION}) +if(HAVE_X11) + find_package(Qt5 ${QT_MIN_VERSION} REQUIRED COMPONENTS X11Extras) +endif() +if(APPLE) + find_package(Qt5 REQUIRED COMPONENTS MacExtras) +endif() +if(WIN32) + find_package(Qt5 REQUIRED COMPONENTS WinExtras) +endif() -# We can include the Qt definitions now -include(${QT_USE_FILE}) +set(QT_LIBRARIES Qt5::Core Qt5::Concurrent Qt5::Widgets Qt5::Network Qt5::Sql Qt5::Xml Qt5::OpenGL) + +if(Qt5DBus_FOUND) + set(QT_LIBRARIES ${QT_LIBRARIES} Qt5::DBus) + get_target_property(QT_DBUSXML2CPP_EXECUTABLE Qt5::qdbusxml2cpp LOCATION) +endif() +if(HAVE_X11) + set(QT_LIBRARIES ${QT_LIBRARIES} Qt5::X11Extras) +endif() +if(APPLE) + set(QT_LIBRARIES ${QT_LIBRARIES} Qt5::MacExtras) +endif() +if(WIN32) + set(QT_LIBRARIES ${QT_LIBRARIES} Qt5::WinExtras) +endif() + +find_package(Qt5LinguistTools CONFIG) +if (Qt5LinguistTools_FOUND) + set(QT_LCONVERT_EXECUTABLE Qt5::lconvert) +endif() -# Find Qt's lconvert binary. Try qt's binary dir first, fall back to looking in PATH -find_program(QT_LCONVERT_EXECUTABLE NAMES lconvert lconvert-qt4 PATHS ${QT_BINARY_DIR} NO_DEFAULT_PATH) -find_program(QT_LCONVERT_EXECUTABLE NAMES lconvert lconvert-qt4) # Only use system taglib if it's greater than 1.11.1 # There is a bug in version 1.11.1 corrupting Ogg files, see: https://github.com/taglib/taglib/issues/864 @@ -140,7 +159,7 @@ else() add_subdirectory(3rdparty/taglib) endif() -if(LASTFM_INCLUDE_DIRS AND LASTFM1_INCLUDE_DIRS) +if(LASTFM5_INCLUDE_DIRS AND LASTFM51_INCLUDE_DIRS) set(HAVE_LIBLASTFM1 ON) endif() @@ -163,17 +182,16 @@ find_package(Threads) if(${CMAKE_BUILD_TYPE} MATCHES "Release") add_definitions(-DNDEBUG) add_definitions(-DQT_NO_DEBUG_OUTPUT) + add_definitions(-DQT_NO_WARNING_OUTPUT) endif(${CMAKE_BUILD_TYPE} MATCHES "Release") # Set up definitions and paths add_definitions(${QT_DEFINITIONS}) link_directories(${TAGLIB_LIBRARY_DIRS}) -link_directories(${QJSON_LIBRARY_DIRS}) link_directories(${GSTREAMER_LIBRARY_DIRS}) include_directories(${Boost_INCLUDE_DIRS}) include_directories(${TAGLIB_INCLUDE_DIRS}) -include_directories(${QJSON_INCLUDE_DIRS}) include_directories(${GSTREAMER_INCLUDE_DIRS}) include_directories(${GSTREAMER_APP_INCLUDE_DIRS}) include_directories(${GSTREAMER_AUDIO_INCLUDE_DIRS}) @@ -257,23 +275,23 @@ optional_component(LIBMTP ON "Devices: MTP support" ) optional_component(LIBLASTFM ON "Last.fm support" - DEPENDS "liblastfm" LASTFM_LIBRARIES LASTFM_INCLUDE_DIRS + DEPENDS "liblastfm" LASTFM5_LIBRARIES LASTFM5_INCLUDE_DIRS ) optional_component(DBUS ON "D-Bus support" - DEPENDS "D-Bus" DBUS_FOUND + DEPENDS "Qt5DBus" Qt5DBus_FOUND ) optional_component(WIIMOTEDEV ON "Wiimote support" - DEPENDS "D-Bus support" DBUS_FOUND + DEPENDS "D-Bus support" Qt5DBus_FOUND ) optional_component(DEVICEKIT ON "Devices: DeviceKit backend" - DEPENDS "D-Bus support" DBUS_FOUND + DEPENDS "D-Bus support" Qt5DBus_FOUND ) optional_component(UDISKS2 ON "Devices: UDisks2 backend" - DEPENDS "D-Bus support" DBUS_FOUND + DEPENDS "D-Bus support" Qt5DBus_FOUND ) optional_component(SPOTIFY_BLOB ON "Spotify support: non-GPL binary helper" @@ -312,7 +330,7 @@ optional_component(VISUALISATIONS ON "Visualisations" optional_component(TRANSLATIONS ON "Translations" DEPENDS "gettext" GETTEXT_XGETTEXT_EXECUTABLE - DEPENDS "lconvert" QT_LCONVERT_EXECUTABLE + DEPENDS "Qt5LinguistTools" Qt5LinguistTools_FOUND ) option(USE_BUNDLE "Bundle macos/windows dependencies" ON) @@ -359,9 +377,9 @@ include_directories("3rdparty/qsqlite") # to system installed qtsingleapplication instead. option(USE_SYSTEM_QTSINGLEAPPLICATION "Don't set this option unless your system QtSingleApplication library has been compiled with the Clementine patches in 3rdparty" OFF) if(USE_SYSTEM_QTSINGLEAPPLICATION) - find_path(QTSINGLEAPPLICATION_INCLUDE_DIRS qtsingleapplication.h PATH_SUFFIXES QtSolutions) - find_library(QTSINGLEAPPLICATION_LIBRARIES QtSolutions_SingleApplication-2.6) - find_library(QTSINGLECOREAPPLICATION_LIBRARIES QtSolutions_SingleCoreApplication-2.6) + find_path(QTSINGLEAPPLICATION_INCLUDE_DIRS qtsingleapplication.h PATH_SUFFIXES qt5/QtSolutions) + find_library(QTSINGLEAPPLICATION_LIBRARIES Qt5Solutions_SingleApplication-2.6) + find_library(QTSINGLECOREAPPLICATION_LIBRARIES Qt5Solutions_SingleCoreApplication-2.6) else(USE_SYSTEM_QTSINGLEAPPLICATION) add_subdirectory(3rdparty/qtsingleapplication) set(QTSINGLEAPPLICATION_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/qtsingleapplication) @@ -382,11 +400,11 @@ endif(NOT QTIOCOMPRESSOR_INCLUDE_DIRS OR NOT QTIOCOMPRESSOR_LIBRARIES) # used to link to system installed qxt instead. option(USE_SYSTEM_QXT "Don't set this option unless your system Qxt library has been compiled with the Clementine patches in 3rdparty" OFF) if (USE_SYSTEM_QXT) - find_path(QXTCORE_INCLUDE_DIRS qxtglobal.h PATH_SUFFIXES QxtCore) - find_path(QXTGUI_INCLUDE_DIRS qxtglobalshortcut.h PATH_SUFFIXES QxtGui) + find_path(QXTCORE_INCLUDE_DIRS qxtglobal.h PATH_SUFFIXES qt5/QxtCore) + find_path(QXTGUI_INCLUDE_DIRS qxtglobalshortcut.h PATH_SUFFIXES qt5/QxtWidgets) set(QXT_INCLUDE_DIRS ${QXTCORE_INCLUDE_DIRS} ${QXTGUI_INCLUDE_DIRS}) # We only need its header. We don't need to link to QxtCore. - find_library(QXT_LIBRARIES QxtGui) + find_library(QXT_LIBRARIES QxtWidgets-qt5) else (USE_SYSTEM_QXT) add_definitions(-DQXT_STATIC -DBUILD_QXT_GUI -DBUILD_QXT_CORE) set(QXT_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/qxt) @@ -409,29 +427,15 @@ if(GMOCK_INCLUDE_DIRS) endif(GTEST_INCLUDE_DIRS) endif(GMOCK_INCLUDE_DIRS) -# Use the system's sha2 if it's available. -find_path(SHA2_INCLUDE_DIRS sha2.h) -find_library(SHA2_LIBRARIES sha2) -if(SHA2_LIBRARIES AND SHA2_INCLUDE_DIRS) - message(STATUS "Using system sha2 library") - set(USE_SYSTEM_SHA2 ON) +# Use the system libmygpo-qt5 if a recent enough version was found +if(LIBMYGPO_QT5_FOUND) + set(MYGPOQT5_LIBRARIES ${LIBMYGPO_QT5_LIBRARIES}) + set(MYGPOQT5_INCLUDE_DIRS ${LIBMYGPO_QT5_INCLUDE_DIRS}) else() - message(STATUS "Using builtin sha2 library") - set(USE_SYSTEM_SHA2 OFF) - add_subdirectory(3rdparty/sha2) - set(SHA2_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/sha2) - set(SHA2_LIBRARIES sha2) -endif() - -# Use the system libmygpo-qt if a recent enough version was found -if(LIBMYGPO_QT_FOUND) - set(MYGPOQT_LIBRARIES ${LIBMYGPO_QT_LIBRARIES}) - set(MYGPOQT_INCLUDE_DIRS ${LIBMYGPO_QT_INCLUDE_DIRS}) -else() - add_definitions(-DMYGPO_EXPORT=) - add_subdirectory(3rdparty/libmygpo-qt) - set(MYGPOQT_LIBRARIES mygpo-qt) - set(MYGPOQT_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/3rdparty/libmygpo-qt/) + add_definitions(-DMYGPO_STATIC) + add_subdirectory(3rdparty/libmygpo-qt5) + set(MYGPOQT5_LIBRARIES mygpo-qt5) + set(MYGPOQT5_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/libmygpo-qt5/src) endif() # Qocoa @@ -440,7 +444,6 @@ add_subdirectory(3rdparty/qocoa) # Subdirectories add_subdirectory(src) if (WIN32) - add_subdirectory(3rdparty/qtwin) add_subdirectory(3rdparty/tinysvcmdns) endif (WIN32) add_subdirectory(tests) @@ -449,7 +452,9 @@ add_subdirectory(ext/libclementine-common) add_subdirectory(ext/libclementine-tagreader) add_subdirectory(ext/clementine-tagreader) add_subdirectory(ext/libclementine-remote) -add_subdirectory(ext/libclementine-spotifyblob) +if(HAVE_SPOTIFY) + add_subdirectory(ext/libclementine-spotifyblob) +endif(HAVE_SPOTIFY) option(WITH_DEBIAN OFF) if(WITH_DEBIAN) diff --git a/cmake/OptionalSource.cmake b/cmake/OptionalSource.cmake index 2b816984f..d543e21f9 100644 --- a/cmake/OptionalSource.cmake +++ b/cmake/OptionalSource.cmake @@ -15,7 +15,7 @@ macro(optional_source TOGGLE) list(APPEND OTHER_SOURCES ${OPTIONAL_SOURCE_HEADERS}) set(_uic_sources) - qt4_wrap_ui(_uic_sources ${OPTIONAL_SOURCE_UI}) + qt5_wrap_ui(_uic_sources ${OPTIONAL_SOURCE_UI}) list(APPEND OTHER_SOURCES ${_uic_sources}) list(APPEND OTHER_UIC_SOURCES ${_uic_sources}) endif(${TOGGLE}) diff --git a/cmake/Translations.cmake b/cmake/Translations.cmake index 462145e2c..8ec962992 100644 --- a/cmake/Translations.cmake +++ b/cmake/Translations.cmake @@ -68,5 +68,5 @@ macro(add_po outfiles po_prefix) file(APPEND ${_qrc} "${po_prefix}${_lang}.qm") endforeach(_lang) file(APPEND ${_qrc} "") - qt4_add_resources(${outfiles} ${_qrc}) + qt5_add_resources(${outfiles} ${_qrc}) endmacro(add_po) diff --git a/data/playstore/fr_generic_rgb_wo_45.png b/data/playstore/fr_generic_rgb_wo_45.png index 66f3bc157..b6b67a4f4 100644 Binary files a/data/playstore/fr_generic_rgb_wo_45.png and b/data/playstore/fr_generic_rgb_wo_45.png differ diff --git a/debian/compat b/debian/compat index 7f8f011eb..ec635144f 100644 --- a/debian/compat +++ b/debian/compat @@ -1 +1 @@ -7 +9 diff --git a/debian/control b/debian/control index 110af2215..1885e75aa 100644 --- a/debian/control +++ b/debian/control @@ -3,40 +3,42 @@ Section: sound Priority: optional Maintainer: David Sansome Build-Depends: debhelper (>= 7), - liblastfm-dev, - libtag1-dev, - libboost1.38-dev | - libboost1.40-dev | - libboost1.42-dev | - libboost-dev, - libboost-serialization1.38-dev | - libboost-serialization1.40-dev | - libboost-serialization1.42-dev | - libboost-serialization-dev, - libcdio-cdda1, - libchromaprint-dev, - libcrypto++-dev, - libglew1.5-dev | - libglew-dev, - libqt4-dev, - qt4-dev-tools, - libqt4-opengl-dev, + make, cmake, + gcc, + protobuf-compiler, + libglib2.0-dev, + libdbus-1-dev, + libprotobuf-dev, + libboost-dev, + libsqlite3-dev, + libasound2-dev, + libpulse-dev, + libtag1-dev, + libqt5-dev, + qt5-dev-tools, + qtbase5-dev, + qtbase5-dev-tools, + qtbase5-private-dev, + libqt5x11extras5-dev, + libqt5opengl5-dev, libgstreamer1.0-dev, libgstreamer-plugins-base1.0-dev, + libcdio-dev, libgpod-dev, + libimobiledevice-dev, + libmtp-dev, libplist-dev, libusbmuxd-dev, - libmtp-dev, - libqjson-dev, - protobuf-compiler, - libprotobuf-dev, + libchromaprint-dev, + liblastfm5-dev, + libcrypto++-dev, + libglew-dev, libfftw3-dev, libsparsehash-dev, - libsqlite3-dev, - libpulse-dev, - libmygpo-qt-dev (>= 1.0.7) -Standards-Version: 3.8.1 + libmygpo-qt-dev (>= 1.0.7), + libprojectm-dev (>= 2.0.1+dfsg-6) +Standards-Version: 3.9.8 Homepage: http://www.clementine-player.org/ Package: clementine @@ -46,6 +48,7 @@ Depends: ${shlibs:Depends}, ${misc:Depends}, gstreamer1.0-plugins-base, gstreamer1.0-plugins-good, gstreamer1.0-plugins-ugly, + gstreamer1.0-alsa, gstreamer1.0-pulseaudio, libprojectm-data | projectm-data Description: Modern music player and library organiser inspired by Amarok 1.4 diff --git a/debian/copyright b/debian/copyright index 499978c1e..d2292b471 100644 --- a/debian/copyright +++ b/debian/copyright @@ -93,12 +93,6 @@ Files: 3rdparty/qtsingleapplication/* Copyright: 2009, Nokia Corporation License: Qt Commercial or LGPL-2.1 or GPL-3 -Files: 3rdparty/qtwin/* -Copyright: 2009, Nokia Corporation -License: other - Use, modification and distribution is allowed without limitation, - warranty, liability or support of any kind. - Files: 3rdparty/qxt/* Copyright: 2007, Qxt Foundation License: CPL 1.0 and/or LGPL-2.1 diff --git a/dist/CMakeLists.txt b/dist/CMakeLists.txt index b89966f70..d97eea2b0 100644 --- a/dist/CMakeLists.txt +++ b/dist/CMakeLists.txt @@ -61,7 +61,7 @@ if (NOT APPLE) clementine-itpc.protocol clementine-feed.protocol clementine-zune.protocol - DESTINATION share/kde4/services + DESTINATION share/kservices5 ) install(FILES clementine.appdata.xml diff --git a/dist/clementine.spec.in b/dist/clementine.spec.in index 9e4dcbdd9..119608270 100644 --- a/dist/clementine.spec.in +++ b/dist/clementine.spec.in @@ -9,14 +9,52 @@ URL: http://www.clementine-player.org/ Source0: %{name}-@CLEMENTINE_VERSION_SPARKLE@.tar.xz BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) -BuildRequires: desktop-file-utils liblastfm-devel taglib-devel gettext -BuildRequires: qt4-devel boost-devel gcc-c++ glew-devel libgpod-devel -BuildRequires: cmake gstreamer1-devel gstreamer1-plugins-base-devel -BuildRequires: libmtp-devel protobuf-devel protobuf-compiler libcdio-devel -BuildRequires: qjson-devel cryptopp-devel fftw-devel sparsehash-devel -BuildRequires: sqlite-devel pulseaudio-libs-devel libchromaprint-devel - -Requires: libgpod protobuf-lite libcdio qjson sqlite +BuildRequires: cmake +BuildRequires: make +BuildRequires: git +BuildRequires: gettext +BuildRequires: gcc-c++ +BuildRequires: boost-devel +BuildRequires: sparsehash-devel +BuildRequires: liblastfm-qt5-devel +BuildRequires: desktop-file-utils +BuildRequires: hicolor-icon-theme +BuildRequires: libappstream-glib +BuildRequires: pkgconfig +BuildRequires: pkgconfig(glib-2.0) +BuildRequires: pkgconfig(gio-2.0) +BuildRequires: pkgconfig(gio-unix-2.0) +BuildRequires: pkgconfig(gthread-2.0) +BuildRequires: pkgconfig(dbus-1) +BuildRequires: pkgconfig(alsa) +BuildRequires: pkgconfig(protobuf) +BuildRequires: pkgconfig(sqlite3) >= 3.7 +BuildRequires: pkgconfig(taglib) >= 1.11 +BuildRequires: pkgconfig(glew) +BuildRequires: pkgconfig(cryptopp) +BuildRequires: pkgconfig(Qt5Core) +BuildRequires: pkgconfig(Qt5Gui) +BuildRequires: pkgconfig(Qt5Widgets) +BuildRequires: pkgconfig(Qt5Concurrent) +BuildRequires: pkgconfig(Qt5Sql) +BuildRequires: pkgconfig(Qt5Network) +BuildRequires: pkgconfig(Qt5Xml) +BuildRequires: pkgconfig(Qt5X11Extras) +BuildRequires: pkgconfig(Qt5OpenGL) +BuildRequires: pkgconfig(Qt5DBus) +BuildRequires: pkgconfig(Qt5Test) +BuildRequires: pkgconfig(gstreamer-1.0) +BuildRequires: pkgconfig(gstreamer-app-1.0) +BuildRequires: pkgconfig(gstreamer-audio-1.0) +BuildRequires: pkgconfig(gstreamer-base-1.0) +BuildRequires: pkgconfig(gstreamer-tag-1.0) +BuildRequires: pkgconfig(libpulse) +BuildRequires: pkgconfig(libcdio) +BuildRequires: pkgconfig(libchromaprint) +BuildRequires: pkgconfig(libgpod-1.0) +BuildRequires: pkgconfig(libmtp) +BuildRequires: pkgconfig(libnotify) +BuildRequires: pkgconfig(libudf) # GStreamer codec dependencies Requires: gstreamer1-plugins-ugly @@ -79,13 +117,14 @@ make clean %doc %{_bindir}/clementine %{_bindir}/clementine-tagreader +%dir %{_datadir}/metainfo/ %{_datadir}/metainfo/clementine.appdata.xml %{_datadir}/applications/clementine.desktop %{_datadir}/clementine/projectm-presets -%{_datadir}/kde4/services/clementine-itms.protocol -%{_datadir}/kde4/services/clementine-itpc.protocol -%{_datadir}/kde4/services/clementine-feed.protocol -%{_datadir}/kde4/services/clementine-zune.protocol +%{_datadir}/kservices5/clementine-itms.protocol +%{_datadir}/kservices5/clementine-itpc.protocol +%{_datadir}/kservices5/clementine-feed.protocol +%{_datadir}/kservices5/clementine-zune.protocol %{_datadir}/icons/hicolor/64x64/apps/clementine.png %{_datadir}/icons/hicolor/128x128/apps/clementine.png %{_datadir}/icons/hicolor/scalable/apps/clementine.svg diff --git a/dist/create-dmg.sh b/dist/create-dmg.sh index 45746c0ad..ce05225b3 100755 --- a/dist/create-dmg.sh +++ b/dist/create-dmg.sh @@ -38,8 +38,21 @@ cp ../dist/dmg_background.png "$TMP/.background/background.png" cp ../dist/DS_Store.in "$TMP/.DS_Store" chmod go-rwx "$TMP/.DS_Store" ln -s /Applications "$TMP/Applications" -# copies the prepared bundle into the dir that will become the DMG +# copies the prepared bundle into the dir that will become the DMG cp -R "$IN" "$TMP" -genisoimage -D -V "Clementine" -no-pad -r -apple -o $NAME.iso $TMP -dmg dmg $NAME.iso $OUT +# create +hdiutil makehybrid -hfs -hfs-volume-name Clementine -hfs-openfolder "$TMP" "$TMP" -o tmp.dmg +hdiutil convert -format UDZO -imagekey zlib-level=9 tmp.dmg -o "$OUT" + +# cleanup +rm tmp.dmg + +#hdiutil create -srcfolder "$TMP" \ +# -format UDZO -imagekey zlib-level=9 \ +# -scrub \ +# "$OUT" \ +# || die "Error creating DMG :(" + +# done ! +echo 'DMG size:' `du -hs "$OUT" | awk '{print $1}'` diff --git a/dist/macdeploy.py b/dist/macdeploy.py index 3371eaed7..5f89a855e 100755 --- a/dist/macdeploy.py +++ b/dist/macdeploy.py @@ -1,4 +1,4 @@ -#!/usr/bin/python2 +#!/usr/bin/python # This file is part of Clementine. # @@ -30,6 +30,11 @@ FRAMEWORK_SEARCH_PATH = [ os.path.join(os.environ['HOME'], 'Library/Frameworks') ] +STRIP_PREFIX = [ + '@@HOMEBREW_PREFIX@@/opt/qt5/lib/', + '@@HOMEBREW_CELLAR@@/qt5/5.8.0_1/lib/', +] + LIBRARY_SEARCH_PATH = ['/target', '/target/lib', '/usr/local/lib', '/sw/lib'] GSTREAMER_PLUGINS = [ @@ -54,14 +59,13 @@ GSTREAMER_PLUGINS = [ 'libgstapetag.so', 'libgstasf.so', 'libgstaudioparsers.so', - 'libgstfaac.so', + #'libgstfaac.so', 'libgstfaad.so', 'libgstflac.so', 'libgstid3demux.so', 'libgstisomp4.so', 'libgstlame.so', 'libgstlibav.so', - 'libgstmad.so', 'libgstmms.so', # TODO: Bring back Musepack support. 'libgstogg.so', @@ -70,49 +74,52 @@ GSTREAMER_PLUGINS = [ 'libgstspeex.so', 'libgsttaglib.so', 'libgstvorbis.so', - 'libgstwavpack.so', 'libgstwavparse.so', 'libgstxingmux.so', # HTTP src support - 'libgstsouphttpsrc.so', + 'libgstsoup.so', # Icecast support 'libgsticydemux.so', - # CD support - 'libgstcdio.so', - # RTSP streaming 'libgstrtp.so', 'libgstrtsp.so', ] GSTREAMER_SEARCH_PATH = [ + '/usr/local/lib/gstreamer-1.0', '/target/lib/gstreamer-1.0', '/target/libexec/gstreamer-1.0', + '/usr/local/Cellar/gstreamer/1.16.1/libexec/gstreamer-1.0', ] QT_PLUGINS = [ - 'accessible/libqtaccessiblewidgets.dylib', - 'codecs/libqcncodecs.dylib', - 'codecs/libqjpcodecs.dylib', - 'codecs/libqkrcodecs.dylib', - 'codecs/libqtwcodecs.dylib', + #'accessible/libqtaccessiblewidgets.dylib', + #'codecs/libqcncodecs.dylib', + #'codecs/libqjpcodecs.dylib', + #'codecs/libqkrcodecs.dylib', + #'codecs/libqtwcodecs.dylib', 'iconengines/libqsvgicon.dylib', 'imageformats/libqgif.dylib', 'imageformats/libqico.dylib', 'imageformats/libqjpeg.dylib', - 'imageformats/libqmng.dylib', + #'imageformats/libqmng.dylib', 'imageformats/libqsvg.dylib', + 'platforms/libqcocoa.dylib', ] QT_PLUGINS_SEARCH_PATH = [ + '/usr/local/Cellar/qt/5.13.1/plugins', '/target/plugins', '/usr/local/Trolltech/Qt-4.7.0/plugins', '/Developer/Applications/Qt/plugins', ] -GIO_MODULES_SEARCH_PATH = ['/target/lib/gio/modules',] +GIO_MODULES_SEARCH_PATH = [ + '/usr/local/lib/gio/modules', + '/target/lib/gio/modules', +] INSTALL_NAME_TOOL_APPLE = 'install_name_tool' INSTALL_NAME_TOOL_CROSS = 'x86_64-apple-darwin-%s' % INSTALL_NAME_TOOL_APPLE @@ -206,6 +213,10 @@ def GetBrokenLibraries(binary): def FindFramework(path): + for prefix in STRIP_PREFIX: + if path.startswith(prefix): + path = path[len(prefix):] + break for search_path in FRAMEWORK_SEARCH_PATH: abs_path = os.path.join(search_path, path) if os.path.exists(abs_path): @@ -294,6 +305,7 @@ def CopyLibrary(path): new_path = os.path.join(frameworks_dir, os.path.basename(path)) args = ['cp', path, new_path] commands.append(args) + commands.append(['chmod', '+w', new_path]) LOGGER.info("Copying library '%s'", path) return new_path @@ -304,6 +316,7 @@ def CopyPlugin(path, subdir): commands.append(args) args = ['cp', path, new_path] commands.append(args) + commands.append(['chmod', '+w', new_path]) LOGGER.info("Copying plugin '%s'", path) return new_path @@ -328,6 +341,7 @@ def CopyFramework(src_binary): commands.append(['mkdir', '-p', dest_dir]) commands.append(['cp', src_binary, dest_binary]) + commands.append(['chmod', '+w', dest_binary]) # Copy special files from various places: # QtCore has Resources/qt_menu.nib (copy to app's Resources) @@ -460,7 +474,6 @@ def main(): FixPlugin(FindGstreamerPlugin('gst-plugin-scanner'), '.') FixPlugin(FindGioModule('libgiognutls.so'), 'gio-modules') - FixPlugin(FindGioModule('libgiolibproxy.so'), 'gio-modules') try: FixPlugin('clementine-spotifyblob', '.') diff --git a/ext/clementine-spotifyblob/CMakeLists.txt b/ext/clementine-spotifyblob/CMakeLists.txt index 7568a2931..e5342ee5b 100644 --- a/ext/clementine-spotifyblob/CMakeLists.txt +++ b/ext/clementine-spotifyblob/CMakeLists.txt @@ -28,7 +28,7 @@ if(APPLE) list(APPEND SOURCES spotify_utilities.mm) endif(APPLE) -qt4_wrap_cpp(MOC ${HEADERS}) +qt5_wrap_cpp(MOC ${HEADERS}) if(WIN32 AND NOT CMAKE_BUILD_TYPE STREQUAL "Debug" AND NOT ENABLE_WIN32_CONSOLE) set(win32_build_flag WIN32) diff --git a/ext/clementine-spotifyblob/spotifyclient.cpp b/ext/clementine-spotifyblob/spotifyclient.cpp index 957393060..ef2e9dc63 100644 --- a/ext/clementine-spotifyblob/spotifyclient.cpp +++ b/ext/clementine-spotifyblob/spotifyclient.cpp @@ -697,7 +697,7 @@ void SpotifyClient::ConvertTrack(sp_track* track, pb::spotify::Track* pb) { const QByteArray art_id(reinterpret_cast(sp_album_cover( sp_track_album(track), SP_IMAGE_SIZE_LARGE)), kSpotifyImageIDSize); - const QString art_id_b64 = QString::fromAscii(art_id.toBase64()); + const QString art_id_b64 = QString::fromLatin1(art_id.toBase64()); pb->set_album_art_id(DataCommaSizeFromQString(art_id_b64)); // Artists @@ -732,7 +732,7 @@ void SpotifyClient::ConvertAlbum(sp_album* album, pb::spotify::Track* pb) { const QByteArray art_id( reinterpret_cast(sp_album_cover(album, SP_IMAGE_SIZE_LARGE)), kSpotifyImageIDSize); - const QString art_id_b64 = QString::fromAscii(art_id.toBase64()); + const QString art_id_b64 = QString::fromLatin1(art_id.toBase64()); pb->set_album_art_id(DataCommaSizeFromQString(art_id_b64)); // URI - Blugh @@ -979,7 +979,7 @@ void SpotifyClient::SendPlaybackError(const QString& error) { } void SpotifyClient::LoadImage(const QString& id_b64) { - QByteArray id = QByteArray::fromBase64(id_b64.toAscii()); + QByteArray id = QByteArray::fromBase64(id_b64.toLatin1()); if (id.length() != kSpotifyImageIDSize) { qLog(Warning) << "Invalid image ID (did not decode to" << kSpotifyImageIDSize << "bytes):" << id_b64; diff --git a/ext/clementine-tagreader/CMakeLists.txt b/ext/clementine-tagreader/CMakeLists.txt index f4c7bb01e..855e390cf 100644 --- a/ext/clementine-tagreader/CMakeLists.txt +++ b/ext/clementine-tagreader/CMakeLists.txt @@ -16,8 +16,8 @@ set(SOURCES tagreaderworker.cpp ) -qt4_wrap_cpp(MOC ${HEADERS}) -qt4_add_resources(QRC data/data.qrc) +qt5_wrap_cpp(MOC ${HEADERS}) +qt5_add_resources(QRC data/data.qrc) add_executable(clementine-tagreader ${SOURCES} @@ -29,8 +29,8 @@ target_link_libraries(clementine-tagreader ${TAGLIB_LIBRARIES} libclementine-common libclementine-tagreader - ${QT_QTCORE_LIBRARY} - ${QT_QTNETWORK_LIBRARY} + Qt5::Core + Qt5::Network z ) diff --git a/ext/libclementine-common/CMakeLists.txt b/ext/libclementine-common/CMakeLists.txt index 82e7829b1..694836c9e 100644 --- a/ext/libclementine-common/CMakeLists.txt +++ b/ext/libclementine-common/CMakeLists.txt @@ -27,7 +27,7 @@ if(APPLE) list(APPEND SOURCES core/scoped_nsautorelease_pool.mm) endif(APPLE) -qt4_wrap_cpp(MOC ${HEADERS}) +qt5_wrap_cpp(MOC ${HEADERS}) add_library(libclementine-common STATIC ${SOURCES} @@ -35,7 +35,8 @@ add_library(libclementine-common STATIC ) target_link_libraries(libclementine-common - ${QT_LIBRARIES} + Qt5::Core + Qt5::Network ${TAGLIB_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} ) diff --git a/ext/libclementine-common/core/logging.cpp b/ext/libclementine-common/core/logging.cpp index 2f9356dbc..9aa131935 100644 --- a/ext/libclementine-common/core/logging.cpp +++ b/ext/libclementine-common/core/logging.cpp @@ -30,6 +30,7 @@ #include #include #include +#include #include @@ -45,7 +46,7 @@ const char* kDefaultLogLevels = "GstEnginePipeline:2,*:3"; static const char* kMessageHandlerMagic = "__logging_message__"; static const int kMessageHandlerMagicLength = strlen(kMessageHandlerMagic); -static QtMsgHandler sOriginalMessageHandler = nullptr; +static QtMessageHandler sOriginalMessageHandler = nullptr; void GLog(const char* domain, int level, const char* message, void* user_data) { switch (level) { @@ -69,9 +70,9 @@ void GLog(const char* domain, int level, const char* message, void* user_data) { } } -static void MessageHandler(QtMsgType type, const char* message) { - if (strncmp(kMessageHandlerMagic, message, kMessageHandlerMagicLength) == 0) { - fprintf(stderr, "%s\n", message + kMessageHandlerMagicLength); +static void MessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &message) { + if (strncmp(kMessageHandlerMagic, message.toLocal8Bit().data(), kMessageHandlerMagicLength) == 0) { + fprintf(stderr, "%s\n", message.toLocal8Bit().data() + kMessageHandlerMagicLength); return; } @@ -90,7 +91,7 @@ static void MessageHandler(QtMsgType type, const char* message) { break; } - for (const QString& line : QString::fromLocal8Bit(message).split('\n')) { + for (const QString& line : message.split('\n')) { CreateLogger(level, "unknown", -1) << line.toLocal8Bit().constData(); } @@ -105,10 +106,11 @@ void Init() { sClassLevels = new QMap(); sNullDevice = new NullDevice; + sNullDevice->open(QIODevice::ReadWrite); // Catch other messages from Qt if (!sOriginalMessageHandler) { - sOriginalMessageHandler = qInstallMsgHandler(MessageHandler); + sOriginalMessageHandler = qInstallMessageHandler(MessageHandler); } } @@ -207,9 +209,9 @@ QDebug CreateLogger(Level level, const QString& class_name, int line) { ret.nospace() << kMessageHandlerMagic << QDateTime::currentDateTime() .toString("hh:mm:ss.zzz") - .toAscii() + .toLatin1() .constData() << level_name - << function_line.leftJustified(32).toAscii().constData(); + << function_line.leftJustified(32).toLatin1().constData(); return ret.space(); } @@ -217,9 +219,9 @@ QDebug CreateLogger(Level level, const QString& class_name, int line) { QString CXXDemangle(const QString& mangled_function) { int status; char* demangled_function = abi::__cxa_demangle( - mangled_function.toAscii().constData(), nullptr, nullptr, &status); + mangled_function.toLatin1().constData(), nullptr, nullptr, &status); if (status == 0) { - QString ret = QString::fromAscii(demangled_function); + QString ret = QString::fromLatin1(demangled_function); free(demangled_function); return ret; } @@ -260,7 +262,7 @@ void DumpStackTrace() { backtrace_symbols(reinterpret_cast(&callstack), callstack_size); // Start from 1 to skip ourself. for (int i = 1; i < callstack_size; ++i) { - std::cerr << DemangleSymbol(QString::fromAscii(symbols[i])).toStdString() + std::cerr << DemangleSymbol(QString::fromLatin1(symbols[i])).toStdString() << std::endl; } free(symbols); @@ -269,6 +271,23 @@ void DumpStackTrace() { #endif } +QDebug CreateLoggerFatal(int line, const char *class_name) { return qCreateLogger(line, class_name, Fatal); } +QDebug CreateLoggerError(int line, const char *class_name) { return qCreateLogger(line, class_name, Error); } + +#ifdef QT_NO_WARNING_OUTPUT +QNoDebug CreateLoggerWarning(int, const char*) { return QNoDebug(); } +#else +QDebug CreateLoggerWarning(int line, const char *class_name) { return qCreateLogger(line, class_name, Warning); } +#endif // QT_NO_WARNING_OUTPUT + +#ifdef QT_NO_DEBUG_OUTPUT +QNoDebug CreateLoggerInfo(int, const char*) { return QNoDebug(); } +QNoDebug CreateLoggerDebug(int, const char*) { return QNoDebug(); } +#else +QDebug CreateLoggerInfo(int line, const char *class_name) { return qCreateLogger(line, class_name, Info); } +QDebug CreateLoggerDebug(int line, const char *class_name) { return qCreateLogger(line, class_name, Debug); } +#endif // QT_NO_DEBUG_OUTPUT + } // namespace logging namespace { diff --git a/ext/libclementine-common/core/logging.h b/ext/libclementine-common/core/logging.h index 21eebdf3a..0433da5aa 100644 --- a/ext/libclementine-common/core/logging.h +++ b/ext/libclementine-common/core/logging.h @@ -30,11 +30,16 @@ #define qLog(level) \ while (false) QNoDebug() #else -#define qLog(level) \ + +#define qLog(level) \ + logging::CreateLogger##level(__LINE__, __PRETTY_FUNCTION__) + +#define qCreateLogger(line, class_name, level) \ logging::CreateLogger(logging::Level_##level, \ - logging::ParsePrettyFunction(__PRETTY_FUNCTION__), \ - __LINE__) -#endif + logging::ParsePrettyFunction(class_name), \ + line) + +#endif // QT_NO_DEBUG_STREAM namespace logging { class NullDevice : public QIODevice { @@ -59,6 +64,24 @@ void DumpStackTrace(); QString ParsePrettyFunction(const char* pretty_function); QDebug CreateLogger(Level level, const QString& class_name, int line); +QDebug CreateLoggerFatal(int line, const char* class_name); +QDebug CreateLoggerError(int line, const char* class_name); + +#ifdef QT_NO_WARNING_OUTPUT +QNoDebug CreateLoggerWarning(int, const char*); +#else +QDebug CreateLoggerWarning(int line, const char* class_name); +#endif // QT_NO_WARNING_OUTPUT + +#ifdef QT_NO_DEBUG_OUTPUT +QNoDebug CreateLoggerInfo(int, const char*); +QNoDebug CreateLoggerDebug(int, const char*); +#else +QDebug CreateLoggerInfo(int line, const char* class_name); +QDebug CreateLoggerDebug(int line, const char* class_name); +#endif // QT_NO_DEBUG_OUTPUT + + void GLog(const char* domain, int level, const char* message, void* user_data); extern const char* kDefaultLogLevels; diff --git a/ext/libclementine-common/core/messagehandler.cpp b/ext/libclementine-common/core/messagehandler.cpp index 1ea64929b..065964d5f 100644 --- a/ext/libclementine-common/core/messagehandler.cpp +++ b/ext/libclementine-common/core/messagehandler.cpp @@ -23,6 +23,7 @@ #include #include +#include _MessageHandlerBase::_MessageHandlerBase(QIODevice* device, QObject* parent) : QObject(parent), diff --git a/ext/libclementine-remote/CMakeLists.txt b/ext/libclementine-remote/CMakeLists.txt index 5f860fbcd..70761b493 100644 --- a/ext/libclementine-remote/CMakeLists.txt +++ b/ext/libclementine-remote/CMakeLists.txt @@ -1,5 +1,7 @@ include_directories(${PROTOBUF_INCLUDE_DIRS}) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --std=c++0x") + set(MESSAGES remotecontrolmessages.proto ) diff --git a/ext/libclementine-tagreader/CMakeLists.txt b/ext/libclementine-tagreader/CMakeLists.txt index 02d54897b..5f4804cd6 100644 --- a/ext/libclementine-tagreader/CMakeLists.txt +++ b/ext/libclementine-tagreader/CMakeLists.txt @@ -28,7 +28,7 @@ optional_source(HAVE_GOOGLE_DRIVE cloudstream.h ) -qt4_wrap_cpp(MOC ${HEADERS}) +qt5_wrap_cpp(MOC ${HEADERS}) protobuf_generate_cpp(PROTO_SOURCES PROTO_HEADERS ${MESSAGES}) diff --git a/ext/libclementine-tagreader/tagreader.cpp b/ext/libclementine-tagreader/tagreader.cpp index 9baba6c46..7a7689ad8 100644 --- a/ext/libclementine-tagreader/tagreader.cpp +++ b/ext/libclementine-tagreader/tagreader.cpp @@ -1312,7 +1312,7 @@ QByteArray TagReader::LoadEmbeddedArt(const QString& filename) const { int pos = data.find('\0') + 1; if ((pos > 0) && (pos < data.size())) { - cover = QByteArray(data.data() + pos, data.size() - pos); + cover = QByteArray(data.data() + pos, data.size() - pos); } } diff --git a/gst/moodbar/CMakeLists.txt b/gst/moodbar/CMakeLists.txt index 44c136253..7713046e1 100644 --- a/gst/moodbar/CMakeLists.txt +++ b/gst/moodbar/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 2.6) +cmake_minimum_required(VERSION 2.8.11) set(CMAKE_C_FLAGS "-Wall") set(CMAKE_CXX_FLAGS "-Woverloaded-virtual -Wall --std=c++0x") @@ -27,3 +27,5 @@ target_link_libraries(gstmoodbar ${GSTREAMER_BASE_LIBRARIES} ${FFTW3_FFTW_LIBRARY} ) + +target_link_libraries(gstmoodbar Qt5::Core) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b67a7c38c..e19419559 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -12,18 +12,9 @@ endif(BUILD_WERROR) include_directories(${CMAKE_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}) include_directories(../3rdparty/gmock/gtest/include) -if(WIN32) - include_directories(../3rdparty/qtwin) -endif(WIN32) # Activate fast QString concatenation -if (QT_VERSION_MINOR GREATER 5) - if (QT_VERSION_MINOR GREATER 7) - add_definitions(-DQT_USE_QSTRINGBUILDER) - else(QT_VERSION_MINOR GREATER 7) - add_definitions(-DQT_USE_FAST_CONCATENATION -DQT_USE_FAST_OPERATOR_PLUS) - endif(QT_VERSION_MINOR GREATER 7) -endif(QT_VERSION_MINOR GREATER 5) +add_definitions(-DQT_USE_QSTRINGBUILDER) add_definitions(-DQT_NO_URL_CAST_FROM_STRING) add_definitions(-DBOOST_BIND_NO_PLACEHOLDERS) @@ -34,9 +25,8 @@ include_directories(${GOBJECT_INCLUDE_DIRS}) include_directories(${QTSINGLEAPPLICATION_INCLUDE_DIRS}) include_directories(${QTIOCOMPRESSOR_INCLUDE_DIRS}) include_directories(${QXT_INCLUDE_DIRS}) -include_directories(${SHA2_INCLUDE_DIRS}) include_directories(${CHROMAPRINT_INCLUDE_DIRS}) -include_directories(${MYGPOQT_INCLUDE_DIRS}) +include_directories(${MYGPOQT5_INCLUDE_DIRS}) if (HAVE_VISUALISATIONS) find_package(OpenGL REQUIRED) @@ -45,7 +35,7 @@ if (HAVE_VISUALISATIONS) endif(HAVE_VISUALISATIONS) if(HAVE_LIBLASTFM) - include_directories(${LASTFM_INCLUDE_DIRS}) + include_directories(${LASTFM5_INCLUDE_DIRS}) endif(HAVE_LIBLASTFM) if(HAVE_BREAKPAD) @@ -64,6 +54,7 @@ endif(HAVE_SPOTIFY) cmake_policy(SET CMP0011 NEW) include(../cmake/ParseArguments.cmake) + if(HAVE_TRANSLATIONS) include(../cmake/Translations.cmake) endif(HAVE_TRANSLATIONS) @@ -118,6 +109,7 @@ set(SOURCES covers/albumcoverfetcher.cpp covers/albumcoverfetchersearch.cpp covers/albumcoverloader.cpp + covers/discogscoverprovider.cpp covers/coverexportrunnable.cpp covers/coverprovider.cpp covers/coverproviders.cpp @@ -436,6 +428,7 @@ set(HEADERS covers/albumcoverfetcher.h covers/albumcoverfetchersearch.h covers/albumcoverloader.h + covers/discogscoverprovider.h covers/coverexportrunnable.h covers/coverprovider.h covers/coverproviders.h @@ -919,28 +912,28 @@ if(UNIX AND HAVE_DBUS) file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/dbus) # MPRIS 2.0 DBUS interfaces - qt4_add_dbus_adaptor(SOURCES + qt5_add_dbus_adaptor(SOURCES dbus/org.mpris.MediaPlayer2.Player.xml core/mpris2.h mpris::Mpris2 core/mpris2_player Mpris2Player) - qt4_add_dbus_adaptor(SOURCES + qt5_add_dbus_adaptor(SOURCES dbus/org.mpris.MediaPlayer2.xml core/mpris2.h mpris::Mpris2 core/mpris2_root Mpris2Root) - qt4_add_dbus_adaptor(SOURCES + qt5_add_dbus_adaptor(SOURCES dbus/org.mpris.MediaPlayer2.TrackList.xml core/mpris2.h mpris::Mpris2 core/mpris2_tracklist Mpris2TrackList) # MPRIS 2.1 DBUS interfaces - qt4_add_dbus_adaptor(SOURCES + qt5_add_dbus_adaptor(SOURCES dbus/org.mpris.MediaPlayer2.Playlists.xml core/mpris2.h mpris::Mpris2 core/mpris2_playlists Mpris2Playlists) # org.freedesktop.Notifications DBUS interface - qt4_add_dbus_interface(SOURCES + qt5_add_dbus_interface(SOURCES dbus/org.freedesktop.Notifications.xml dbus/notification) # org.gnome.SettingsDaemon interface - qt4_add_dbus_interface(SOURCES + qt5_add_dbus_interface(SOURCES dbus/org.gnome.SettingsDaemon.MediaKeys.xml dbus/gnomesettingsdaemon) @@ -978,10 +971,10 @@ if(UNIX AND HAVE_DBUS) PROPERTIES NO_NAMESPACE dbus/udisks) set_source_files_properties(dbus/org.freedesktop.UDisks.Device.xml PROPERTIES NO_NAMESPACE dbus/udisksdevice) - qt4_add_dbus_interface(SOURCES + qt5_add_dbus_interface(SOURCES dbus/org.freedesktop.UDisks.xml dbus/udisks) - qt4_add_dbus_interface(SOURCES + qt5_add_dbus_interface(SOURCES dbus/org.freedesktop.UDisks.Device.xml dbus/udisksdevice) endif(HAVE_DEVICEKIT) @@ -997,26 +990,26 @@ if(UNIX AND HAVE_DBUS) PROPERTIES NO_NAMESPACE dbus/udisks2drive INCLUDE dbus/metatypes.h) set_source_files_properties(dbus/org.freedesktop.UDisks2.Job.xml PROPERTIES NO_NAMESPACE dbus/udisks2job INCLUDE dbus/metatypes.h) - qt4_add_dbus_interface(SOURCES + qt5_add_dbus_interface(SOURCES dbus/org.freedesktop.DBus.ObjectManager.xml dbus/objectmanager) - qt4_add_dbus_interface(SOURCES + qt5_add_dbus_interface(SOURCES dbus/org.freedesktop.UDisks2.Filesystem.xml dbus/udisks2filesystem) - qt4_add_dbus_interface(SOURCES + qt5_add_dbus_interface(SOURCES dbus/org.freedesktop.UDisks2.Block.xml dbus/udisks2block) - qt4_add_dbus_interface(SOURCES + qt5_add_dbus_interface(SOURCES dbus/org.freedesktop.UDisks2.Drive.xml dbus/udisks2drive) - qt4_add_dbus_interface(SOURCES + qt5_add_dbus_interface(SOURCES dbus/org.freedesktop.UDisks2.Job.xml dbus/udisks2job) endif(HAVE_UDISKS2) # Wiimotedev interface classes if(ENABLE_WIIMOTEDEV) - qt4_add_dbus_interface(SOURCES + qt5_add_dbus_interface(SOURCES dbus/org.wiimotedev.deviceEvents.xml dbus/wiimotedev) endif(ENABLE_WIIMOTEDEV) @@ -1220,9 +1213,9 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.in configure_file(${CMAKE_CURRENT_SOURCE_DIR}/version.h.in ${CMAKE_CURRENT_BINARY_DIR}/version.h) -qt4_wrap_cpp(MOC ${HEADERS} OPTIONS "-D_SYS_SYSMACROS_H_OUTER") -qt4_wrap_ui(UIC ${UI}) -qt4_add_resources(QRC ${RESOURCES}) +qt5_wrap_cpp(MOC ${HEADERS}) +qt5_wrap_ui(UIC ${UI}) +qt5_add_resources(QRC ${RESOURCES}) if(HAVE_TRANSLATIONS) add_pot(POT @@ -1251,14 +1244,13 @@ target_link_libraries(clementine_lib libclementine-common libclementine-tagreader libclementine-remote - ${SHA2_LIBRARIES} + ${TAGLIB_LIBRARIES} - ${MYGPOQT_LIBRARIES} + ${MYGPOQT5_LIBRARIES} ${CHROMAPRINT_LIBRARIES} ${GOBJECT_LIBRARIES} ${GLIB_LIBRARIES} ${GIO_LIBRARIES} - ${QJSON_LIBRARIES} ${QT_LIBRARIES} ${GSTREAMER_BASE_LIBRARIES} ${GSTREAMER_LIBRARIES} @@ -1270,8 +1262,15 @@ target_link_libraries(clementine_lib ${QTIOCOMPRESSOR_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} ${SQLITE_LIBRARIES} - z + Qocoa + z +) + +link_directories( + ${CHROMAPRINT_LIBRARY_DIRS} + ${GSTREAMER_APP_LIBRARY_DIRS} + ${GLEW_LIBRARY_DIRS} ) if(HAVE_VISUALISATIONS) @@ -1279,7 +1278,7 @@ if(HAVE_VISUALISATIONS) endif(HAVE_VISUALISATIONS) if(HAVE_LIBLASTFM) - target_link_libraries(clementine_lib ${LASTFM_LIBRARIES}) + target_link_libraries(clementine_lib ${LASTFM5_LIBRARIES}) endif(HAVE_LIBLASTFM) if(HAVE_LIBGPOD) @@ -1356,12 +1355,11 @@ target_link_libraries(clementine_lib qsqlite) if (WIN32) target_link_libraries(clementine_lib + protobuf ${ZLIB_LIBRARIES} ${QTSPARKLE_LIBRARIES} tinysvcmdns - qtwin dsound - ${QT_QTGUI_LIBRARY} ) endif (WIN32) @@ -1371,7 +1369,6 @@ if (UNIX AND NOT APPLE) # command but they're actually used by libraries that appear after them, so # they end up getting ignored. This appends them to the very end of the link # line, ensuring they're always used. - find_package(X11) if (FREEBSD) target_link_libraries(clementine_lib ${X11_X11_LIB}) else () @@ -1433,9 +1430,6 @@ if (APPLE) install(FILES ../dist/cacert.pem DESTINATION "${CMAKE_BINARY_DIR}/clementine.app/Contents/Resources") - install(DIRECTORY "${QT_QTGUI_LIBRARY_RELEASE}/Versions/Current/Resources/" - DESTINATION "${CMAKE_BINARY_DIR}/clementine.app/Contents/Resources") - if (HAVE_BREAKPAD) install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../3rdparty/google-breakpad/client/mac/build/Release/Breakpad.framework diff --git a/src/analyzers/analyzerbase.h b/src/analyzers/analyzerbase.h index 9831575b6..e66ed0c1f 100644 --- a/src/analyzers/analyzerbase.h +++ b/src/analyzers/analyzerbase.h @@ -42,7 +42,7 @@ #ifdef HAVE_OPENGL #include -#ifdef Q_WS_MACX +#ifdef Q_OS_MACX #include #include #else diff --git a/src/core/application.cpp b/src/core/application.cpp index 75975c712..e3704df6a 100644 --- a/src/core/application.cpp +++ b/src/core/application.cpp @@ -20,6 +20,9 @@ along with Clementine. If not, see . */ +#include +#include + #include "application.h" #include "config.h" @@ -32,6 +35,7 @@ #include "covers/albumcoverloader.h" #include "covers/coverproviders.h" #include "covers/currentartloader.h" +#include "covers/discogscoverprovider.h" #include "covers/musicbrainzcoverprovider.h" #include "devices/devicemanager.h" #include "globalsearch/globalsearch.h" @@ -42,8 +46,8 @@ #include "internet/podcasts/podcastdeleter.h" #include "internet/podcasts/podcastdownloader.h" #include "internet/podcasts/podcastupdater.h" -#include "library/librarybackend.h" #include "library/library.h" +#include "library/librarybackend.h" #include "moodbar/moodbarcontroller.h" #include "moodbar/moodbarloader.h" #include "networkremote/networkremote.h" @@ -66,7 +70,8 @@ bool Application::kIsPortable = false; class ApplicationImpl { public: ApplicationImpl(Application* app) - : tag_reader_client_([=]() { + : settings_timer_(app), + tag_reader_client_([=]() { TagReaderClient* client = new TagReaderClient(app); app->MoveToNewThread(client); client->Start(); @@ -98,6 +103,7 @@ class ApplicationImpl { CoverProviders* cover_providers = new CoverProviders(app); // Initialize the repository of cover providers. cover_providers->AddProvider(new MusicbrainzCoverProvider); + cover_providers->AddProvider(new DiscogsCoverProvider); #ifdef HAVE_LIBLASTFM cover_providers->AddProvider(new LastFmCoverProvider(app)); #endif @@ -148,6 +154,9 @@ class ApplicationImpl { }) { } + QTimer settings_timer_; + QSettings settings_; + Lazy tag_reader_client_; Lazy database_; Lazy album_cover_loader_; @@ -186,6 +195,10 @@ Application::Application(QObject* parent) // TODO(John Maguire): Make this not a weird singleton. tag_reader_client(); + + p_->settings_timer_.setInterval(1000); + p_->settings_timer_.setSingleShot(true); + connect(&(p_->settings_timer_), SIGNAL(timeout()), SLOT(SaveSettings_())); } Application::~Application() { @@ -227,6 +240,8 @@ QString Application::language_without_region() const { return language_name_; } +void Application::SaveSettings_() { emit SaveSettings(&(p_->settings_)); } + void Application::ReloadSettings() { emit SettingsChanged(); } void Application::OpenSettingsDialogAtPage(SettingsDialog::Page page) { @@ -324,3 +339,5 @@ TagReaderClient* Application::tag_reader_client() const { TaskManager* Application::task_manager() const { return p_->task_manager_.get(); } + +void Application::DirtySettings() { p_->settings_timer_.start(); } diff --git a/src/core/application.h b/src/core/application.h index 679c45335..1c1a1cb07 100644 --- a/src/core/application.h +++ b/src/core/application.h @@ -28,6 +28,8 @@ #include "ui/settingsdialog.h" +class QSettings; + class AlbumCoverLoader; class Appearance; class ApplicationImpl; @@ -98,6 +100,8 @@ class Application : public QObject { TagReaderClient* tag_reader_client() const; TaskManager* task_manager() const; + void DirtySettings(); + void MoveToNewThread(QObject* object); void MoveToThread(QObject* object, QThread* thread); @@ -109,8 +113,12 @@ class Application : public QObject { signals: void ErrorAdded(const QString& message); void SettingsChanged(); + void SaveSettings(QSettings* settings); void SettingsDialogRequested(SettingsDialog::Page page); + private slots: + void SaveSettings_(); + private: QString language_name_; std::unique_ptr p_; diff --git a/src/core/commandlineoptions.cpp b/src/core/commandlineoptions.cpp index 00089ac71..0919789e5 100644 --- a/src/core/commandlineoptions.cpp +++ b/src/core/commandlineoptions.cpp @@ -327,11 +327,11 @@ QByteArray CommandlineOptions::Serialize() const { s << *this; buf.close(); - return buf.data(); + return buf.data().toBase64(); } void CommandlineOptions::Load(const QByteArray& serialized) { - QByteArray copy(serialized); + QByteArray copy = QByteArray::fromBase64(serialized); QBuffer buf(©); buf.open(QIODevice::ReadOnly); diff --git a/src/core/commandlineoptions.h b/src/core/commandlineoptions.h index 5f5b32115..b18f139fc 100644 --- a/src/core/commandlineoptions.h +++ b/src/core/commandlineoptions.h @@ -33,7 +33,7 @@ class CommandlineOptions { friend QDataStream& operator>>(QDataStream& s, CommandlineOptions& a); public: - explicit CommandlineOptions(int argc = 0, char* *argv = nullptr); + explicit CommandlineOptions(int argc = 0, char** argv = nullptr); static const char* kHelpText; static const char* kVersionText; diff --git a/src/core/database.cpp b/src/core/database.cpp index caa227b49..aef879679 100644 --- a/src/core/database.cpp +++ b/src/core/database.cpp @@ -281,13 +281,14 @@ QSqlDatabase Database::Connect() { } #endif - QSqlQuery set_fts_tokenizer("SELECT fts3_tokenizer(:name, :pointer)", db); + QSqlQuery set_fts_tokenizer(db); + set_fts_tokenizer.prepare("SELECT fts3_tokenizer(:name, :pointer)"); set_fts_tokenizer.bindValue(":name", "unicode"); set_fts_tokenizer.bindValue( ":pointer", QByteArray(reinterpret_cast(&sFTSTokenizer), sizeof(&sFTSTokenizer))); if (!set_fts_tokenizer.exec()) { - qLog(Warning) << "Couldn't register FTS3 tokenizer"; + qLog(Warning) << "Couldn't register FTS3 tokenizer : " << set_fts_tokenizer.lastError(); } // Implicit invocation of ~QSqlQuery() when leaving the scope // to release any remaining database locks! @@ -306,12 +307,13 @@ QSqlDatabase Database::Connect() { if (!injected_database_name_.isNull()) filename = injected_database_name_; // Attach the db - QSqlQuery q("ATTACH DATABASE :filename AS :alias", db); + QSqlQuery q(db); + q.prepare("ATTACH DATABASE :filename AS :alias"); q.bindValue(":filename", filename); q.bindValue(":alias", key); if (!q.exec()) { qFatal("Couldn't attach external database '%s'", - key.toAscii().constData()); + key.toLatin1().constData()); } } @@ -326,10 +328,10 @@ QSqlDatabase Database::Connect() { attached_databases_[key].schema_.isEmpty()) continue; // Find out if there are any tables in this database - QSqlQuery q(QString( + QSqlQuery q(db); + q.prepare(QString( "SELECT ROWID FROM %1.sqlite_master" - " WHERE type='table'").arg(key), - db); + " WHERE type='table'").arg(key)); if (!q.exec() || !q.next()) { q.finish(); ExecSchemaCommandsFromFile(db, attached_databases_[key].schema_, 0); @@ -376,7 +378,8 @@ void Database::RecreateAttachedDb(const QString& database_name) { { QSqlDatabase db(Connect()); - QSqlQuery q("DETACH DATABASE :alias", db); + QSqlQuery q(db); + q.prepare("DETACH DATABASE :alias"); q.bindValue(":alias", database_name); if (!q.exec()) { qLog(Warning) << "Failed to detach database" << database_name; @@ -407,12 +410,13 @@ void Database::AttachDatabaseOnDbConnection(const QString& database_name, AttachDatabase(database_name, database); // Attach the db - QSqlQuery q("ATTACH DATABASE :filename AS :alias", db); + QSqlQuery q(db); + q.prepare("ATTACH DATABASE :filename AS :alias"); q.bindValue(":filename", database.filename_); q.bindValue(":alias", database_name); if (!q.exec()) { qFatal("Couldn't attach external database '%s'", - database_name.toAscii().constData()); + database_name.toLatin1().constData()); } } @@ -421,7 +425,8 @@ void Database::DetachDatabase(const QString& database_name) { { QSqlDatabase db(Connect()); - QSqlQuery q("DETACH DATABASE :alias", db); + QSqlQuery q(db); + q.prepare("DETACH DATABASE :alias"); q.bindValue(":alias", database_name); if (!q.exec()) { qLog(Warning) << "Failed to detach database" << database_name; @@ -464,10 +469,10 @@ void Database::UpdateDatabaseSchema(int version, QSqlDatabase& db) { } void Database::UrlEncodeFilenameColumn(const QString& table, QSqlDatabase& db) { - QSqlQuery select(QString("SELECT ROWID, filename FROM %1").arg(table), db); - QSqlQuery update( - QString("UPDATE %1 SET filename=:filename WHERE ROWID=:id").arg(table), - db); + QSqlQuery select(db); + select.prepare(QString("SELECT ROWID, filename FROM %1").arg(table)); + QSqlQuery update(db); + update.prepare(QString("UPDATE %1 SET filename=:filename WHERE ROWID=:id").arg(table)); select.exec(); if (CheckErrors(select)) return; while (select.next()) { @@ -561,12 +566,11 @@ QStringList Database::SongsTables(QSqlDatabase& db, int schema_version) const { // look for the tables in attached dbs for (const QString& key : attached_databases_.keys()) { - QSqlQuery q( - QString( + QSqlQuery q(db); + q.prepare(QString( "SELECT NAME FROM %1.sqlite_master" " WHERE type='table' AND name='songs' OR name LIKE '%songs'") - .arg(key), - db); + .arg(key)); if (q.exec()) { while (q.next()) { QString tab_name = key + "." + q.value(0).toString(); @@ -603,7 +607,7 @@ bool Database::IntegrityCheck(QSqlDatabase db) { bool ok = false; bool error_reported = false; // Ask for 10 error messages at most. - QSqlQuery q(QString("PRAGMA integrity_check(10)"), db); + QSqlQuery q("PRAGMA integrity_check(10)", db); while (q.next()) { QString message = q.value(0).toString(); diff --git a/src/core/mergedproxymodel.cpp b/src/core/mergedproxymodel.cpp index 97a151cc9..703df79c4 100644 --- a/src/core/mergedproxymodel.cpp +++ b/src/core/mergedproxymodel.cpp @@ -184,12 +184,14 @@ void MergedProxyModel::SourceModelReset() { // Delete all mappings DeleteAllMappings(); + // Reset the proxy + beginResetModel(); + // Clear the containers p_->mappings_.clear(); merge_points_.clear(); - // Reset the proxy - reset(); + endResetModel(); } void MergedProxyModel::SubModelReset() { @@ -498,7 +500,8 @@ void MergedProxyModel::LayoutChanged() { const int new_row = merge_points_[key].row(); if (old_row != new_row) { - reset(); + beginResetModel(); + endResetModel(); return; } } diff --git a/src/core/metatypes.cpp b/src/core/metatypes.cpp index 4c5337e88..e6584568a 100644 --- a/src/core/metatypes.cpp +++ b/src/core/metatypes.cpp @@ -30,6 +30,7 @@ #include "covers/albumcoverfetcher.h" #include "engines/enginebase.h" #include "engines/gstengine.h" +#include "engines/gstenginepipeline.h" #include "globalsearch/searchprovider.h" #include "internet/core/geolocator.h" #include "internet/digitally/digitallyimportedclient.h" @@ -53,7 +54,6 @@ class QNetworkReply; void RegisterMetaTypes() { qRegisterMetaType("CollapsibleInfoPane::Data"); - qRegisterMetaType("ColumnAlignmentMap"); qRegisterMetaType("const char*"); qRegisterMetaType("CoverSearchResult"); qRegisterMetaType("CoverSearchResults"); @@ -110,6 +110,7 @@ void RegisterMetaTypes() { qRegisterMetaType("SubdirectoryList"); qRegisterMetaType("Subdirectory"); qRegisterMetaType>("QList"); + qRegisterMetaType(); qRegisterMetaType("QFileInfo"); #ifdef HAVE_DBUS diff --git a/src/core/organiseformat.h b/src/core/organiseformat.h index e24a22461..77005794c 100644 --- a/src/core/organiseformat.h +++ b/src/core/organiseformat.h @@ -22,6 +22,7 @@ #include #include +#include #include "core/song.h" diff --git a/src/core/potranslator.h b/src/core/potranslator.h index eafdccf2f..e92ba3429 100644 --- a/src/core/potranslator.h +++ b/src/core/potranslator.h @@ -29,7 +29,7 @@ class PoTranslator : public QTranslator { public: QString translate(const char* context, const char* source_text, - const char* disambiguation = 0) const { + const char* disambiguation = 0, int n = -1) const { QString ret = QTranslator::translate(context, source_text, disambiguation); if (!ret.isEmpty()) return ret; return QTranslator::translate(nullptr, source_text, disambiguation); diff --git a/src/core/qhash_qurl.h b/src/core/qhash_qurl.h deleted file mode 100644 index d7d2924c3..000000000 --- a/src/core/qhash_qurl.h +++ /dev/null @@ -1,29 +0,0 @@ -/* This file is part of Clementine. - Copyright 2012, David Sansome - Copyright 2014, Krzysztof Sobiecki - Copyright 2014, John Maguire - - Clementine is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Clementine is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Clementine. If not, see . -*/ - -#ifndef CORE_QHASH_QURL_H_ -#define CORE_QHASH_QURL_H_ - -#include - -#if QT_VERSION < 0x040700 -inline uint qHash(const QUrl& url) { return qHash(url.toEncoded()); } -#endif - -#endif // CORE_QHASH_QURL_H_ diff --git a/src/core/qxtglobalshortcutbackend.cpp b/src/core/qxtglobalshortcutbackend.cpp index f33b3e325..c04e41d4a 100644 --- a/src/core/qxtglobalshortcutbackend.cpp +++ b/src/core/qxtglobalshortcutbackend.cpp @@ -40,7 +40,6 @@ bool QxtGlobalShortcutBackend::DoRegister() { void QxtGlobalShortcutBackend::AddShortcut(QAction* action) { if (action->shortcut().isEmpty()) return; - QxtGlobalShortcut* shortcut = new QxtGlobalShortcut(action->shortcut(), this); connect(shortcut, SIGNAL(activated()), action, SLOT(trigger())); shortcuts_ << shortcut; diff --git a/src/core/qxtglobalshortcutbackend.h b/src/core/qxtglobalshortcutbackend.h index 32361291c..4976241c5 100644 --- a/src/core/qxtglobalshortcutbackend.h +++ b/src/core/qxtglobalshortcutbackend.h @@ -23,6 +23,7 @@ #include "globalshortcutbackend.h" class QxtGlobalShortcut; +class QAction; class QxtGlobalShortcutBackend : public GlobalShortcutBackend { public: diff --git a/src/core/song.cpp b/src/core/song.cpp index 01b320fe9..d8882c6e5 100644 --- a/src/core/song.cpp +++ b/src/core/song.cpp @@ -45,9 +45,9 @@ #ifdef HAVE_LIBLASTFM #include "internet/lastfm/fixlastfm.h" #ifdef HAVE_LIBLASTFM1 -#include +#include #else -#include +#include #endif #endif diff --git a/src/core/tagreaderclient.cpp b/src/core/tagreaderclient.cpp index 96434be52..853c2733e 100644 --- a/src/core/tagreaderclient.cpp +++ b/src/core/tagreaderclient.cpp @@ -18,6 +18,7 @@ along with Clementine. If not, see . */ +#include "player.h" #include "tagreaderclient.h" #include @@ -34,8 +35,14 @@ TagReaderClient::TagReaderClient(QObject* parent) : QObject(parent), worker_pool_(new WorkerPool(this)) { sInstance = this; + QSettings s; + s.beginGroup(Player::kSettingsGroup); + + int max_workers = QThread::idealThreadCount(); + int num_workers = s.value("max_numprocs_tagclients", max_workers).toInt(); + worker_pool_->SetExecutableName(kWorkerExecutableName); - worker_pool_->SetWorkerCount(QThread::idealThreadCount()); + worker_pool_->SetWorkerCount(num_workers); connect(worker_pool_, SIGNAL(WorkerFailedToStart()), SLOT(WorkerFailedToStart())); } diff --git a/src/core/utilities.cpp b/src/core/utilities.cpp index b78008b2b..e0383b4e1 100644 --- a/src/core/utilities.cpp +++ b/src/core/utilities.cpp @@ -52,8 +52,6 @@ #include "config.h" #include "timeconstants.h" -#include "sha2.h" - #if defined(Q_OS_UNIX) #include #elif defined(Q_OS_WIN32) @@ -467,7 +465,10 @@ QByteArray Hmac(const QByteArray& key, const QByteArray& data, QCryptographicHash::Sha1), QCryptographicHash::Sha1); } else { // Sha256_Algo, currently default - return Sha256(outer_padding + Sha256(inner_padding + data)); + return QCryptographicHash::hash( + outer_padding + QCryptographicHash::hash(inner_padding + data, + QCryptographicHash::Sha256), + QCryptographicHash::Sha256); } } @@ -483,26 +484,6 @@ QByteArray HmacSha1(const QByteArray& key, const QByteArray& data) { return Hmac(key, data, Sha1_Algo); } -QByteArray Sha256(const QByteArray& data) { -#ifndef USE_SYSTEM_SHA2 - using clementine_sha2::SHA256_CTX; - using clementine_sha2::SHA256_Init; - using clementine_sha2::SHA256_Update; - using clementine_sha2::SHA256_Final; - using clementine_sha2::SHA256_DIGEST_LENGTH; -#endif - - SHA256_CTX context; - SHA256_Init(&context); - SHA256_Update(&context, reinterpret_cast(data.constData()), - data.length()); - - QByteArray ret(SHA256_DIGEST_LENGTH, '\0'); - SHA256_Final(reinterpret_cast(ret.data()), &context); - - return ret; -} - // File must not be open and will be closed afterwards! QByteArray Sha1File(QFile& file) { file.open(QIODevice::ReadOnly); @@ -715,16 +696,12 @@ bool IsLaptop() { } QString SystemLanguageName() { -#if QT_VERSION >= 0x040800 QString system_language = QLocale::system().uiLanguages().empty() ? QLocale::system().name() : QLocale::system().uiLanguages().first(); // uiLanguages returns strings with "-" as separators for language/region; // however QTranslator needs "_" separators system_language.replace("-", "_"); -#else - QString system_language = QLocale::system().name(); -#endif return system_language; } diff --git a/src/core/utilities.h b/src/core/utilities.h index 7345a1140..021ded6cf 100644 --- a/src/core/utilities.h +++ b/src/core/utilities.h @@ -74,7 +74,6 @@ QByteArray Hmac(const QByteArray& key, const QByteArray& data, QByteArray HmacMd5(const QByteArray& key, const QByteArray& data); QByteArray HmacSha256(const QByteArray& key, const QByteArray& data); QByteArray HmacSha1(const QByteArray& key, const QByteArray& data); -QByteArray Sha256(const QByteArray& data); QByteArray Sha1File(QFile& file); QByteArray Sha1CoverHash(const QString& artist, const QString& album); diff --git a/src/covers/albumcoverfetcher.cpp b/src/covers/albumcoverfetcher.cpp index f32305eb3..3c409bb64 100644 --- a/src/covers/albumcoverfetcher.cpp +++ b/src/covers/albumcoverfetcher.cpp @@ -40,12 +40,14 @@ AlbumCoverFetcher::AlbumCoverFetcher(CoverProviders* cover_providers, } quint64 AlbumCoverFetcher::FetchAlbumCover(const QString& artist, - const QString& album) { + const QString& album, + bool fetchall) { CoverSearchRequest request; request.artist = artist; request.album = album; request.search = false; request.id = next_id_++; + request.fetchall = fetchall; AddRequest(request); return request.id; @@ -58,6 +60,7 @@ quint64 AlbumCoverFetcher::SearchForCovers(const QString& artist, request.album = album; request.search = true; request.id = next_id_++; + request.fetchall = false; AddRequest(request); return request.id; diff --git a/src/covers/albumcoverfetcher.h b/src/covers/albumcoverfetcher.h index 75e51161c..588c7ea2e 100644 --- a/src/covers/albumcoverfetcher.h +++ b/src/covers/albumcoverfetcher.h @@ -51,6 +51,9 @@ struct CoverSearchRequest { // is this only a search request or should we also fetch the first // cover that's found? bool search; + + // is the request part of fetchall (fetching all missing covers) + bool fetchall; }; // This structure represents a single result of some album's cover search @@ -88,7 +91,8 @@ class AlbumCoverFetcher : public QObject { static const int kMaxConcurrentRequests; quint64 SearchForCovers(const QString& artist, const QString& album); - quint64 FetchAlbumCover(const QString& artist, const QString& album); + quint64 FetchAlbumCover(const QString& artist, const QString& album, + bool fetchall); void Clear(); diff --git a/src/covers/albumcoverfetchersearch.cpp b/src/covers/albumcoverfetchersearch.cpp index 47bca2b61..1e3237207 100644 --- a/src/covers/albumcoverfetchersearch.cpp +++ b/src/covers/albumcoverfetchersearch.cpp @@ -64,6 +64,11 @@ void AlbumCoverFetcherSearch::TerminateSearch() { void AlbumCoverFetcherSearch::Start(CoverProviders* cover_providers) { for (CoverProvider* provider : cover_providers->List()) { + // Skip provider if it does not have fetchall set, and we are doing fetchall + // - "Fetch Missing Covers". + if (!provider->fetchall() && request_.fetchall) { + continue; + } connect(provider, SIGNAL(SearchFinished(int, QList)), SLOT(ProviderSearchFinished(int, QList))); const int id = cover_providers->NextId(); diff --git a/src/covers/albumcoverloader.cpp b/src/covers/albumcoverloader.cpp index fd48f044f..a04cd923a 100644 --- a/src/covers/albumcoverloader.cpp +++ b/src/covers/albumcoverloader.cpp @@ -202,6 +202,10 @@ AlbumCoverLoader::TryLoadResult AlbumCoverLoader::TryLoadImage( return TryLoadResult(true, false, QImage()); } #endif + else if (filename.isEmpty()) { + // Avoid "QFSFileEngine::open: No file name specified" messages if we know that the filename is empty + return TryLoadResult(false, false, task.options.default_output_image_); + } QImage image(filename); return TryLoadResult( diff --git a/src/covers/coverprovider.cpp b/src/covers/coverprovider.cpp index 17dd8a262..247109dfe 100644 --- a/src/covers/coverprovider.cpp +++ b/src/covers/coverprovider.cpp @@ -19,5 +19,6 @@ #include "coverprovider.h" -CoverProvider::CoverProvider(const QString& name, QObject* parent) - : QObject(parent), name_(name) {} +CoverProvider::CoverProvider(const QString& name, const bool& fetchall, + QObject* parent) + : QObject(parent), name_(name), fetchall_(fetchall) {} diff --git a/src/covers/coverprovider.h b/src/covers/coverprovider.h index c87ad5dae..040eaa201 100644 --- a/src/covers/coverprovider.h +++ b/src/covers/coverprovider.h @@ -35,10 +35,12 @@ class CoverProvider : public QObject { Q_OBJECT public: - explicit CoverProvider(const QString& name, QObject* parent); + explicit CoverProvider(const QString& name, const bool& fetchall, + QObject* parent); // A name (very short description) of this provider, like "last.fm". QString name() const { return name_; } + bool fetchall() const { return fetchall_; } // Starts searching for covers matching the given query text. Returns true // if the query has been started, or false if an error occurred. The provider @@ -53,6 +55,7 @@ class CoverProvider : public QObject { private: QString name_; + bool fetchall_; }; #endif // COVERS_COVERPROVIDER_H_ diff --git a/src/covers/currentartloader.cpp b/src/covers/currentartloader.cpp index 2cbc7f197..ab43fad46 100644 --- a/src/covers/currentartloader.cpp +++ b/src/covers/currentartloader.cpp @@ -61,7 +61,7 @@ void CurrentArtLoader::TempArtLoaded(quint64 id, const QImage& image) { QString thumbnail_uri; QImage thumbnail; - if (!image.isNull()) { + if (image != options_.default_output_image_) { temp_art_.reset(new QTemporaryFile(temp_file_pattern_)); temp_art_->setAutoRemove(true); temp_art_->open(); diff --git a/src/covers/discogscoverprovider.cpp b/src/covers/discogscoverprovider.cpp new file mode 100644 index 000000000..95e00fe28 --- /dev/null +++ b/src/covers/discogscoverprovider.cpp @@ -0,0 +1,323 @@ +/* This file is part of Clementine. + Copyright 2012, Martin Björklund + Copyright 2018, Jonas Kvinge + + Clementine is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Clementine is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Clementine. If not, see . +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "discogscoverprovider.h" + +#include "core/closure.h" +#include "core/logging.h" +#include "core/network.h" +#include "core/utilities.h" + +const char* DiscogsCoverProvider::kUrlSearch = + "https://api.discogs.com/database/search"; +const char* DiscogsCoverProvider::kUrlReleases = + "https://api.discogs.com/releases"; + +const char* DiscogsCoverProvider::kAccessKeyB64 = + "YVR4Yk5JTnlmUkhFY0pTaldid2c="; +const char* DiscogsCoverProvider::kSecretKeyB64 = + "QkJNb2tMVXVUVFhSRWRUVmZDc0ZGamZmSWRjdHZRVno="; + +DiscogsCoverProvider::DiscogsCoverProvider(QObject* parent) + : CoverProvider("Discogs", false, parent), + network_(new NetworkAccessManager(this)) {} + +bool DiscogsCoverProvider::StartSearch(const QString& artist, + const QString& album, int s_id) { + DiscogsCoverSearchContext* s_ctx = new DiscogsCoverSearchContext; + + s_ctx->id = s_id; + s_ctx->artist = artist; + s_ctx->album = album; + s_ctx->r_count = 0; + requests_search_.insert(s_id, s_ctx); + SendSearchRequest(s_ctx); + + return true; +} + +void DiscogsCoverProvider::CancelSearch(int id) { + delete requests_search_.take(id); +} + +bool DiscogsCoverProvider::StartRelease(DiscogsCoverSearchContext* s_ctx, + int r_id, QString resource_url) { + DiscogsCoverReleaseContext* r_ctx = new DiscogsCoverReleaseContext; + + s_ctx->r_count++; + + r_ctx->id = r_id; + r_ctx->resource_url = resource_url; + + r_ctx->s_id = s_ctx->id; + + requests_release_.insert(r_id, r_ctx); + SendReleaseRequest(s_ctx, r_ctx); + + return true; +} + +void DiscogsCoverProvider::SendSearchRequest(DiscogsCoverSearchContext* s_ctx) { + typedef QPair Arg; + typedef QList ArgList; + + typedef QPair EncodedArg; + typedef QList EncodedArgList; + + ArgList args = + ArgList() << Arg("key", QByteArray::fromBase64(kAccessKeyB64)) + << Arg("secret", QByteArray::fromBase64(kSecretKeyB64)); + + args.append(Arg("type", "release")); + if (!s_ctx->artist.isEmpty()) { + args.append(Arg("artist", s_ctx->artist.toLower())); + } + if (!s_ctx->album.isEmpty()) { + args.append(Arg("release_title", s_ctx->album.toLower())); + } + + QUrlQuery url_query; + QUrl url(kUrlSearch); + QStringList query_items; + + // Encode the arguments + for (const Arg& arg : args) { + EncodedArg encoded_arg(QUrl::toPercentEncoding(arg.first), + QUrl::toPercentEncoding(arg.second)); + query_items << QString(encoded_arg.first + "=" + encoded_arg.second); + url_query.addQueryItem(encoded_arg.first, encoded_arg.second); + } + + // Sign the request + const QByteArray data_to_sign = + QString("GET\n%1\n%2\n%3") + .arg(url.host(), url.path(), query_items.join("&")) + .toUtf8(); + const QByteArray signature(Utilities::HmacSha256( + QByteArray::fromBase64(kSecretKeyB64), data_to_sign)); + + // Add the signature to the request + url_query.addQueryItem("Signature", + QUrl::toPercentEncoding(signature.toBase64())); + + url.setQuery(url_query); + QNetworkReply* reply = network_->get(QNetworkRequest(url)); + + NewClosure(reply, SIGNAL(error(QNetworkReply::NetworkError)), this, + SLOT(SearchRequestError(QNetworkReply::NetworkError, + QNetworkReply*, int)), + reply, s_ctx->id); + NewClosure(reply, SIGNAL(finished()), this, + SLOT(HandleSearchReply(QNetworkReply*, int)), reply, s_ctx->id); +} + +void DiscogsCoverProvider::SendReleaseRequest( + DiscogsCoverSearchContext* s_ctx, DiscogsCoverReleaseContext* r_ctx) { + typedef QPair Arg; + typedef QList ArgList; + + typedef QPair EncodedArg; + typedef QList EncodedArgList; + + QUrlQuery url_query; + QStringList query_items; + + ArgList args = + ArgList() << Arg("key", QByteArray::fromBase64(kAccessKeyB64)) + << Arg("secret", QByteArray::fromBase64(kSecretKeyB64)); + // Encode the arguments + for (const Arg& arg : args) { + EncodedArg encoded_arg(QUrl::toPercentEncoding(arg.first), + QUrl::toPercentEncoding(arg.second)); + query_items << QString(encoded_arg.first + "=" + encoded_arg.second); + url_query.addQueryItem(encoded_arg.first, encoded_arg.second); + } + + QUrl url(r_ctx->resource_url); + + // Sign the request + const QByteArray data_to_sign = + QString("GET\n%1\n%2\n%3") + .arg(url.host(), url.path(), query_items.join("&")) + .toUtf8(); + const QByteArray signature(Utilities::HmacSha256( + QByteArray::fromBase64(kSecretKeyB64), data_to_sign)); + + // Add the signature to the request + url_query.addQueryItem("Signature", + QUrl::toPercentEncoding(signature.toBase64())); + + url.setQuery(url_query); + QNetworkReply* reply = network_->get(QNetworkRequest(url)); + + NewClosure(reply, SIGNAL(error(QNetworkReply::NetworkError)), this, + SLOT(ReleaseRequestError(QNetworkReply::NetworkError, + QNetworkReply*, int, int)), + reply, s_ctx->id, r_ctx->id); + NewClosure(reply, SIGNAL(finished()), this, + SLOT(HandleReleaseReply(QNetworkReply*, int, int)), reply, + s_ctx->id, r_ctx->id); +} + +void DiscogsCoverProvider::HandleSearchReply(QNetworkReply* reply, int s_id) { + reply->deleteLater(); + + if (!requests_search_.contains(s_id)) return; + DiscogsCoverSearchContext* s_ctx = requests_search_.value(s_id); + + QJsonDocument json_doc = QJsonDocument::fromJson(reply->readAll()); + if ((json_doc.isNull()) || (!json_doc.isObject())) { + qLog(Error) << "Discogs: Failed to create JSON doc."; + EndSearch(s_ctx); + return; + } + + QJsonObject json_obj = json_doc.object(); + if (json_obj.isEmpty()) { + qLog(Error) << "Discogs: Failed to create JSON object."; + EndSearch(s_ctx); + return; + } + + QVariantMap reply_map = json_obj.toVariantMap(); + if (!reply_map.contains("results")) { + EndSearch(s_ctx); + return; + } + + QVariantList results = reply_map["results"].toList(); + int i = 0; + for (const QVariant& result : results) { + QVariantMap result_map = result.toMap(); + if ((result_map.contains("id")) && (result_map.contains("resource_url"))) { + int r_id = result_map["id"].toInt(); + QString title = result_map["title"].toString(); + QString resource_url = result_map["resource_url"].toString(); + if (resource_url.isEmpty()) continue; + StartRelease(s_ctx, r_id, resource_url); + i++; + } + } + if (i <= 0) EndSearch(s_ctx); +} + +void DiscogsCoverProvider::HandleReleaseReply(QNetworkReply* reply, int s_id, + int r_id) { + reply->deleteLater(); + + if (!requests_release_.contains(r_id)) return; + DiscogsCoverReleaseContext* r_ctx = requests_release_.value(r_id); + + if (!requests_search_.contains(s_id)) { + EndSearch(r_ctx); + return; + } + DiscogsCoverSearchContext* s_ctx = requests_search_.value(s_id); + + QJsonDocument json_doc = QJsonDocument::fromJson(reply->readAll()); + if ((json_doc.isNull()) || (!json_doc.isObject())) { + qLog(Error) << "Discogs: Failed to create JSON doc."; + EndSearch(s_ctx, r_ctx); + return; + } + QJsonObject json_obj = json_doc.object(); + if (json_obj.isEmpty()) { + qLog(Error) << "Discogs: JSON object is empty."; + EndSearch(s_ctx, r_ctx); + return; + } + + QVariantMap reply_map = json_obj.toVariantMap(); + if (!reply_map.contains("images")) { + EndSearch(s_ctx, r_ctx); + return; + } + + QVariantList results = reply_map["images"].toList(); + + for (const QVariant& result : results) { + QVariantMap result_map = result.toMap(); + CoverSearchResult cover_result; + cover_result.description = s_ctx->title; + + if (result_map.contains("type")) { + QString type = result_map["type"].toString(); + if (type != "primary") continue; + } + if (result_map.contains("resource_url")) { + cover_result.image_url = QUrl(result_map["resource_url"].toString()); + } + if (cover_result.image_url.isEmpty()) continue; + s_ctx->results.append(cover_result); + } + + EndSearch(s_ctx, r_ctx); +} + +void DiscogsCoverProvider::SearchRequestError(QNetworkReply::NetworkError error, + QNetworkReply* reply, int s_id) { + if (!requests_search_.contains(s_id)) return; + DiscogsCoverSearchContext* s_ctx = requests_search_.value(s_id); + + EndSearch(s_ctx); +} + +void DiscogsCoverProvider::ReleaseRequestError( + QNetworkReply::NetworkError error, QNetworkReply* reply, int s_id, + int r_id) { + if (!requests_release_.contains(r_id)) return; + DiscogsCoverReleaseContext* r_ctx = requests_release_.value(r_id); + + if (!requests_search_.contains(s_id)) { + EndSearch(r_ctx); + return; + } + DiscogsCoverSearchContext* s_ctx = requests_search_.value(s_id); + EndSearch(s_ctx, r_ctx); +} + +void DiscogsCoverProvider::EndSearch(DiscogsCoverSearchContext* s_ctx, + DiscogsCoverReleaseContext* r_ctx) { + delete requests_release_.take(r_ctx->id); + + s_ctx->r_count--; + + if (s_ctx->r_count <= 0) EndSearch(s_ctx); +} + +void DiscogsCoverProvider::EndSearch(DiscogsCoverSearchContext* s_ctx) { + requests_search_.remove(s_ctx->id); + emit SearchFinished(s_ctx->id, s_ctx->results); + delete s_ctx; +} + +void DiscogsCoverProvider::EndSearch(DiscogsCoverReleaseContext* r_ctx) { + delete requests_release_.take(r_ctx->id); +} diff --git a/src/covers/discogscoverprovider.h b/src/covers/discogscoverprovider.h new file mode 100644 index 000000000..3b16c0597 --- /dev/null +++ b/src/covers/discogscoverprovider.h @@ -0,0 +1,94 @@ +/* This file is part of Clementine. + Copyright 2012, Martin Björklund + Copyright 2018, Jonas Kvinge + + Clementine is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Clementine is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Clementine. If not, see . +*/ + +#ifndef COVERS_DISCOGSCOVERPROVIDER_H +#define COVERS_DISCOGSCOVERPROVIDER_H + +#include +#include + +#include "coverprovider.h" + +class QNetworkAccessManager; + +// This struct represents a single search request. It identifies and describes +// the request. +struct DiscogsCoverSearchContext { + // the unique request identifier + int id; + + // the search query + QString artist; + QString album; + QString title; + int r_count; + + CoverSearchResults results; +}; +Q_DECLARE_METATYPE(DiscogsCoverSearchContext) + +// This struct represents a single release request. It identifies and describes +// the request. +struct DiscogsCoverReleaseContext { + int id; // the unique request identifier + int s_id; // the search request identifier + + QString resource_url; +}; +Q_DECLARE_METATYPE(DiscogsCoverReleaseContext) + +class DiscogsCoverProvider : public CoverProvider { + Q_OBJECT + + public: + explicit DiscogsCoverProvider(QObject* parent = nullptr); + + bool StartSearch(const QString& artist, const QString& album, int s_id); + void CancelSearch(int id); + + private slots: + void SearchRequestError(QNetworkReply::NetworkError error, + QNetworkReply* reply, int s_id); + void ReleaseRequestError(QNetworkReply::NetworkError error, + QNetworkReply* reply, int s_id, int r_id); + void HandleSearchReply(QNetworkReply* reply, int s_id); + void HandleReleaseReply(QNetworkReply* reply, int s_id, int r_id); + + private: + static const char* kUrlSearch; + static const char* kUrlReleases; + static const char* kAccessKeyB64; + static const char* kSecretKeyB64; + + QNetworkAccessManager* network_; + QHash requests_search_; + QHash requests_release_; + + bool StartRelease(DiscogsCoverSearchContext* s_ctx, int r_id, + QString resource_url); + + void SendSearchRequest(DiscogsCoverSearchContext* s_ctx); + void SendReleaseRequest(DiscogsCoverSearchContext* s_ctx, + DiscogsCoverReleaseContext* r_ctx); + void EndSearch(DiscogsCoverSearchContext* s_ctx, + DiscogsCoverReleaseContext* r_ctx); + void EndSearch(DiscogsCoverSearchContext* s_ctx); + void EndSearch(DiscogsCoverReleaseContext* r_ctx); +}; + +#endif // COVERS_DISCOGSCOVERPROVIDER_H diff --git a/src/covers/lastfmcoverprovider.cpp b/src/covers/lastfmcoverprovider.cpp index 545e2511f..d0ee14d91 100644 --- a/src/covers/lastfmcoverprovider.cpp +++ b/src/covers/lastfmcoverprovider.cpp @@ -29,7 +29,7 @@ #include "internet/lastfm/lastfmcompat.h" LastFmCoverProvider::LastFmCoverProvider(QObject* parent) - : CoverProvider("last.fm", parent) {} + : CoverProvider("last.fm", true, parent) {} bool LastFmCoverProvider::StartSearch(const QString& artist, const QString& album, int id) { diff --git a/src/covers/musicbrainzcoverprovider.cpp b/src/covers/musicbrainzcoverprovider.cpp index 827bd085c..73d945e38 100644 --- a/src/covers/musicbrainzcoverprovider.cpp +++ b/src/covers/musicbrainzcoverprovider.cpp @@ -22,6 +22,7 @@ #include #include +#include #include "core/closure.h" #include "core/network.h" @@ -36,7 +37,7 @@ static const char* kAlbumCoverUrl = } // namespace MusicbrainzCoverProvider::MusicbrainzCoverProvider(QObject* parent) - : CoverProvider("MusicBrainz", parent), + : CoverProvider("MusicBrainz", true, parent), network_(new NetworkAccessManager(this)) {} bool MusicbrainzCoverProvider::StartSearch(const QString& artist, @@ -46,8 +47,10 @@ bool MusicbrainzCoverProvider::StartSearch(const QString& artist, QString query = QString("release:\"%1\" AND artist:\"%2\"") .arg(album.trimmed().replace('"', "\\\"")) .arg(artist.trimmed().replace('"', "\\\"")); - url.addQueryItem("query", query); - url.addQueryItem("limit", "5"); + QUrlQuery url_query; + url_query.addQueryItem("query", query); + url_query.addQueryItem("limit", "5"); + url.setQuery(url_query); QNetworkRequest request(url); QNetworkReply* reply = network_->get(request); diff --git a/src/dbus/org.freedesktop.Avahi.EntryGroup.xml b/src/dbus/org.freedesktop.Avahi.EntryGroup.xml index 2930d7eeb..ec7f13742 100644 --- a/src/dbus/org.freedesktop.Avahi.EntryGroup.xml +++ b/src/dbus/org.freedesktop.Avahi.EntryGroup.xml @@ -51,7 +51,7 @@ - @@ -73,7 +73,7 @@ - diff --git a/src/dbus/org.freedesktop.Avahi.Server.xml b/src/dbus/org.freedesktop.Avahi.Server.xml index f336f207c..49493b3e0 100644 --- a/src/dbus/org.freedesktop.Avahi.Server.xml +++ b/src/dbus/org.freedesktop.Avahi.Server.xml @@ -132,7 +132,7 @@ - diff --git a/src/dbus/org.freedesktop.Notifications.xml b/src/dbus/org.freedesktop.Notifications.xml index 41f733009..00e85ea53 100644 --- a/src/dbus/org.freedesktop.Notifications.xml +++ b/src/dbus/org.freedesktop.Notifications.xml @@ -22,7 +22,7 @@ - + diff --git a/src/dbus/org.freedesktop.UDisks.Device.xml b/src/dbus/org.freedesktop.UDisks.Device.xml index 6f0a5807f..f93d4dfc2 100644 --- a/src/dbus/org.freedesktop.UDisks.Device.xml +++ b/src/dbus/org.freedesktop.UDisks.Device.xml @@ -636,7 +636,7 @@ - + An array of triples (pid, uid, command line for the process @@ -1355,9 +1355,9 @@ - - - + + + diff --git a/src/dbus/org.freedesktop.UDisks.xml b/src/dbus/org.freedesktop.UDisks.xml index 07daea04d..f046d64bf 100644 --- a/src/dbus/org.freedesktop.UDisks.xml +++ b/src/dbus/org.freedesktop.UDisks.xml @@ -1051,7 +1051,7 @@ - + An array of file systems known to the daemon and what features are supported. Each element in the array contains the following members: diff --git a/src/dbus/org.mpris.MediaPlayer2.Player.xml b/src/dbus/org.mpris.MediaPlayer2.Player.xml index 3c11567fa..711a74e47 100644 --- a/src/dbus/org.mpris.MediaPlayer2.Player.xml +++ b/src/dbus/org.mpris.MediaPlayer2.Player.xml @@ -27,7 +27,7 @@ - + diff --git a/src/dbus/org.mpris.MediaPlayer2.Playlists.xml b/src/dbus/org.mpris.MediaPlayer2.Playlists.xml index f94b31f2f..ef4c28a3c 100644 --- a/src/dbus/org.mpris.MediaPlayer2.Playlists.xml +++ b/src/dbus/org.mpris.MediaPlayer2.Playlists.xml @@ -6,7 +6,7 @@ - + @@ -17,12 +17,12 @@ - + - + - + diff --git a/src/dbus/org.mpris.MediaPlayer2.TrackList.xml b/src/dbus/org.mpris.MediaPlayer2.TrackList.xml index 51b4bbc6a..24fae962f 100644 --- a/src/dbus/org.mpris.MediaPlayer2.TrackList.xml +++ b/src/dbus/org.mpris.MediaPlayer2.TrackList.xml @@ -5,9 +5,8 @@ - - - + + @@ -25,9 +24,8 @@ - - - + + @@ -35,9 +33,8 @@ - - - + + diff --git a/src/devices/cddasongloader.cpp b/src/devices/cddasongloader.cpp index 54f204f4e..7b92c5d07 100644 --- a/src/devices/cddasongloader.cpp +++ b/src/devices/cddasongloader.cpp @@ -37,7 +37,7 @@ CddaSongLoader::~CddaSongLoader() { QUrl CddaSongLoader::GetUrlFromTrack(int track_number) const { if (url_.isEmpty()) { - return QUrl(QString("cdda://%1").arg(track_number)); + return QUrl(QString("cdda://%1a").arg(track_number)); } else { return QUrl(QString("cdda://%1/%2").arg(url_.path()).arg(track_number)); } diff --git a/src/devices/devicedatabasebackend.cpp b/src/devices/devicedatabasebackend.cpp index 14f28ed66..308805507 100644 --- a/src/devices/devicedatabasebackend.cpp +++ b/src/devices/devicedatabasebackend.cpp @@ -36,11 +36,10 @@ DeviceDatabaseBackend::DeviceList DeviceDatabaseBackend::GetAllDevices() { DeviceList ret; - QSqlQuery q( - "SELECT ROWID, unique_id, friendly_name, size, icon," + QSqlQuery q(db); + q.prepare("SELECT ROWID, unique_id, friendly_name, size, icon," " transcode_mode, transcode_format" - " FROM devices", - db); + " FROM devices"); q.exec(); if (db_->CheckErrors(q)) return ret; @@ -65,13 +64,12 @@ int DeviceDatabaseBackend::AddDevice(const Device& device) { ScopedTransaction t(&db); // Insert the device into the devices table - QSqlQuery q( - "INSERT INTO devices (" + QSqlQuery q(db); + q.prepare("INSERT INTO devices (" " unique_id, friendly_name, size, icon," " transcode_mode, transcode_format)" " VALUES (:unique_id, :friendly_name, :size, :icon," - " :transcode_mode, :transcode_format)", - db); + " :transcode_mode, :transcode_format)"); q.bindValue(":unique_id", device.unique_id_); q.bindValue(":friendly_name", device.friendly_name_); q.bindValue(":size", device.size_); @@ -103,7 +101,8 @@ void DeviceDatabaseBackend::RemoveDevice(int id) { ScopedTransaction t(&db); // Remove the device from the devices table - QSqlQuery q("DELETE FROM devices WHERE ROWID=:id", db); + QSqlQuery q(db); + q.prepare("DELETE FROM devices WHERE ROWID=:id"); q.bindValue(":id", id); q.exec(); if (db_->CheckErrors(q)) return; @@ -125,14 +124,13 @@ void DeviceDatabaseBackend::SetDeviceOptions(int id, QMutexLocker l(db_->Mutex()); QSqlDatabase db(db_->Connect()); - QSqlQuery q( - "UPDATE devices" + QSqlQuery q(db); + q.prepare("UPDATE devices" " SET friendly_name=:friendly_name," " icon=:icon_name," " transcode_mode=:transcode_mode," " transcode_format=:transcode_format" - " WHERE ROWID=:id", - db); + " WHERE ROWID=:id"); q.bindValue(":friendly_name", friendly_name); q.bindValue(":icon_name", icon_name); q.bindValue(":transcode_mode", mode); diff --git a/src/devices/deviceproperties.cpp b/src/devices/deviceproperties.cpp index 70fd872a6..a886f0f7f 100644 --- a/src/devices/deviceproperties.cpp +++ b/src/devices/deviceproperties.cpp @@ -154,7 +154,7 @@ void DeviceProperties::UpdateHardwareInfo() { AddHardwareInfo(row++, tr("Model"), lister->DeviceModel(id)); AddHardwareInfo(row++, tr("Manufacturer"), lister->DeviceManufacturer(id)); for (const QString& key : info.keys()) { - AddHardwareInfo(row++, tr(key.toAscii()), info[key].toString()); + AddHardwareInfo(row++, tr(key.toLatin1()), info[key].toString()); } ui_->hardware_info->sortItems(0); diff --git a/src/devices/deviceview.cpp b/src/devices/deviceview.cpp index c9e0beb2c..f4d45420f 100644 --- a/src/devices/deviceview.cpp +++ b/src/devices/deviceview.cpp @@ -56,9 +56,7 @@ void DeviceItemDelegate::paint(QPainter* p, const QStyleOptionViewItem& opt, } // Draw the background - const QStyleOptionViewItemV3* vopt = - qstyleoption_cast(&opt); - const QWidget* widget = vopt->widget; + const QWidget* widget = opt.widget; QStyle* style = widget->style() ? widget->style() : QApplication::style(); style->drawPrimitive(QStyle::PE_PanelItemViewItem, &opt, p, widget); diff --git a/src/devices/giolister.cpp b/src/devices/giolister.cpp index 5aac8dfbf..7021ba427 100644 --- a/src/devices/giolister.cpp +++ b/src/devices/giolister.cpp @@ -22,6 +22,7 @@ #include #include +#include #include #include "giolister.h" @@ -187,8 +188,10 @@ QList GioLister::MakeDeviceUrls(const QString& id) { if (url.isValid()) { QRegExp device_re("usb/(\\d+)/(\\d+)"); if (device_re.indexIn(unix_device) >= 0) { - url.addQueryItem("busnum", device_re.cap(1)); - url.addQueryItem("devnum", device_re.cap(2)); + QUrlQuery url_query(url); + url_query.addQueryItem("busnum", device_re.cap(1)); + url_query.addQueryItem("devnum", device_re.cap(2)); + url.setQuery(url_query); } // Special case for file:// GIO URIs - we have to check whether they point diff --git a/src/devices/macdevicelister.mm b/src/devices/macdevicelister.mm index e4d8934a8..2ac240776 100644 --- a/src/devices/macdevicelister.mm +++ b/src/devices/macdevicelister.mm @@ -42,11 +42,12 @@ #include -#include - -#include #include #include +#include +#include +#include +#include #ifndef kUSBSerialNumberString #define kUSBSerialNumberString "USB Serial Number" @@ -118,9 +119,9 @@ void MacDeviceLister::Init() { for (int i = 0; i < num; ++i) { LIBMTP_device_entry_t device = devices[i]; MTPDevice d; - d.vendor = QString::fromAscii(device.vendor); + d.vendor = QString::fromLatin1(device.vendor); d.vendor_id = device.vendor_id; - d.product = QString::fromAscii(device.product); + d.product = QString::fromLatin1(device.product); d.product_id = device.product_id; d.quirks = device.device_flags; sMTPDeviceList << d; @@ -305,7 +306,7 @@ QString GetSerialForMTPDevice(io_object_t device) { QString FindDeviceProperty(const QString& bsd_name, CFStringRef property) { ScopedCFTypeRef session(DASessionCreate(kCFAllocatorDefault)); ScopedCFTypeRef disk(DADiskCreateFromBSDName( - kCFAllocatorDefault, session.get(), bsd_name.toAscii().constData())); + kCFAllocatorDefault, session.get(), bsd_name.toLatin1().constData())); ScopedIOObject device(DADiskCopyIOMedia(disk.get())); QString ret = GetUSBRegistryEntryString(device.get(), property); @@ -358,7 +359,7 @@ void MacDeviceLister::DiskAddedCallback(DADiskRef disk, void* context) { #ifdef HAVE_AUDIOCD if (kind && strcmp([kind UTF8String], kIOCDMediaClass) == 0) { // CD inserted. - QString bsd_name = QString::fromAscii(DADiskGetBSDName(disk)); + QString bsd_name = QString::fromLatin1(DADiskGetBSDName(disk)); me->cd_devices_ << bsd_name; emit me->DeviceAdded(bsd_name); return; @@ -402,7 +403,7 @@ void MacDeviceLister::DiskRemovedCallback(DADiskRef disk, void* context) { // We cannot access the USB tree when the disk is removed but we still get // the BSD disk name. - QString bsd_name = QString::fromAscii(DADiskGetBSDName(disk)); + QString bsd_name = QString::fromLatin1(DADiskGetBSDName(disk)); if (me->cd_devices_.remove(bsd_name)) { emit me->DeviceRemoved(bsd_name); return; @@ -579,7 +580,7 @@ void MacDeviceLister::USBDeviceAddedCallback(void* refcon, io_iterator_t it) { 4, 256, &data); if (!ret || data.at(0) != 0x28) continue; - if (QString::fromAscii(data.data() + 0x12, 3) != "MTP") { + if (QString::fromLatin1(data.data() + 0x12, 3) != "MTP") { // Not quite. continue; } @@ -590,7 +591,7 @@ void MacDeviceLister::USBDeviceAddedCallback(void* refcon, io_iterator_t it) { continue; } - if (QString::fromAscii(data.data() + 0x12, 3) != "MTP") { + if (QString::fromLatin1(data.data() + 0x12, 3) != "MTP") { // Not quite. continue; } @@ -671,7 +672,7 @@ QString MacDeviceLister::MakeFriendlyName(const QString& serial) { IsCDDevice(serial) ? *cd_devices_.find(serial) : current_devices_[serial]; ScopedCFTypeRef session(DASessionCreate(kCFAllocatorDefault)); ScopedCFTypeRef disk(DADiskCreateFromBSDName( - kCFAllocatorDefault, session.get(), bsd_name.toAscii().constData())); + kCFAllocatorDefault, session.get(), bsd_name.toLatin1().constData())); if (IsCDDevice(serial)) { scoped_nsobject properties( @@ -700,12 +701,14 @@ QList MacDeviceLister::MakeDeviceUrls(const QString& serial) { const MTPDevice& device = mtp_devices_[serial]; QString str; str.sprintf("gphoto2://usb-%d-%d/", device.bus, device.address); + QUrlQuery url_query; + url_query.addQueryItem("vendor", device.vendor); + url_query.addQueryItem("vendor_id", QString::number(device.vendor_id)); + url_query.addQueryItem("product", device.product); + url_query.addQueryItem("product_id", QString::number(device.product_id)); + url_query.addQueryItem("quirks", QString::number(device.quirks)); QUrl url(str); - url.addQueryItem("vendor", device.vendor); - url.addQueryItem("vendor_id", QString::number(device.vendor_id)); - url.addQueryItem("product", device.product); - url.addQueryItem("product_id", QString::number(device.product_id)); - url.addQueryItem("quirks", QString::number(device.quirks)); + url.setQuery(url_query); return QList() << url; } @@ -716,7 +719,7 @@ QList MacDeviceLister::MakeDeviceUrls(const QString& serial) { QString bsd_name = current_devices_[serial]; ScopedCFTypeRef session(DASessionCreate(kCFAllocatorDefault)); ScopedCFTypeRef disk(DADiskCreateFromBSDName( - kCFAllocatorDefault, session.get(), bsd_name.toAscii().constData())); + kCFAllocatorDefault, session.get(), bsd_name.toLatin1().constData())); scoped_nsobject properties( (NSDictionary*)DADiskCopyDescription(disk.get())); @@ -745,7 +748,7 @@ QVariantList MacDeviceLister::DeviceIcons(const QString& serial) { QString bsd_name = current_devices_[serial]; ScopedCFTypeRef session(DASessionCreate(kCFAllocatorDefault)); ScopedCFTypeRef disk(DADiskCreateFromBSDName( - kCFAllocatorDefault, session.get(), bsd_name.toAscii().constData())); + kCFAllocatorDefault, session.get(), bsd_name.toLatin1().constData())); ScopedIOObject device(DADiskCopyIOMedia(disk.get())); QString icon = GetIconForDevice(device.get()); @@ -788,7 +791,7 @@ quint64 MacDeviceLister::DeviceCapacity(const QString& serial) { QString bsd_name = current_devices_[serial]; ScopedCFTypeRef session(DASessionCreate(kCFAllocatorDefault)); ScopedCFTypeRef disk(DADiskCreateFromBSDName( - kCFAllocatorDefault, session.get(), bsd_name.toAscii().constData())); + kCFAllocatorDefault, session.get(), bsd_name.toLatin1().constData())); io_object_t device = DADiskCopyIOMedia(disk); @@ -809,7 +812,7 @@ quint64 MacDeviceLister::DeviceFreeSpace(const QString& serial) { QString bsd_name = current_devices_[serial]; ScopedCFTypeRef session(DASessionCreate(kCFAllocatorDefault)); ScopedCFTypeRef disk(DADiskCreateFromBSDName( - kCFAllocatorDefault, session.get(), bsd_name.toAscii().constData())); + kCFAllocatorDefault, session.get(), bsd_name.toLatin1().constData())); scoped_nsobject properties( (NSDictionary*)DADiskCopyDescription(disk)); @@ -840,7 +843,7 @@ void MacDeviceLister::UnmountDevice(const QString& serial) { QString bsd_name = current_devices_[serial]; ScopedCFTypeRef disk(DADiskCreateFromBSDName( - kCFAllocatorDefault, loop_session_, bsd_name.toAscii().constData())); + kCFAllocatorDefault, loop_session_, bsd_name.toLatin1().constData())); DADiskUnmount(disk, kDADiskUnmountOptionDefault, &DiskUnmountCallback, this); } diff --git a/src/devices/mtpconnection.cpp b/src/devices/mtpconnection.cpp index 970d3311a..7b13dfba1 100644 --- a/src/devices/mtpconnection.cpp +++ b/src/devices/mtpconnection.cpp @@ -20,6 +20,7 @@ #include #include +#include MtpConnection::MtpConnection(const QUrl& url) : device_(nullptr) { QString hostname = url.host(); @@ -29,30 +30,32 @@ MtpConnection::MtpConnection(const QUrl& url) : device_(nullptr) { unsigned int bus_location; unsigned int device_num; + QUrlQuery url_query(url); + if (host_re.indexIn(hostname) >= 0) { bus_location = host_re.cap(1).toUInt(); device_num = host_re.cap(2).toUInt(); - } else if (url.hasQueryItem("busnum")) { - bus_location = url.queryItemValue("busnum").toUInt(); - device_num = url.queryItemValue("devnum").toUInt(); + } else if (url_query.hasQueryItem("busnum")) { + bus_location = url_query.queryItemValue("busnum").toUInt(); + device_num = url_query.queryItemValue("devnum").toUInt(); } else { qLog(Warning) << "Invalid MTP device:" << hostname; return; } - if (url.hasQueryItem("vendor")) { + if (url_query.hasQueryItem("vendor")) { LIBMTP_raw_device_t* raw_device = (LIBMTP_raw_device_t*)malloc(sizeof(LIBMTP_raw_device_t)); raw_device->device_entry.vendor = - url.queryItemValue("vendor").toAscii().data(); + url_query.queryItemValue("vendor").toLatin1().data(); raw_device->device_entry.product = - url.queryItemValue("product").toAscii().data(); + url_query.queryItemValue("product").toLatin1().data(); raw_device->device_entry.vendor_id = - url.queryItemValue("vendor_id").toUShort(); + url_query.queryItemValue("vendor_id").toUShort(); raw_device->device_entry.product_id = - url.queryItemValue("product_id").toUShort(); + url_query.queryItemValue("product_id").toUShort(); raw_device->device_entry.device_flags = - url.queryItemValue("quirks").toUInt(); + url_query.queryItemValue("quirks").toUInt(); raw_device->bus_location = bus_location; raw_device->devnum = device_num; diff --git a/src/engines/gstengine.cpp b/src/engines/gstengine.cpp index 4d0260278..c9ba65a04 100644 --- a/src/engines/gstengine.cpp +++ b/src/engines/gstengine.cpp @@ -770,7 +770,7 @@ GstElement* GstEngine::CreateElement(const QString& factoryName, QString name = factoryName + "-" + QString::number(next_element_id_++); GstElement* element = gst_element_factory_make( - factoryName.toAscii().constData(), name.toAscii().constData()); + factoryName.toLatin1().constData(), name.toLatin1().constData()); if (!element) { emit Error(QString( diff --git a/src/engines/gstenginepipeline.cpp b/src/engines/gstenginepipeline.cpp index dea4745b2..f3d468592 100644 --- a/src/engines/gstenginepipeline.cpp +++ b/src/engines/gstenginepipeline.cpp @@ -36,8 +36,8 @@ #include "core/utilities.h" #include "internet/core/internetmodel.h" #ifdef HAVE_SPOTIFY -#include "internet/spotify/spotifyserver.h" -#include "internet/spotify/spotifyservice.h" +# include "internet/spotify/spotifyserver.h" +# include "internet/spotify/spotifyservice.h" #endif const int GstEnginePipeline::kGstStateTimeoutNanosecs = 10000000; @@ -162,7 +162,7 @@ GstElement* GstEnginePipeline::CreateDecodeBinFromUrl(const QUrl& url) { #ifdef HAVE_SPOTIFY if (url.scheme() == "spotify") { new_bin = gst_bin_new("spotify_bin"); - if (!new_bin) return nullptr; + if (!new_bin) return nullptr; // Create elements GstElement* src = engine_->CreateElement("tcpserversrc", new_bin); @@ -198,10 +198,17 @@ GstElement* GstEnginePipeline::CreateDecodeBinFromUrl(const QUrl& url) { Q_ARG(QString, url.toString()), Q_ARG(quint16, port)); } else { #endif + QByteArray uri; + if (url.scheme() == "cdda") { + QString str = url.toString(); + str.remove(str.lastIndexOf(QChar('a')), 1); + uri = str.toUtf8(); + } else { + uri = url.toEncoded(); + } new_bin = engine_->CreateElement("uridecodebin"); - if (!new_bin) return nullptr; - g_object_set(G_OBJECT(new_bin), "uri", url.toEncoded().constData(), - nullptr); + if (!new_bin) return nullptr; + g_object_set(G_OBJECT(new_bin), "uri", uri.constData(), nullptr); CHECKED_GCONNECT(G_OBJECT(new_bin), "drained", &SourceDrainedCallback, this); CHECKED_GCONNECT(G_OBJECT(new_bin), "pad-added", &NewPadCallback, this); @@ -295,7 +302,7 @@ bool GstEnginePipeline::Init() { audioconvert_ = engine_->CreateElement("audioconvert", audiobin_); tee = engine_->CreateElement("tee", audiobin_); - probe_queue = engine_->CreateElement("queue2", audiobin_); + probe_queue = engine_->CreateElement("queue", audiobin_); probe_converter = engine_->CreateElement("audioconvert", audiobin_); probe_sink = engine_->CreateElement("fakesink", audiobin_); @@ -461,7 +468,7 @@ bool GstEnginePipeline::Init() { gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER, HandoffCallback, this, nullptr); gst_object_unref(pad); - GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(pipeline_)); + GstBus* bus = gst_pipeline_get_bus(GST_PIPELINE(pipeline_)); gst_bus_set_sync_handler(bus, BusCallbackSync, this, nullptr); bus_cb_id_ = gst_bus_add_watch(bus, BusCallback, this); gst_object_unref(bus); @@ -485,7 +492,7 @@ bool GstEnginePipeline::InitFromString(const QString& pipeline) { pipeline_ = gst_pipeline_new("pipeline"); GstElement* new_bin = - CreateDecodeBinFromString(pipeline.toAscii().constData()); + CreateDecodeBinFromString(pipeline.toLatin1().constData()); if (!new_bin) { return false; } @@ -524,7 +531,7 @@ bool GstEnginePipeline::InitFromUrl(const QUrl& url, qint64 end_nanosec) { GstEnginePipeline::~GstEnginePipeline() { if (pipeline_) { - GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(pipeline_)); + GstBus* bus = gst_pipeline_get_bus(GST_PIPELINE(pipeline_)); gst_bus_set_sync_handler(bus, nullptr, nullptr, nullptr); gst_object_unref(bus); diff --git a/src/globalsearch/globalsearchsettingspage.cpp b/src/globalsearch/globalsearchsettingspage.cpp index f45f22a82..e7b2541c1 100644 --- a/src/globalsearch/globalsearchsettingspage.cpp +++ b/src/globalsearch/globalsearchsettingspage.cpp @@ -31,8 +31,8 @@ GlobalSearchSettingsPage::GlobalSearchSettingsPage(SettingsDialog* dialog) ui_->setupUi(this); setWindowIcon(IconLoader::Load("search", IconLoader::Base)); - ui_->sources->header()->setResizeMode(0, QHeaderView::Stretch); - ui_->sources->header()->setResizeMode(1, QHeaderView::ResizeToContents); + ui_->sources->header()->setSectionResizeMode(0, QHeaderView::Stretch); + ui_->sources->header()->setSectionResizeMode(1, QHeaderView::ResizeToContents); warning_icon_ = IconLoader::Load("dialog-warning", IconLoader::Base); diff --git a/src/internet/box/boxservice.cpp b/src/internet/box/boxservice.cpp index e461f543a..65eae3f6d 100644 --- a/src/internet/box/boxservice.cpp +++ b/src/internet/box/boxservice.cpp @@ -18,7 +18,10 @@ #include "boxservice.h" -#include +#include +#include +#include +#include #include "core/application.h" #include "core/player.h" @@ -124,10 +127,9 @@ void BoxService::AddAuthorizationHeader(QNetworkRequest* request) const { void BoxService::FetchUserInfoFinished(QNetworkReply* reply) { reply->deleteLater(); - QJson::Parser parser; - QVariantMap response = parser.parse(reply).toMap(); + QJsonObject json_response = QJsonDocument::fromJson(reply->readAll()).object(); - QString name = response["name"].toString(); + QString name = json_response["name"].toString(); if (!name.isEmpty()) { QSettings s; s.beginGroup(kSettingsGroup); @@ -162,7 +164,9 @@ void BoxService::UpdateFiles() { void BoxService::InitialiseEventsCursor() { QUrl url(kEvents); - url.addQueryItem("stream_position", "now"); + QUrlQuery url_query; + url_query.addQueryItem("stream_position", "now"); + url.setQuery(url_query); QNetworkRequest request(url); AddAuthorizationHeader(&request); QNetworkReply* reply = network_->get(request); @@ -172,12 +176,11 @@ void BoxService::InitialiseEventsCursor() { void BoxService::InitialiseEventsFinished(QNetworkReply* reply) { reply->deleteLater(); - QJson::Parser parser; - QVariantMap response = parser.parse(reply).toMap(); - if (response.contains("next_stream_position")) { + QJsonObject json_response = QJsonDocument::fromJson(reply->readAll()).object(); + if (json_response.contains("next_stream_position")) { QSettings s; s.beginGroup(kSettingsGroup); - s.setValue("cursor", response["next_stream_position"]); + s.setValue("cursor", json_response["next_stream_position"].toString()); } } @@ -191,9 +194,11 @@ void BoxService::FetchRecursiveFolderItems(const int folder_id, << "modified_at" << "name"; QString fields_list = fields.join(","); - url.addQueryItem("fields", fields_list); - url.addQueryItem("limit", "1000"); // Maximum according to API docs. - url.addQueryItem("offset", QString::number(offset)); + QUrlQuery url_query (url); + url_query.addQueryItem("fields", fields_list); + url_query.addQueryItem("limit", "1000"); // Maximum according to API docs. + url_query.addQueryItem("offset", QString::number(offset)); + url.setQuery(url_query); QNetworkRequest request(url); AddAuthorizationHeader(&request); QNetworkReply* reply = network_->get(request); @@ -206,21 +211,18 @@ void BoxService::FetchFolderItemsFinished(QNetworkReply* reply, const int folder_id) { reply->deleteLater(); - QByteArray data = reply->readAll(); + QJsonObject json_response = QJsonDocument::fromJson(reply->readAll()).object(); - QJson::Parser parser; - QVariantMap response = parser.parse(data).toMap(); - - QVariantList entries = response["entries"].toList(); - const int total_entries = response["total_count"].toInt(); - const int offset = response["offset"].toInt(); + QJsonArray entries = json_response["entries"].toArray(); + const int total_entries = json_response["total_count"].toInt(); + const int offset = json_response["offset"].toInt(); if (entries.size() + offset < total_entries) { // Fetch the next page if necessary. FetchRecursiveFolderItems(folder_id, offset + entries.size()); } - for (const QVariant& e : entries) { - QVariantMap entry = e.toMap(); + for (const QJsonValue& e : entries) { + QJsonObject entry = e.toObject(); if (entry["type"].toString() == "folder") { FetchRecursiveFolderItems(entry["id"].toInt()); } else { @@ -229,16 +231,16 @@ void BoxService::FetchFolderItemsFinished(QNetworkReply* reply, } } -void BoxService::MaybeAddFileEntry(const QVariantMap& entry) { +void BoxService::MaybeAddFileEntry(const QJsonObject &entry) { QString mime_type = GuessMimeTypeForFile(entry["name"].toString()); QUrl url; url.setScheme("box"); - url.setPath(entry["id"].toString()); + url.setPath("/" + entry["id"].toString()); Song song; song.set_url(url); - song.set_ctime(entry["created_at"].toDateTime().toTime_t()); - song.set_mtime(entry["modified_at"].toDateTime().toTime_t()); + song.set_ctime(QDateTime::fromString(entry["created_at"].toString()).toTime_t()); + song.set_mtime(QDateTime::fromString(entry["modified_at"].toString()).toTime_t()); song.set_filesize(entry["size"].toInt()); song.set_title(entry["name"].toString()); @@ -273,8 +275,10 @@ void BoxService::RedirectFollowed(QNetworkReply* reply, const Song& song, void BoxService::UpdateFilesFromCursor(const QString& cursor) { QUrl url(kEvents); - url.addQueryItem("stream_position", cursor); - url.addQueryItem("limit", "5000"); + QUrlQuery url_query; + url_query.addQueryItem("stream_position", cursor); + url_query.addQueryItem("limit", "5000"); + url.setQuery(url_query); QNetworkRequest request(url); AddAuthorizationHeader(&request); QNetworkReply* reply = network_->get(request); @@ -285,18 +289,17 @@ void BoxService::UpdateFilesFromCursor(const QString& cursor) { void BoxService::FetchEventsFinished(QNetworkReply* reply) { // TODO(John Maguire): Page through events. reply->deleteLater(); - QJson::Parser parser; - QVariantMap response = parser.parse(reply).toMap(); + QJsonObject json_response = QJsonDocument::fromJson(reply->readAll()).object(); QSettings s; s.beginGroup(kSettingsGroup); - s.setValue("cursor", response["next_stream_position"]); + s.setValue("cursor", json_response["next_stream_position"].toString()); - QVariantList entries = response["entries"].toList(); - for (const QVariant& e : entries) { - QVariantMap event = e.toMap(); + QJsonArray entries = json_response["entries"].toArray(); + for (const QJsonValue& e : entries) { + QJsonObject event = e.toObject(); QString type = event["event_type"].toString(); - QVariantMap source = event["source"].toMap(); + QJsonObject source = event["source"].toObject(); if (source["type"] == "file") { if (type == "ITEM_UPLOAD") { // Add file. @@ -305,7 +308,7 @@ void BoxService::FetchEventsFinished(QNetworkReply* reply) { // Delete file. QUrl url; url.setScheme("box"); - url.setPath(source["id"].toString()); + url.setPath("/" + source["id"].toString()); Song song = library_backend_->GetSongByUrl(url); if (song.is_valid()) { library_backend_->DeleteSongs(SongList() << song); diff --git a/src/internet/box/boxservice.h b/src/internet/box/boxservice.h index 9748f680e..a7fd990aa 100644 --- a/src/internet/box/boxservice.h +++ b/src/internet/box/boxservice.h @@ -64,7 +64,7 @@ class BoxService : public CloudFileService { void UpdateFilesFromCursor(const QString& cursor); QNetworkReply* FetchContentUrlForFile(const QString& file_id); void InitialiseEventsCursor(); - void MaybeAddFileEntry(const QVariantMap& entry); + void MaybeAddFileEntry(const QJsonObject& entry); void EnsureConnected(); QString access_token_; diff --git a/src/internet/core/geolocator.cpp b/src/internet/core/geolocator.cpp index 3650fb89b..b4ac30852 100644 --- a/src/internet/core/geolocator.cpp +++ b/src/internet/core/geolocator.cpp @@ -22,9 +22,10 @@ #include #include -#include - #include +#include +#include +#include #include "core/closure.h" #include "core/logging.h" @@ -97,16 +98,15 @@ void Geolocator::RequestFinished(QNetworkReply* reply) { return; } - QJson::Parser parser; - bool ok = false; - QVariant result = parser.parse(reply, &ok); - if (!ok) { + QJsonParseError error; + QJsonDocument json_document = QJsonDocument::fromJson(reply->readAll(), &error); + if (error.error != QJsonParseError::NoError) { emit Finished(LatLng()); return; } - QVariantMap map = result.toMap(); - QString latlng = map["latlng"].toString(); + QJsonObject json_object = json_document.object(); + QString latlng = json_object["latlng"].toString(); LatLng ll(latlng); emit Finished(ll); diff --git a/src/internet/core/internetshowsettingspage.cpp b/src/internet/core/internetshowsettingspage.cpp index 5a4b67629..e8f0d33f9 100644 --- a/src/internet/core/internetshowsettingspage.cpp +++ b/src/internet/core/internetshowsettingspage.cpp @@ -31,8 +31,8 @@ InternetShowSettingsPage::InternetShowSettingsPage(SettingsDialog* parent) ui_->setupUi(this); setWindowIcon(IconLoader::Load("internet-services", IconLoader::Base)); - ui_->sources->header()->setResizeMode(0, QHeaderView::Stretch); - ui_->sources->header()->setResizeMode(1, QHeaderView::ResizeToContents); + ui_->sources->header()->setSectionResizeMode(0, QHeaderView::Stretch); + ui_->sources->header()->setSectionResizeMode(1, QHeaderView::ResizeToContents); } void InternetShowSettingsPage::Load() { diff --git a/src/internet/core/oauthenticator.cpp b/src/internet/core/oauthenticator.cpp index afada16dc..3f7cae01a 100644 --- a/src/internet/core/oauthenticator.cpp +++ b/src/internet/core/oauthenticator.cpp @@ -24,8 +24,10 @@ #include #include #include - -#include +#include +#include +#include +#include #include "core/closure.h" #include "core/logging.h" @@ -50,27 +52,32 @@ void OAuthenticator::StartAuthorisation(const QString& oauth_endpoint, server->Listen(); QUrl url = QUrl(oauth_endpoint); - url.addQueryItem("response_type", "code"); - url.addQueryItem("client_id", client_id_); + QUrlQuery url_query; + url_query.addQueryItem("response_type", "code"); + url_query.addQueryItem("client_id", client_id_); QUrl redirect_url; + QUrlQuery redirect_url_query; const QString port = QString::number(server->url().port()); if (redirect_style_ == RedirectStyle::REMOTE) { redirect_url = QUrl(kRemoteURL); - redirect_url.addQueryItem("port", port); + redirect_url_query.addQueryItem("port", port); } else if (redirect_style_ == RedirectStyle::REMOTE_WITH_STATE) { redirect_url = QUrl(kRemoteURL); - url.addQueryItem("state", port); + url_query.addQueryItem("state", port); } else { redirect_url = server->url(); } - url.addQueryItem("redirect_uri", redirect_url.toString()); + url_query.addQueryItem("redirect_uri", redirect_url.toString()); if (!scope.isEmpty()) { // Empty scope is valid for Dropbox. - url.addQueryItem("scope", scope); + url_query.addQueryItem("scope", scope); } + url.setQuery(url_query); + redirect_url.setQuery(redirect_url_query); + NewClosure(server, SIGNAL(Finished()), this, &OAuthenticator::RedirectArrived, server, redirect_url); @@ -80,7 +87,7 @@ void OAuthenticator::StartAuthorisation(const QString& oauth_endpoint, void OAuthenticator::RedirectArrived(LocalRedirectServer* server, QUrl url) { server->deleteLater(); QUrl request_url = server->request_url(); - RequestAccessToken(request_url.queryItemValue("code").toUtf8(), url); + RequestAccessToken(QUrlQuery(request_url).queryItemValue("code").toUtf8(), url); } QByteArray OAuthenticator::ParseHttpRequest(const QByteArray& request) const { @@ -130,14 +137,15 @@ void OAuthenticator::FetchAccessTokenFinished(QNetworkReply* reply) { return; } - QJson::Parser parser; - bool ok = false; - QVariantMap result = parser.parse(reply, &ok).toMap(); - if (!ok) { + QJsonParseError error; + QJsonDocument json_document = QJsonDocument::fromJson(reply->readAll(), &error); + + if (error.error != QJsonParseError::NoError) { qLog(Error) << "Failed to parse oauth reply"; return; } + QJsonObject result = json_document.object(); access_token_ = result["access_token"].toString(); refresh_token_ = result["refresh_token"].toString(); SetExpiryTime(result["expires_in"].toInt()); @@ -180,15 +188,14 @@ void OAuthenticator::SetExpiryTime(int expires_in_seconds) { void OAuthenticator::RefreshAccessTokenFinished(QNetworkReply* reply) { reply->deleteLater(); - QJson::Parser parser; - bool ok = false; - QVariantMap result = parser.parse(reply, &ok).toMap(); - access_token_ = result["access_token"].toString(); - if (result.contains("refresh_token")) { - refresh_token_ = result["refresh_token"].toString(); + QJsonObject json_result = QJsonDocument::fromJson(reply->readAll()).object(); + + access_token_ = json_result["access_token"].toString(); + if (json_result.contains("refresh_token")) { + refresh_token_ = json_result["refresh_token"].toString(); } - SetExpiryTime(result["expires_in"].toInt()); + SetExpiryTime(json_result["expires_in"].toInt()); emit Finished(); } diff --git a/src/internet/digitally/digitallyimportedclient.cpp b/src/internet/digitally/digitallyimportedclient.cpp index c5aeb8f84..8ee96d9ba 100644 --- a/src/internet/digitally/digitallyimportedclient.cpp +++ b/src/internet/digitally/digitallyimportedclient.cpp @@ -19,10 +19,11 @@ #include "digitallyimportedclient.h" -#include - #include #include +#include +#include +#include #include "core/logging.h" #include "core/network.h" @@ -52,7 +53,7 @@ void DigitallyImportedClient::SetAuthorisationHeader( req->setRawHeader("Authorization", "Basic " + QString("%1:%2") .arg(kApiUsername, kApiPassword) - .toAscii() + .toLatin1() .toBase64()); } @@ -82,32 +83,30 @@ DigitallyImportedClient::AuthReply DigitallyImportedClient::ParseAuthReply( return ret; } - QJson::Parser parser; - QVariantMap data = parser.parse(reply).toMap(); + QJsonObject json_root_object = QJsonDocument::fromJson(reply->readAll()).object(); - if (!data.contains("subscriptions")) { + if (json_root_object["subscriptions"].isUndefined()) { return ret; } - QVariantList subscriptions = - data.value("subscriptions", QVariantList()).toList(); - if (subscriptions.isEmpty() || - subscriptions[0].toMap().value("status").toString() != "active") { + QJsonArray json_subscriptions = json_root_object["subscriptions"].toArray(); + if (json_subscriptions.isEmpty() || + json_subscriptions[0].toObject()["status"].toString() != "active") { ret.error_reason_ = tr("You do not have an active subscription"); return ret; } - if (!data.contains("first_name") || !data.contains("last_name") || - !subscriptions[0].toMap().contains("expires_on") || - !data.contains("listen_key")) + if (json_root_object["first_name"].isUndefined() || json_root_object["last_name"].isUndefined() || + json_subscriptions[0].toObject()["expires_on"].isUndefined() || + json_root_object["listen_key"].isUndefined()) return ret; ret.success_ = true; - ret.first_name_ = data["first_name"].toString(); - ret.last_name_ = data["last_name"].toString(); + ret.first_name_ = json_root_object["first_name"].toString(); + ret.last_name_ = json_root_object["last_name"].toString(); ret.expires_ = QDateTime::fromString( - subscriptions[0].toMap()["expires_on"].toString(), Qt::ISODate); - ret.listen_hash_ = data["listen_key"].toString(); + json_subscriptions[0].toObject()["expires_on"].toString(), Qt::ISODate); + ret.listen_hash_ = json_root_object["listen_key"].toString(); return ret; } @@ -123,30 +122,28 @@ DigitallyImportedClient::ChannelList DigitallyImportedClient::ParseChannelList( QNetworkReply* reply) const { ChannelList ret; - QJson::Parser parser; - QVariantMap data = parser.parse(reply).toMap(); + QJsonObject json_root_object = QJsonDocument::fromJson(reply->readAll()).object(); - if (!data.contains("channel_filters")) return ret; + if (json_root_object["channel_filters"].isUndefined()) return ret; - QVariantList filters = data["channel_filters"].toList(); + QJsonArray json_filters = json_root_object["channel_filters"].toArray(); - for (const QVariant& filter : filters) { + for (const QJsonValue & filter: json_filters) { // Find the filter called "All" - QVariantMap filter_map = filter.toMap(); - if (filter_map.value("name", QString()).toString() != "All") continue; + QJsonObject json_filter = filter.toObject(); + if (json_filter["name"].toString() != "All") continue; // Add all its stations to the result - QVariantList channels = - filter_map.value("channels", QVariantList()).toList(); - for (const QVariant& channel_var : channels) { - QVariantMap channel_map = channel_var.toMap(); + QJsonArray json_channels = json_filter["channels"].toArray(); + for (const QJsonValue& channel_var : json_channels) { + QJsonObject json_channel = channel_var.toObject(); Channel channel; - channel.art_url_ = QUrl(channel_map.value("asset_url").toString()); - channel.description_ = channel_map.value("description").toString(); - channel.director_ = channel_map.value("channel_director").toString(); - channel.key_ = channel_map.value("key").toString(); - channel.name_ = channel_map.value("name").toString(); + channel.art_url_ = QUrl(json_channel["asset_url"].toString()); + channel.description_ = json_channel["description"].toString(); + channel.director_ = json_channel["channel_director"].toString(); + channel.key_ = json_channel["key"].toString(); + channel.name_ = json_channel["name"].toString(); ret << channel; } diff --git a/src/internet/dropbox/dropboxservice.cpp b/src/internet/dropbox/dropboxservice.cpp index 15d2ef36e..21c0fa785 100644 --- a/src/internet/dropbox/dropboxservice.cpp +++ b/src/internet/dropbox/dropboxservice.cpp @@ -21,9 +21,9 @@ #include #include - -#include -#include +#include +#include +#include #include "core/application.h" #include "core/logging.h" @@ -107,7 +107,7 @@ void DropboxService::RequestFileList() { if (cursor.isEmpty()) { QUrl url = QUrl(QString(kListFolderEndpoint)); - QVariantMap json; + QJsonObject json; json.insert("path", ""); json.insert("recursive", true); json.insert("include_deleted", true); @@ -116,20 +116,19 @@ void DropboxService::RequestFileList() { request.setRawHeader("Authorization", GenerateAuthorisationHeader()); request.setRawHeader("Content-Type", "application/json; charset=utf-8"); - QJson::Serializer serializer; - - QNetworkReply* reply = network_->post(request, serializer.serialize(json)); + QJsonDocument document(json); + QNetworkReply* reply = network_->post(request, document.toJson()); NewClosure(reply, SIGNAL(finished()), this, SLOT(RequestFileListFinished(QNetworkReply*)), reply); } else { QUrl url = QUrl(kListFolderContinueEndpoint); - QVariantMap json; + QJsonObject json; json.insert("cursor", cursor); - QJson::Serializer serializer; + QJsonDocument document(json); QNetworkRequest request(url); request.setRawHeader("Authorization", GenerateAuthorisationHeader()); request.setRawHeader("Content-Type", "application/json; charset=utf-8"); - QNetworkReply* reply = network_->post(request, serializer.serialize(json)); + QNetworkReply* reply = network_->post(request, document.toJson()); NewClosure(reply, SIGNAL(finished()), this, SLOT(RequestFileListFinished(QNetworkReply*)), reply); } @@ -138,17 +137,22 @@ void DropboxService::RequestFileList() { void DropboxService::RequestFileListFinished(QNetworkReply* reply) { reply->deleteLater(); - QJson::Parser parser; - QVariantMap response = parser.parse(reply).toMap(); + QJsonDocument document = QJsonDocument::fromBinaryData(reply->readAll()); + QJsonObject json_response = document.object(); + + if (json_response.contains("reset") && json_response["reset"].toBool()) { + qLog(Debug) << "Resetting Dropbox DB"; + library_backend_->DeleteAll(); + } QSettings settings; settings.beginGroup(kSettingsGroup); - settings.setValue("cursor", response["cursor"].toString()); + settings.setValue("cursor", json_response["cursor"].toString()); - QVariantList contents = response["entries"].toList(); + QJsonArray contents = json_response["entries"].toArray(); qLog(Debug) << "File list found:" << contents.size(); - for (const QVariant& c : contents) { - QVariantMap item = c.toMap(); + for (const QJsonValue& c : contents) { + QJsonObject item = c.toObject(); QString path = item["path_lower"].toString(); QUrl url; @@ -176,10 +180,10 @@ void DropboxService::RequestFileListFinished(QNetworkReply* reply) { } } - if (response.contains("has_more") && response["has_more"].toBool()) { + if (json_response.contains("has_more") && json_response["has_more"].toBool()) { QSettings s; s.beginGroup(kSettingsGroup); - s.setValue("cursor", response["cursor"]); + s.setValue("cursor", json_response["cursor"].toVariant()); RequestFileList(); } else { // Long-poll wait for changes. @@ -196,28 +200,27 @@ void DropboxService::LongPollDelta() { s.beginGroup(kSettingsGroup); QUrl request_url = QUrl(QString(kLongPollEndpoint)); - QVariantMap json; + QJsonObject json; json.insert("cursor", s.value("cursor").toString()); json.insert("timeout", 30); QNetworkRequest request(request_url); request.setRawHeader("Content-Type", "application/json; charset=utf-8"); - QJson::Serializer serializer; - QNetworkReply* reply = network_->post(request, serializer.serialize(json)); + QJsonDocument document(json); + QNetworkReply* reply = network_->post(request, document.toJson()); NewClosure(reply, SIGNAL(finished()), this, SLOT(LongPollFinished(QNetworkReply*)), reply); } void DropboxService::LongPollFinished(QNetworkReply* reply) { reply->deleteLater(); - QJson::Parser parser; - QVariantMap response = parser.parse(reply).toMap(); - if (response["changes"].toBool()) { + QJsonObject json_response = QJsonDocument::fromBinaryData(reply->readAll()).object(); + if (json_response["changes"].toBool()) { // New changes, we should request deltas again. qLog(Debug) << "Detected new dropbox changes; fetching..."; RequestFileList(); } else { bool ok = false; - int backoff_secs = response["backoff"].toInt(&ok); + int backoff_secs = json_response["backoff"].toString().toInt(&ok); backoff_secs = ok ? backoff_secs : 0; QTimer::singleShot(backoff_secs * 1000, this, SLOT(LongPollDelta())); @@ -226,20 +229,19 @@ void DropboxService::LongPollFinished(QNetworkReply* reply) { QNetworkReply* DropboxService::FetchContentUrl(const QUrl& url) { QUrl request_url(kMediaEndpoint); - QVariantMap json; + QJsonObject json; json.insert("path", url.path()); - QJson::Serializer serializer; + QJsonDocument document(json); QNetworkRequest request(request_url); request.setRawHeader("Authorization", GenerateAuthorisationHeader()); request.setRawHeader("Content-Type", "application/json; charset=utf-8"); - return network_->post(request, serializer.serialize(json)); + return network_->post(request, document.toJson()); } void DropboxService::FetchContentUrlFinished(QNetworkReply* reply, const QVariantMap& data) { reply->deleteLater(); - QJson::Parser parser; - QVariantMap response = parser.parse(reply).toMap(); + QJsonObject json_response = QJsonDocument::fromBinaryData(reply->readAll()).object(); QFileInfo info(data["path_lower"].toString()); QUrl url; @@ -256,7 +258,7 @@ void DropboxService::FetchContentUrlFinished(QNetworkReply* reply, song.set_ctime(0); MaybeAddFileToDatabase(song, GuessMimeTypeForFile(url.toString()), - QUrl::fromEncoded(response["link"].toByteArray()), + QUrl::fromEncoded(json_response["link"].toVariant().toByteArray()), QString::null); } @@ -264,7 +266,6 @@ QUrl DropboxService::GetStreamingUrlFromSongId(const QUrl& url) { QNetworkReply* reply = FetchContentUrl(url); WaitForSignal(reply, SIGNAL(finished())); - QJson::Parser parser; - QVariantMap response = parser.parse(reply).toMap(); - return QUrl::fromEncoded(response["link"].toByteArray()); + QJsonObject json_response = QJsonDocument::fromJson(reply->readAll()).object(); + return QUrl::fromEncoded(json_response["link"].toVariant().toByteArray()); } diff --git a/src/internet/googledrive/googledriveclient.cpp b/src/internet/googledrive/googledriveclient.cpp index e93cae44f..66e9a3eba 100644 --- a/src/internet/googledrive/googledriveclient.cpp +++ b/src/internet/googledrive/googledriveclient.cpp @@ -19,7 +19,12 @@ #include "googledriveclient.h" -#include +#include +#include +#include +#include +#include +#include #include "internet/core/oauthenticator.h" #include "core/closure.h" @@ -114,16 +119,15 @@ void Client::FetchUserInfoFinished(ConnectResponse* response, if (reply->attribute(QNetworkRequest::HttpStatusCodeAttribute) != 200) { qLog(Warning) << "Failed to get user info" << reply->readAll(); } else { - QJson::Parser parser; - bool ok = false; - QVariantMap result = parser.parse(reply, &ok).toMap(); - if (!ok) { + QJsonParseError error; + QJsonDocument document = QJsonDocument::fromJson(reply->readAll(), &error); + if (error.error != QJsonParseError::NoError) { qLog(Error) << "Failed to parse user info reply"; return; } - qLog(Debug) << result; - response->user_email_ = result["email"].toString(); + qLog(Debug) << document; + response->user_email_ = document.object()["email"].toString(); qLog(Debug) << response->user_email_; } emit response->Finished(); @@ -157,16 +161,15 @@ GetFileResponse* Client::GetFile(const QString& file_id) { void Client::GetFileFinished(GetFileResponse* response, QNetworkReply* reply) { reply->deleteLater(); - QJson::Parser parser; - bool ok = false; - QVariantMap result = parser.parse(reply, &ok).toMap(); - if (!ok) { + QJsonParseError error; + QJsonDocument document = QJsonDocument::fromJson(reply->readAll(), &error); + if (error.error != QJsonParseError::NoError) { qLog(Error) << "Failed to fetch file with ID" << response->file_id_; emit response->Finished(); return; } - response->file_ = File(result); + response->file_ = File(document.object().toVariantMap()); emit response->Finished(); } @@ -179,13 +182,16 @@ ListChangesResponse* Client::ListChanges(const QString& cursor) { void Client::MakeListChangesRequest(ListChangesResponse* response, const QString& page_token) { QUrl url(kGoogleDriveChanges); + QUrlQuery url_query; if (!response->cursor().isEmpty()) { - url.addQueryItem("startChangeId", response->cursor()); + url_query.addQueryItem("startChangeId", response->cursor()); } if (!page_token.isEmpty()) { - url.addQueryItem("pageToken", page_token); + url_query.addQueryItem("pageToken", page_token); } + url.setQuery(url_query); + qLog(Debug) << "Requesting changes at:" << response->cursor() << page_token; QNetworkRequest request(url); @@ -201,33 +207,33 @@ void Client::ListChangesFinished(ListChangesResponse* response, QNetworkReply* reply) { reply->deleteLater(); - QJson::Parser parser; - bool ok = false; + QJsonParseError error; + QJsonDocument document = QJsonDocument::fromJson(reply->readAll(), &error); // TODO(John Maguire): Put this on a separate thread as the response could be large. - QVariantMap result = parser.parse(reply, &ok).toMap(); - if (!ok) { + if (error.error != QJsonParseError::NoError) { qLog(Error) << "Failed to fetch changes" << response->cursor(); emit response->Finished(); return; } - if (result.contains("largestChangeId")) { - response->next_cursor_ = result["largestChangeId"].toString(); + QJsonObject json_result = document.object(); + if (json_result.contains("largestChangeId")) { + response->next_cursor_ = json_result["largestChangeId"].toString(); } // Emit the FilesFound signal for the files in the response. FileList files; QList files_deleted; - for (const QVariant& v : result["items"].toList()) { - QVariantMap change = v.toMap(); + for (const QJsonValue & v : json_result["items"].toArray()) { + QJsonObject change = v.toObject(); if (change["deleted"].toBool() || - change["file"].toMap()["labels"].toMap()["trashed"].toBool()) { + change["file"].toObject()["labels"].toObject()["trashed"].toBool()) { QUrl url; url.setScheme("googledrive"); - url.setPath(change["fileId"].toString()); + url.setPath("/" + change["fileId"].toString()); files_deleted << url; } else { - files << File(change["file"].toMap()); + files << File(change["file"].toObject().toVariantMap()); } } @@ -235,8 +241,8 @@ void Client::ListChangesFinished(ListChangesResponse* response, emit response->FilesDeleted(files_deleted); // Get the next page of results if there is one. - if (result.contains("nextPageToken")) { - MakeListChangesRequest(response, result["nextPageToken"].toString()); + if (json_result.contains("nextPageToken")) { + MakeListChangesRequest(response, json_result["nextPageToken"].toString()); } else { emit response->Finished(); } diff --git a/src/internet/googledrive/googledriveservice.cpp b/src/internet/googledrive/googledriveservice.cpp index 1465f3891..f68681430 100644 --- a/src/internet/googledrive/googledriveservice.cpp +++ b/src/internet/googledrive/googledriveservice.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include "core/application.h" #include "core/closure.h" @@ -163,7 +164,7 @@ void GoogleDriveService::FilesFound(const QList& files) { QUrl url; url.setScheme("googledrive"); - url.setPath(file.id()); + url.setPath("/" + file.id()); Song song; // Add some extra tags from the Google Drive metadata. @@ -204,7 +205,9 @@ QUrl GoogleDriveService::GetStreamingUrlFromSongId(const QString& id) { loop.exec(); QUrl url(response->file().download_url()); - url.addQueryItem("access_token", client_->access_token()); + QUrlQuery url_query(url); + url_query.addQueryItem("access_token", client_->access_token()); + url.setQuery(url_query); return url; } diff --git a/src/internet/icecast/icecastbackend.cpp b/src/internet/icecast/icecastbackend.cpp index 35daa3c24..2c9f1bbe7 100644 --- a/src/internet/icecast/icecastbackend.cpp +++ b/src/internet/icecast/icecastbackend.cpp @@ -43,7 +43,8 @@ QStringList IcecastBackend::GetGenresAlphabetical(const QString& filter) { QString sql = QString("SELECT DISTINCT genre FROM %1 %2 ORDER BY genre") .arg(kTableName, where); - QSqlQuery q(sql, db); + QSqlQuery q(db); + q.prepare(sql); if (!filter.isEmpty()) { q.bindValue(":filter", QString("%" + filter + "%")); } @@ -69,7 +70,8 @@ QStringList IcecastBackend::GetGenresByPopularity(const QString& filter) { " %2" " GROUP BY genre" " ORDER BY count DESC").arg(kTableName, where); - QSqlQuery q(sql, db); + QSqlQuery q(db); + q.prepare(sql); if (!filter.isEmpty()) { q.bindValue(":filter", QString("%" + filter + "%")); } @@ -109,7 +111,8 @@ IcecastBackend::StationList IcecastBackend::GetStations(const QString& filter, if (!where_clauses.isEmpty()) { sql += " WHERE " + where_clauses.join(" AND "); } - QSqlQuery q(sql, db); + QSqlQuery q(db); + q.prepare(sql); for (const QString& value : bound_items) { q.addBindValue(value); } @@ -134,7 +137,8 @@ IcecastBackend::StationList IcecastBackend::GetStations(const QString& filter, bool IcecastBackend::IsEmpty() { QMutexLocker l(db_->Mutex()); QSqlDatabase db = db_->Connect(); - QSqlQuery q(QString("SELECT ROWID FROM %1 LIMIT 1").arg(kTableName), db); + QSqlQuery q(db); + q.prepare(QString("SELECT ROWID FROM %1 LIMIT 1").arg(kTableName)); q.exec(); return !q.next(); } @@ -146,17 +150,16 @@ void IcecastBackend::ClearAndAddStations(const StationList& stations) { ScopedTransaction t(&db); // Remove all existing items - QSqlQuery q(QString("DELETE FROM %1").arg(kTableName), db); + QSqlQuery q(db); + q.prepare(QString("DELETE FROM %1").arg(kTableName)); q.exec(); if (db_->CheckErrors(q)) return; - q = QSqlQuery( - QString( + q.prepare(QString( "INSERT INTO %1 (name, url, mime_type, bitrate," " channels, samplerate, genre)" " VALUES (:name, :url, :mime_type, :bitrate," - " :channels, :samplerate, :genre)").arg(kTableName), - db); + " :channels, :samplerate, :genre)").arg(kTableName)); // Add these ones for (const Station& station : stations) { diff --git a/src/internet/icecast/icecastmodel.cpp b/src/internet/icecast/icecastmodel.cpp index 26e0e898d..3c1d4bfab 100644 --- a/src/internet/icecast/icecastmodel.cpp +++ b/src/internet/icecast/icecastmodel.cpp @@ -48,7 +48,8 @@ void IcecastModel::Reset() { LazyPopulate(root_); - reset(); + beginResetModel(); + endResetModel(); } void IcecastModel::LazyPopulate(IcecastItem* parent) { diff --git a/src/internet/jamendo/jamendodynamicplaylist.cpp b/src/internet/jamendo/jamendodynamicplaylist.cpp index cfcfb16a8..4424a978a 100644 --- a/src/internet/jamendo/jamendodynamicplaylist.cpp +++ b/src/internet/jamendo/jamendodynamicplaylist.cpp @@ -21,9 +21,8 @@ #include "jamendodynamicplaylist.h" #include -#include -#include #include +#include #include "core/logging.h" #include "core/network.h" @@ -119,35 +118,36 @@ QString JamendoDynamicPlaylist::OrderSpec(OrderBy by, OrderDirection dir) { void JamendoDynamicPlaylist::Fetch() { QUrl url(kUrl); - url.addQueryItem("pn", QString::number(current_page_++)); - url.addQueryItem("n", QString::number(kPageSize)); - url.addQueryItem("order", OrderSpec(order_by_, order_direction_)); + QUrlQuery url_query; + url_query.addQueryItem("pn", QString::number(current_page_++)); + url_query.addQueryItem("n", QString::number(kPageSize)); + url_query.addQueryItem("order", OrderSpec(order_by_, order_direction_)); + url.setQuery(url_query); + // TODO // We have to use QHttp here because there's no way to disable Keep-Alive // with QNetworkManager. - QHttpRequestHeader header( - "GET", QString(url.encodedPath() + "?" + url.encodedQuery())); - header.setValue("Host", url.encodedHost()); - - QHttp http(url.host()); - http.request(header); + QNetworkAccessManager network(this); + QNetworkRequest req(url); + QNetworkReply *reply = network.get(req); // Wait for the reply { QEventLoop event_loop; - connect(&http, SIGNAL(requestFinished(int, bool)), &event_loop, - SLOT(quit())); + connect(reply, SIGNAL(finished()), &event_loop, SLOT(quit())); event_loop.exec(); } - if (http.error() != QHttp::NoError) { - qLog(Warning) << "HTTP error returned from Jamendo:" << http.errorString() + reply->deleteLater(); + + if (reply->error() != QNetworkReply::NoError) { + qLog(Warning) << "HTTP error returned from Jamendo:" << reply->errorString() << ", url:" << url.toString(); return; } // The reply will contain one track ID per line - QStringList lines = QString::fromAscii(http.readAll()).split('\n'); + QStringList lines = QString::fromLatin1(reply->readAll()).split('\n'); // Get the songs from the database SongList songs = backend_->GetSongsByForeignId( diff --git a/src/internet/jamendo/jamendoservice.cpp b/src/internet/jamendo/jamendoservice.cpp index 1e8143377..eea8635e5 100644 --- a/src/internet/jamendo/jamendoservice.cpp +++ b/src/internet/jamendo/jamendoservice.cpp @@ -285,9 +285,9 @@ void JamendoService::InsertTrackIds(const TrackIdList& ids) const { ScopedTransaction t(&db); - QSqlQuery insert(QString("INSERT INTO %1 (%2) VALUES (:id)") - .arg(kTrackIdsTable, kTrackIdsColumn), - db); + QSqlQuery insert(db); + insert.prepare(QString("INSERT INTO %1 (%2) VALUES (:id)") + .arg(kTrackIdsTable, kTrackIdsColumn)); for (int id : ids) { insert.bindValue(":id", id); diff --git a/src/internet/lastfm/lastfmcompat.h b/src/internet/lastfm/lastfmcompat.h index 7ca9acf5d..c0681869f 100644 --- a/src/internet/lastfm/lastfmcompat.h +++ b/src/internet/lastfm/lastfmcompat.h @@ -24,21 +24,21 @@ #include "fixlastfm.h" #ifdef HAVE_LIBLASTFM1 -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include #else -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include #endif namespace lastfm { diff --git a/src/internet/lastfm/lastfmservice.cpp b/src/internet/lastfm/lastfmservice.cpp index 9a46a0ee7..5f4a3dd50 100644 --- a/src/internet/lastfm/lastfmservice.cpp +++ b/src/internet/lastfm/lastfmservice.cpp @@ -28,14 +28,7 @@ // some functions in their includes files, which aren't compatible with // QStringBuilder, we undef it here #include -#if QT_VERSION >= 0x040600 -#if QT_VERSION >= 0x040800 #undef QT_USE_QSTRINGBUILDER -#else -#undef QT_USE_FAST_CONCATENATION -#undef QT_USE_FAST_OPERATOR_PLUS -#endif // QT_VERSION >= 0x040800 -#endif // QT_VERSION >= 0x040600 #include "lastfmservice.h" @@ -46,11 +39,12 @@ #include #include #include +#include #ifdef HAVE_LIBLASTFM1 -#include +#include #else -#include +#include #endif #include "lastfmcompat.h" @@ -153,24 +147,28 @@ QByteArray SignApiRequest(QList> params) { void LastFMService::Authenticate() { QUrl url("https://www.last.fm/api/auth/"); - url.addQueryItem("api_key", kApiKey); LocalRedirectServer* server = new LocalRedirectServer(this); server->Listen(); - url.addQueryItem("cb", server->url().toString()); + QUrlQuery url_query; + url_query.addQueryItem("api_key", kApiKey); + url_query.addQueryItem("cb", server->url().toString()); + url.setQuery(url_query); NewClosure(server, SIGNAL(Finished()), [this, server]() { server->deleteLater(); const QUrl& url = server->request_url(); - QString token = url.queryItemValue("token"); + QString token = QUrlQuery(url).queryItemValue("token"); QUrl session_url("https://ws.audioscrobbler.com/2.0/"); - session_url.addQueryItem("api_key", kApiKey); - session_url.addQueryItem("method", "auth.getSession"); - session_url.addQueryItem("token", token); - session_url.addQueryItem("api_sig", SignApiRequest(session_url.queryItems())); + QUrlQuery session_url_query; + session_url_query.addQueryItem("api_key", kApiKey); + session_url_query.addQueryItem("method", "auth.getSession"); + session_url_query.addQueryItem("token", token); + session_url_query.addQueryItem("api_sig", SignApiRequest(session_url_query.queryItems())); + session_url.setQuery(session_url_query); QNetworkReply* reply = network_->get(QNetworkRequest(session_url)); NewClosure(reply, SIGNAL(finished()), this, SLOT(AuthenticateReplyFinished(QNetworkReply*)), reply); @@ -255,7 +253,7 @@ void LastFMService::UpdateSubscriberStatusFinished(QNetworkReply* reply) { QUrl LastFMService::FixupUrl(const QUrl& url) { QUrl ret; - ret.setEncodedUrl(url.toEncoded().replace( + ret.setUrl(url.toEncoded().replace( "USERNAME", QUrl::toPercentEncoding(lastfm::ws::Username))); return ret; } diff --git a/src/internet/lastfm/lastfmsettingspage.cpp b/src/internet/lastfm/lastfmsettingspage.cpp index 7353c5377..e01757721 100644 --- a/src/internet/lastfm/lastfmsettingspage.cpp +++ b/src/internet/lastfm/lastfmsettingspage.cpp @@ -22,7 +22,7 @@ #include "lastfmsettingspage.h" #include "ui_lastfmsettingspage.h" -#include +#include #include #include diff --git a/src/internet/magnatune/magnatunedownloaddialog.cpp b/src/internet/magnatune/magnatunedownloaddialog.cpp index eabbee318..d112bd811 100644 --- a/src/internet/magnatune/magnatunedownloaddialog.cpp +++ b/src/internet/magnatune/magnatunedownloaddialog.cpp @@ -31,6 +31,7 @@ #include #include #include +#include #include "magnatuneservice.h" #include "internet/core/internetmodel.h" @@ -53,8 +54,8 @@ MagnatuneDownloadDialog::MagnatuneDownloadDialog(MagnatuneService* service, setWindowIcon(IconLoader::Load("magnatune", IconLoader::Provider)); - ui_->albums->header()->setResizeMode(QHeaderView::ResizeToContents); - ui_->albums->header()->setResizeMode(1, QHeaderView::Fixed); + ui_->albums->header()->setSectionResizeMode(QHeaderView::ResizeToContents); + ui_->albums->header()->setSectionResizeMode(1, QHeaderView::Fixed); ui_->albums->header()->resizeSection(1, 150); ui_->albums->setItemDelegateForColumn(1, new ProgressItemDelegate(this)); @@ -130,8 +131,10 @@ void MagnatuneDownloadDialog::DownloadNext() { QUrl url(MagnatuneService::kDownloadUrl); url.setUserName(service_->username()); url.setPassword(service_->password()); - url.addQueryItem("id", MagnatuneService::kPartnerId); - url.addQueryItem("sku", sku); + + QUrlQuery url_query; + url_query.addQueryItem("id", MagnatuneService::kPartnerId); + url_query.addQueryItem("sku", sku); current_reply_ = network_->get(QNetworkRequest(url)); diff --git a/src/internet/magnatune/magnatuneservice.cpp b/src/internet/magnatune/magnatuneservice.cpp index 104e23a7b..1724b4d0b 100644 --- a/src/internet/magnatune/magnatuneservice.cpp +++ b/src/internet/magnatune/magnatuneservice.cpp @@ -229,7 +229,7 @@ Song MagnatuneService::ReadTrack(QXmlStreamReader& reader) { if (name == "url") { QUrl url; // Magnatune's URLs are already encoded - url.setEncodedUrl(value.toLocal8Bit()); + url.setUrl(value.toLocal8Bit()); url.setScheme("magnatune"); song.set_url(url); } diff --git a/src/internet/podcasts/gpoddersync.cpp b/src/internet/podcasts/gpoddersync.cpp index bf8e15067..6e54d41cb 100644 --- a/src/internet/podcasts/gpoddersync.cpp +++ b/src/internet/podcasts/gpoddersync.cpp @@ -31,7 +31,6 @@ #include "core/closure.h" #include "core/logging.h" #include "core/network.h" -#include "core/qhash_qurl.h" #include "core/timeconstants.h" #include "core/utilities.h" diff --git a/src/internet/podcasts/itunessearchpage.cpp b/src/internet/podcasts/itunessearchpage.cpp index 20f9b2a6b..5be00f74d 100644 --- a/src/internet/podcasts/itunessearchpage.cpp +++ b/src/internet/podcasts/itunessearchpage.cpp @@ -19,9 +19,13 @@ #include "itunessearchpage.h" -#include #include #include +#include +#include +#include +#include +#include #include "core/closure.h" #include "core/network.h" @@ -49,7 +53,9 @@ void ITunesSearchPage::SearchClicked() { emit Busy(true); QUrl url(QUrl::fromEncoded(kUrlBase)); - url.addQueryItem("term", ui_->query->text()); + QUrlQuery url_query; + url_query.addQueryItem("term", ui_->query->text()); + url.setQuery(url_query); QNetworkReply* reply = network_->get(QNetworkRequest(url)); NewClosure(reply, SIGNAL(finished()), this, @@ -69,37 +75,38 @@ void ITunesSearchPage::SearchFinished(QNetworkReply* reply) { return; } - QJson::Parser parser; - QVariant data = parser.parse(reply); + QJsonParseError error; + QJsonDocument json_document = QJsonDocument::fromJson(reply->readAll(), &error); - // Was it valid JSON? - if (data.isNull()) { + if (error.error != QJsonParseError::NoError) { QMessageBox::warning( this, tr("Failed to fetch podcasts"), tr("There was a problem parsing the response from the iTunes Store")); return; } + QJsonObject json_data = json_document.object(); + // Was there an error message in the JSON? - if (data.toMap().contains("errorMessage")) { + if (!json_data["errorMessage"].isUndefined()) { QMessageBox::warning(this, tr("Failed to fetch podcasts"), - data.toMap()["errorMessage"].toString()); + json_data["errorMessage"].toString()); return; } - for (const QVariant& result_variant : data.toMap()["results"].toList()) { - QVariantMap result(result_variant.toMap()); - if (result["kind"].toString() != "podcast") { + for (const QJsonValue& result : json_data["results"].toArray()) { + QJsonObject json_result = result.toObject(); + if (json_result["kind"].toString() != "podcast") { continue; } Podcast podcast; - podcast.set_author(result["artistName"].toString()); - podcast.set_title(result["trackName"].toString()); - podcast.set_url(result["feedUrl"].toUrl()); - podcast.set_link(result["trackViewUrl"].toUrl()); - podcast.set_image_url_small(QUrl(result["artworkUrl30"].toString())); - podcast.set_image_url_large(QUrl(result["artworkUrl100"].toString())); + podcast.set_author(json_result["artistName"].toString()); + podcast.set_title(json_result["trackName"].toString()); + podcast.set_url(QUrl(json_result["feedUrl"].toString())); + podcast.set_link(QUrl(json_result["trackViewUrl"].toString())); + podcast.set_image_url_small(QUrl(json_result["artworkUrl30"].toString())); + podcast.set_image_url_large(QUrl(json_result["artworkUrl100"].toString())); model()->appendRow(model()->CreatePodcastItem(podcast)); } diff --git a/src/internet/podcasts/podcastbackend.cpp b/src/internet/podcasts/podcastbackend.cpp index 665b7eb72..e43c603d4 100644 --- a/src/internet/podcasts/podcastbackend.cpp +++ b/src/internet/podcasts/podcastbackend.cpp @@ -47,11 +47,11 @@ void PodcastBackend::Subscribe(Podcast* podcast) { ScopedTransaction t(&db); // Insert the podcast. - QSqlQuery q("INSERT INTO podcasts (" + Podcast::kColumnSpec + + QSqlQuery q(db); + q.prepare("INSERT INTO podcasts (" + Podcast::kColumnSpec + ")" " VALUES (" + - Podcast::kBindSpec + ")", - db); + Podcast::kBindSpec + ")"); podcast->BindToQuery(&q); q.exec(); @@ -86,13 +86,14 @@ void PodcastBackend::Unsubscribe(const Podcast& podcast) { ScopedTransaction t(&db); // Remove the podcast. - QSqlQuery q("DELETE FROM podcasts WHERE ROWID = :id", db); + QSqlQuery q(db); + q.prepare("DELETE FROM podcasts WHERE ROWID = :id"); q.bindValue(":id", podcast.database_id()); q.exec(); if (db_->CheckErrors(q)) return; // Remove all episodes in the podcast - q = QSqlQuery("DELETE FROM podcast_episodes WHERE podcast_id = :id", db); + q.prepare("DELETE FROM podcast_episodes WHERE podcast_id = :id"); q.bindValue(":id", podcast.database_id()); q.exec(); if (db_->CheckErrors(q)) return; @@ -104,11 +105,11 @@ void PodcastBackend::Unsubscribe(const Podcast& podcast) { void PodcastBackend::AddEpisodes(PodcastEpisodeList* episodes, QSqlDatabase* db) { - QSqlQuery q("INSERT INTO podcast_episodes (" + PodcastEpisode::kColumnSpec + + QSqlQuery q(*db); + q.prepare("INSERT INTO podcast_episodes (" + PodcastEpisode::kColumnSpec + ")" " VALUES (" + - PodcastEpisode::kBindSpec + ")", - *db); + PodcastEpisode::kBindSpec + ")"); for (auto it = episodes->begin(); it != episodes->end(); ++it) { it->BindToQuery(&q); @@ -136,14 +137,13 @@ void PodcastBackend::UpdateEpisodes(const PodcastEpisodeList& episodes) { QSqlDatabase db(db_->Connect()); ScopedTransaction t(&db); - QSqlQuery q( - "UPDATE podcast_episodes" + QSqlQuery q(db); + q.prepare("UPDATE podcast_episodes" " SET listened = :listened," " listened_date = :listened_date," " downloaded = :downloaded," " local_url = :local_url" - " WHERE ROWID = :id", - db); + " WHERE ROWID = :id"); for (const PodcastEpisode& episode : episodes) { q.bindValue(":listened", episode.listened()); @@ -166,7 +166,8 @@ PodcastList PodcastBackend::GetAllSubscriptions() { QMutexLocker l(db_->Mutex()); QSqlDatabase db(db_->Connect()); - QSqlQuery q("SELECT ROWID, " + Podcast::kColumnSpec + " FROM podcasts", db); + QSqlQuery q(db); + q.prepare("SELECT ROWID, " + Podcast::kColumnSpec + " FROM podcasts"); q.exec(); if (db_->CheckErrors(q)) return ret; @@ -185,10 +186,10 @@ Podcast PodcastBackend::GetSubscriptionById(int id) { QMutexLocker l(db_->Mutex()); QSqlDatabase db(db_->Connect()); - QSqlQuery q("SELECT ROWID, " + Podcast::kColumnSpec + + QSqlQuery q(db); + q.prepare("SELECT ROWID, " + Podcast::kColumnSpec + " FROM podcasts" - " WHERE ROWID = :id", - db); + " WHERE ROWID = :id"); q.bindValue(":id", id); q.exec(); if (!db_->CheckErrors(q) && q.next()) { @@ -204,10 +205,10 @@ Podcast PodcastBackend::GetSubscriptionByUrl(const QUrl& url) { QMutexLocker l(db_->Mutex()); QSqlDatabase db(db_->Connect()); - QSqlQuery q("SELECT ROWID, " + Podcast::kColumnSpec + + QSqlQuery q(db); + q.prepare("SELECT ROWID, " + Podcast::kColumnSpec + " FROM podcasts" - " WHERE url = :url", - db); + " WHERE url = :url"); q.bindValue(":url", url.toEncoded()); q.exec(); if (!db_->CheckErrors(q) && q.next()) { @@ -223,11 +224,11 @@ PodcastEpisodeList PodcastBackend::GetEpisodes(int podcast_id) { QMutexLocker l(db_->Mutex()); QSqlDatabase db(db_->Connect()); - QSqlQuery q("SELECT ROWID, " + PodcastEpisode::kColumnSpec + + QSqlQuery q(db); + q.prepare("SELECT ROWID, " + PodcastEpisode::kColumnSpec + " FROM podcast_episodes" " WHERE podcast_id = :id" - " ORDER BY publication_date DESC", - db); + " ORDER BY publication_date DESC"); q.bindValue(":id", podcast_id); q.exec(); if (db_->CheckErrors(q)) return ret; @@ -247,10 +248,10 @@ PodcastEpisode PodcastBackend::GetEpisodeById(int id) { QMutexLocker l(db_->Mutex()); QSqlDatabase db(db_->Connect()); - QSqlQuery q("SELECT ROWID, " + PodcastEpisode::kColumnSpec + + QSqlQuery q(db); + q.prepare("SELECT ROWID, " + PodcastEpisode::kColumnSpec + " FROM podcast_episodes" - " WHERE ROWID = :id", - db); + " WHERE ROWID = :id"); q.bindValue(":id", id); q.exec(); if (!db_->CheckErrors(q) && q.next()) { @@ -266,10 +267,10 @@ PodcastEpisode PodcastBackend::GetEpisodeByUrl(const QUrl& url) { QMutexLocker l(db_->Mutex()); QSqlDatabase db(db_->Connect()); - QSqlQuery q("SELECT ROWID, " + PodcastEpisode::kColumnSpec + + QSqlQuery q(db); + q.prepare("SELECT ROWID, " + PodcastEpisode::kColumnSpec + " FROM podcast_episodes" - " WHERE url = :url", - db); + " WHERE url = :url"); q.bindValue(":url", url.toEncoded()); q.exec(); if (!db_->CheckErrors(q) && q.next()) { @@ -285,11 +286,11 @@ PodcastEpisode PodcastBackend::GetEpisodeByUrlOrLocalUrl(const QUrl& url) { QMutexLocker l(db_->Mutex()); QSqlDatabase db(db_->Connect()); - QSqlQuery q("SELECT ROWID, " + PodcastEpisode::kColumnSpec + + QSqlQuery q(db); + q.prepare("SELECT ROWID, " + PodcastEpisode::kColumnSpec + " FROM podcast_episodes" " WHERE url = :url" - " OR local_url = :url", - db); + " OR local_url = :url"); q.bindValue(":url", url.toEncoded()); q.exec(); if (!db_->CheckErrors(q) && q.next()) { @@ -306,11 +307,11 @@ PodcastEpisodeList PodcastBackend::GetOldDownloadedEpisodes( QMutexLocker l(db_->Mutex()); QSqlDatabase db(db_->Connect()); - QSqlQuery q("SELECT ROWID, " + PodcastEpisode::kColumnSpec + + QSqlQuery q(db); + q.prepare("SELECT ROWID, " + PodcastEpisode::kColumnSpec + " FROM podcast_episodes" " WHERE downloaded = 'true'" - " AND listened_date <= :max_listened_date", - db); + " AND listened_date <= :max_listened_date"); q.bindValue(":max_listened_date", max_listened_date.toTime_t()); q.exec(); if (db_->CheckErrors(q)) return ret; @@ -330,12 +331,12 @@ PodcastEpisode PodcastBackend::GetOldestDownloadedListenedEpisode() { QMutexLocker l(db_->Mutex()); QSqlDatabase db(db_->Connect()); - QSqlQuery q("SELECT ROWID, " + PodcastEpisode::kColumnSpec + + QSqlQuery q(db); + q.prepare("SELECT ROWID, " + PodcastEpisode::kColumnSpec + " FROM podcast_episodes" " WHERE downloaded = 'true'" " AND listened = 'true'" - " ORDER BY listened_date ASC", - db); + " ORDER BY listened_date ASC"); q.exec(); if (db_->CheckErrors(q)) return ret; q.next(); @@ -350,11 +351,11 @@ PodcastEpisodeList PodcastBackend::GetNewDownloadedEpisodes() { QMutexLocker l(db_->Mutex()); QSqlDatabase db(db_->Connect()); - QSqlQuery q("SELECT ROWID, " + PodcastEpisode::kColumnSpec + + QSqlQuery q(db); + q.prepare("SELECT ROWID, " + PodcastEpisode::kColumnSpec + " FROM podcast_episodes" " WHERE downloaded = 'true'" - " AND listened = 'false'", - db); + " AND listened = 'false'"); q.exec(); if (db_->CheckErrors(q)) return ret; diff --git a/src/internet/podcasts/podcastparser.cpp b/src/internet/podcasts/podcastparser.cpp index 933efd8cd..a5da1626a 100644 --- a/src/internet/podcasts/podcastparser.cpp +++ b/src/internet/podcasts/podcastparser.cpp @@ -114,7 +114,7 @@ void PodcastParser::ParseChannel(QXmlStreamReader* reader, Podcast* ret) const { if (name == "title") { ret->set_title(reader->readElementText()); } else if (name == "link" && lower_namespace.isEmpty()) { - ret->set_link(QUrl::fromEncoded(reader->readElementText().toAscii())); + ret->set_link(QUrl::fromEncoded(reader->readElementText().toLatin1())); } else if (name == "description") { ret->set_description(reader->readElementText()); } else if (name == "owner" && lower_namespace == kItunesNamespace) { @@ -126,7 +126,7 @@ void PodcastParser::ParseChannel(QXmlStreamReader* reader, Podcast* ret) const { } else if (name == "link" && lower_namespace == kAtomNamespace && ret->url().isEmpty() && reader->attributes().value("rel") == "self") { - ret->set_url(QUrl::fromEncoded(reader->readElementText().toAscii())); + ret->set_url(QUrl::fromEncoded(reader->readElementText().toLatin1())); } else if (name == "item") { ParseItem(reader, ret); } else { @@ -152,7 +152,7 @@ void PodcastParser::ParseImage(QXmlStreamReader* reader, Podcast* ret) const { const QStringRef name = reader->name(); if (name == "url") { ret->set_image_url_large( - QUrl::fromEncoded(reader->readElementText().toAscii())); + QUrl::fromEncoded(reader->readElementText().toLatin1())); } else { Utilities::ConsumeCurrentElement(reader); } @@ -229,7 +229,7 @@ void PodcastParser::ParseItem(QXmlStreamReader* reader, Podcast* ret) const { } } else if (name == "enclosure") { const QString type = reader->attributes().value("type").toString(); - const QUrl url = QUrl::fromEncoded(reader->attributes().value("url").toString().toAscii()); + const QUrl url = QUrl::fromEncoded(reader->attributes().value("url").toString().toLatin1()); if (type.startsWith("audio/") || type.startsWith("x-audio/")) { episode.set_url(url); } @@ -305,9 +305,9 @@ void PodcastParser::ParseOutline(QXmlStreamReader* reader, } podcast.set_title(title); podcast.set_image_url_large(QUrl::fromEncoded( - attributes.value("imageHref").toString().toAscii())); + attributes.value("imageHref").toString().toLatin1())); podcast.set_url(QUrl::fromEncoded( - attributes.value("xmlUrl").toString().toAscii())); + attributes.value("xmlUrl").toString().toLatin1())); ret->feeds.append(podcast); // Consume any children and the EndElement. diff --git a/src/internet/podcasts/podcastupdater.cpp b/src/internet/podcasts/podcastupdater.cpp index 56f9b13d8..911b08cbb 100644 --- a/src/internet/podcasts/podcastupdater.cpp +++ b/src/internet/podcasts/podcastupdater.cpp @@ -25,7 +25,6 @@ #include "core/application.h" #include "core/closure.h" #include "core/logging.h" -#include "core/qhash_qurl.h" #include "core/timeconstants.h" #include "podcastbackend.h" #include "podcasturlloader.h" diff --git a/src/internet/podcasts/podcasturlloader.cpp b/src/internet/podcasts/podcasturlloader.cpp index b6509e4ad..c08265fd6 100644 --- a/src/internet/podcasts/podcasturlloader.cpp +++ b/src/internet/podcasts/podcasturlloader.cpp @@ -20,6 +20,7 @@ #include "podcasturlloader.h" #include +#include #include "podcastparser.h" #include "core/closure.h" @@ -73,14 +74,15 @@ QUrl PodcastUrlLoader::FixPodcastUrl(const QString& url_text) { QUrl PodcastUrlLoader::FixPodcastUrl(const QUrl& url_orig) { QUrl url(url_orig); + QUrlQuery url_query(url); // Replace schemes if (url.scheme().isEmpty() || url.scheme() == "feed" || url.scheme() == "itpc" || url.scheme() == "itms") { url.setScheme("http"); } else if (url.scheme() == "zune" && url.host() == "subscribe" && - !url.queryItems().isEmpty()) { - url = QUrl(url.queryItems()[0].second); + !url_query.queryItems().isEmpty()) { + url = QUrl(url_query.queryItems()[0].second); } return url; diff --git a/src/internet/seafile/seafileservice.cpp b/src/internet/seafile/seafileservice.cpp index 69909513e..28a17d8fa 100644 --- a/src/internet/seafile/seafileservice.cpp +++ b/src/internet/seafile/seafileservice.cpp @@ -22,8 +22,11 @@ #include -#include #include +#include +#include +#include +#include #include "core/application.h" #include "core/taskmanager.h" @@ -86,7 +89,7 @@ bool SeafileService::has_credentials() const { void SeafileService::AddAuthorizationHeader(QNetworkRequest* request) const { request->setRawHeader("Authorization", - QString("Token %1").arg(access_token_).toAscii()); + QString("Token %1").arg(access_token_).toLatin1()); } void SeafileService::ForgetCredentials() { @@ -104,13 +107,15 @@ void SeafileService::ForgetCredentials() { bool SeafileService::GetToken(const QString& mail, const QString& password, const QString& server) { QUrl url(server + kAuthTokenUrl); + QUrlQuery url_query; + + url_query.addQueryItem("username", mail); + url_query.addQueryItem("password", password); + QNetworkRequest request(url); AddAuthorizationHeader(&request); - url.addQueryItem("username", mail); - url.addQueryItem("password", password); - - QNetworkReply* reply = network_->post(request, url.encodedQuery()); + QNetworkReply* reply = network_->post(request, url_query.toString().toLatin1()); WaitForSignal(reply, SIGNAL(finished())); if (!CheckReply(&reply)) { @@ -120,11 +125,10 @@ bool SeafileService::GetToken(const QString& mail, const QString& password, reply->deleteLater(); - QJson::Parser parser; - QVariantMap response = parser.parse(reply->readAll()).toMap(); + QJsonObject json_response = QJsonDocument::fromJson(reply->readAll()).object(); // Because the server responds "token" - access_token_ = response["token"].toString().replace("\"", ""); + access_token_ = json_response["token"].toString().replace("\"", ""); if (access_token_.isEmpty()) { return false; @@ -162,11 +166,11 @@ void SeafileService::GetLibrariesFinished(QNetworkReply* reply) { // key : id, value : name QMap libraries; QByteArray data = reply->readAll(); - QJson::Parser parser; - QList repos = parser.parse(data).toList(); - for (int i = 0; i < repos.size(); ++i) { - QVariantMap repo = repos.at(i).toMap(); + QJsonArray json_repos = QJsonDocument::fromJson(data).array(); + + for (const QJsonValue & json_repo: json_repos) { + QJsonObject repo = json_repo.toObject(); QString repo_name = repo["name"].toString(), repo_id = repo["id"].toString(); @@ -289,7 +293,9 @@ void SeafileService::UpdateLibrariesInProgress( QNetworkReply* SeafileService::PrepareFetchFolderItems(const QString& library, const QString& path) { QUrl url(server_ + QString(kFolderItemsUrl).arg(library)); - url.addQueryItem("p", path); + QUrlQuery url_query; + url_query.addQueryItem("p", path); + url.setQuery(url_query); QNetworkRequest request(url); AddAuthorizationHeader(&request); @@ -323,12 +329,11 @@ void SeafileService::FetchAndCheckFolderItemsFinished( QByteArray data = reply->readAll(); - QJson::Parser parser; - QList variant_entries = parser.parse(data).toList(); + QJsonArray json_entries = QJsonDocument::fromJson(data).array(); SeafileTree::Entries entries; - for (const QVariant& e : variant_entries) { - QVariantMap entry = e.toMap(); + for (const QJsonValue& e : json_entries) { + QJsonObject entry = e.toObject(); SeafileTree::Entry::Type entry_type = SeafileTree::Entry::StringToType(entry["type"].toString()); QString entry_name = entry["name"].toString(); @@ -373,14 +378,13 @@ void SeafileService::AddRecursivelyFolderItemsFinished(QNetworkReply* reply, reply->deleteLater(); QByteArray data = reply->readAll(); - QJson::Parser parser; - QList entries = parser.parse(data).toList(); + QJsonArray json_entries = QJsonDocument::fromJson(data).array(); - for (const QVariant& e : entries) { - QVariantMap entry_map = e.toMap(); + for (const QJsonValue& e : json_entries) { + QJsonObject json_entry = e.toObject(); SeafileTree::Entry::Type entry_type = - SeafileTree::Entry::StringToType(entry_map["type"].toString()); - QString entry_name = entry_map["name"].toString(); + SeafileTree::Entry::StringToType(json_entry["type"].toString()); + QString entry_name = json_entry["name"].toString(); // We just want libraries/directories and files which could be songs. if (entry_type == SeafileTree::Entry::NONE) { @@ -390,7 +394,7 @@ void SeafileService::AddRecursivelyFolderItemsFinished(QNetworkReply* reply, continue; } - SeafileTree::Entry entry(entry_name, entry_map["id"].toString(), + SeafileTree::Entry entry(entry_name, json_entry["id"].toString(), entry_type); // If AddEntry was not successful we stop @@ -412,7 +416,9 @@ void SeafileService::AddRecursivelyFolderItemsFinished(QNetworkReply* reply, QNetworkReply* SeafileService::PrepareFetchContentForFile( const QString& library, const QString& filepath) { QUrl content_url(server_ + QString(kFileContentUrl).arg(library)); - content_url.addQueryItem("p", filepath); + QUrlQuery content_url_query; + content_url_query.addQueryItem("p", filepath); + content_url.setQuery(content_url_query); QNetworkRequest request(content_url); AddAuthorizationHeader(&request); @@ -449,23 +455,22 @@ void SeafileService::MaybeAddFileEntryInProgress(QNetworkReply* reply, QByteArray data = reply->readAll(); - QJson::Parser parser; - QVariantMap entry_detail_map = parser.parse(data).toMap(); + QJsonObject json_entry_detail = QJsonDocument::fromJson(data).object(); QUrl url; url.setScheme("seafile"); - url.setPath("/" + library + path + entry_detail_map["name"].toString()); + url.setPath("/" + library + path + json_entry_detail["name"].toString()); Song song; song.set_url(url); song.set_ctime(0); - song.set_mtime(entry_detail_map["mtime"].toInt()); - song.set_filesize(entry_detail_map["size"].toInt()); - song.set_title(entry_detail_map["name"].toString()); + song.set_mtime(json_entry_detail["mtime"].toInt()); + song.set_filesize(json_entry_detail["size"].toInt()); + song.set_title(json_entry_detail["name"].toString()); // Get the download url of the entry reply = PrepareFetchContentUrlForFile( - library, path + entry_detail_map["name"].toString()); + library, path + json_entry_detail["name"].toString()); NewClosure( reply, SIGNAL(finished()), this, SLOT(FetchContentUrlForFileFinished(QNetworkReply*, Song, QString)), @@ -475,9 +480,11 @@ void SeafileService::MaybeAddFileEntryInProgress(QNetworkReply* reply, QNetworkReply* SeafileService::PrepareFetchContentUrlForFile( const QString& library, const QString& filepath) { QUrl content_url(server_ + QString(kFileUrl).arg(library)); - content_url.addQueryItem("p", filepath); + QUrlQuery content_url_query; + content_url_query.addQueryItem("p", filepath); // See https://github.com/haiwen/seahub/issues/677 - content_url.addQueryItem("reuse", "1"); + content_url_query.addQueryItem("reuse", "1"); + content_url.setQuery(content_url_query); QNetworkRequest request(content_url); AddAuthorizationHeader(&request); @@ -643,7 +650,7 @@ bool SeafileService::CheckReply(QNetworkReply** reply, int tries) { // Unknown, 404 ... (*reply)->deleteLater(); - qLog(Warning) << "Error for reply : " << status_code_variant.toInt(); + qLog(Warning) << "Error with the reply : " << status_code_variant.toInt(); return false; } diff --git a/src/internet/skydrive/skydriveservice.cpp b/src/internet/skydrive/skydriveservice.cpp index 5ecefd17f..3e8c43710 100644 --- a/src/internet/skydrive/skydriveservice.cpp +++ b/src/internet/skydrive/skydriveservice.cpp @@ -19,9 +19,12 @@ #include "skydriveservice.h" -#include +#include +#include +#include +#include -#include +#include #include "core/application.h" #include "core/player.h" @@ -108,10 +111,9 @@ void SkydriveService::AddAuthorizationHeader(QNetworkRequest* request) { void SkydriveService::FetchUserInfoFinished(QNetworkReply* reply) { reply->deleteLater(); - QJson::Parser parser; - QVariantMap response = parser.parse(reply).toMap(); + QJsonObject json_response = QJsonDocument::fromBinaryData(reply->readAll()).object(); - QString name = response["name"].toString(); + QString name = json_response["name"].toString(); if (!name.isEmpty()) { QSettings s; s.beginGroup(kSettingsGroup); @@ -135,29 +137,28 @@ void SkydriveService::ListFiles(const QString& folder) { void SkydriveService::ListFilesFinished(QNetworkReply* reply) { reply->deleteLater(); - QJson::Parser parser; - QVariantMap response = parser.parse(reply).toMap(); + QJsonObject json_response = QJsonDocument::fromBinaryData(reply->readAll()).object(); - QVariantList files = response["data"].toList(); - for (const QVariant& f : files) { - QVariantMap file = f.toMap(); + QJsonArray files = json_response["data"].toArray(); + for (const QJsonValue& f : files) { + QJsonObject file = f.toObject(); if (file["type"].toString() == "folder") { ListFiles(file["id"].toString()); } else { QString mime_type = GuessMimeTypeForFile(file["name"].toString()); QUrl url; url.setScheme("skydrive"); - url.setPath(file["id"].toString()); + url.setPath("/" + file["id"].toString()); Song song; song.set_url(url); - song.set_ctime(file["created_time"].toDateTime().toTime_t()); - song.set_mtime(file["updated_time"].toDateTime().toTime_t()); + song.set_ctime(QDateTime::fromString(file["created_time"].toString()).toTime_t()); + song.set_mtime(QDateTime::fromString(file["updated_time"].toString()).toTime_t()); song.set_comment(file["description"].toString()); song.set_filesize(file["size"].toInt()); song.set_title(file["name"].toString()); - QUrl download_url = file["source"].toUrl(); + QUrl download_url(file["source"].toString()); // HTTPS appears to be broken somehow between Qt & Skydrive downloads. // Fortunately, just changing the scheme to HTTP works. download_url.setScheme("http"); @@ -175,9 +176,8 @@ QUrl SkydriveService::GetStreamingUrlFromSongId(const QString& file_id) { std::unique_ptr reply(network_->get(request)); WaitForSignal(reply.get(), SIGNAL(finished())); - QJson::Parser parser; - QVariantMap response = parser.parse(reply.get()).toMap(); - return response["source"].toUrl(); + QJsonObject json_response = QJsonDocument::fromBinaryData(reply.get()->readAll()).object(); + return QUrl(json_response["source"].toString()); } void SkydriveService::EnsureConnected() { diff --git a/src/internet/spotify/spotifyservice.cpp b/src/internet/spotify/spotifyservice.cpp index 75c5c7beb..e05aeb1b7 100644 --- a/src/internet/spotify/spotifyservice.cpp +++ b/src/internet/spotify/spotifyservice.cpp @@ -90,9 +90,9 @@ SpotifyService::SpotifyService(Application* app, InternetModel* parent) // Build the search path for the binary blob. // Look for one distributed alongside clementine first, then check in the // user's home directory for any that have been downloaded. -#if defined(Q_OS_MAC) && defined(USE_BUNDLE) - system_blob_path_ = QCoreApplication::applicationDirPath() + "/" + - USE_BUNDLE_DIR + "/clementine-spotifyblob"; +#if defined(Q_OS_MACOS) && defined(USE_BUNDLE) + system_blob_path_ = QCoreApplication::applicationDirPath() + + "/" + USE_BUNDLE_DIR + "/clementine-spotifyblob"; #else system_blob_path_ = QCoreApplication::applicationDirPath() + "/clementine-spotifyblob" CMAKE_EXECUTABLE_SUFFIX; diff --git a/src/internet/subsonic/subsonicdynamicplaylist.cpp b/src/internet/subsonic/subsonicdynamicplaylist.cpp index 2f145d8e6..c691c6352 100644 --- a/src/internet/subsonic/subsonicdynamicplaylist.cpp +++ b/src/internet/subsonic/subsonicdynamicplaylist.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include #include "core/application.h" @@ -98,9 +99,11 @@ PlaylistItemList SubsonicDynamicPlaylist::GenerateMore(int count) { if (count > kMaxCount) count = kMaxCount; - url.addQueryItem("type", GetTypeString()); - url.addQueryItem("size", QString::number(count)); - url.addQueryItem("offset", QString::number(offset_)); + QUrlQuery url_query(url.query()); + url_query.addQueryItem("type", GetTypeString()); + url_query.addQueryItem("size", QString::number(count)); + url_query.addQueryItem("offset", QString::number(offset_)); + url.setQuery(url_query); PlaylistItemList items; @@ -157,10 +160,12 @@ void SubsonicDynamicPlaylist::GetAlbum(SubsonicService* service, QNetworkAccessManager& network, const bool usesslv3) { QUrl url = service->BuildRequestUrl("getAlbum"); - url.addQueryItem("id", id); + QUrlQuery url_query(url.query()); + url_query.addQueryItem("id", id); if (service->IsAmpache()) { - url.addQueryItem("ampache", "1"); + url_query.addQueryItem("ampache", "1"); } + url.setQuery(url_query); QNetworkReply* reply = Send(network, url, usesslv3); WaitForSignal(reply, SIGNAL(finished())); reply->deleteLater(); @@ -216,7 +221,9 @@ void SubsonicDynamicPlaylist::GetAlbum(SubsonicService* service, song.set_length_nanosec(length); QUrl url = QUrl(QString("subsonic://%1").arg(id)); QUrl cover_url = service->BuildRequestUrl("getCoverArt"); - cover_url.addQueryItem("id", id); + QUrlQuery cover_url_query(cover_url.query()); + cover_url_query.addQueryItem("id", id); + cover_url.setQuery(cover_url_query); song.set_art_automatic(cover_url.toEncoded()); song.set_url(url); song.set_filesize(reader.attributes().value("size").toString().toInt()); diff --git a/src/internet/subsonic/subsonicservice.cpp b/src/internet/subsonic/subsonicservice.cpp index 94375ac64..aa9c00511 100644 --- a/src/internet/subsonic/subsonicservice.cpp +++ b/src/internet/subsonic/subsonicservice.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include "core/application.h" #include "core/closure.h" @@ -244,10 +245,12 @@ void SubsonicService::Ping() { QUrl SubsonicService::BuildRequestUrl(const QString& view) const { QUrl url(working_server_ + "/rest/" + view + ".view"); - url.addQueryItem("v", kApiVersion); - url.addQueryItem("c", kApiClientName); - url.addQueryItem("u", username_); - url.addQueryItem("p", QString("enc:" + password_.toUtf8().toHex())); + QUrlQuery url_query; + url_query.addQueryItem("v", kApiVersion); + url_query.addQueryItem("c", kApiClientName); + url_query.addQueryItem("u", username_); + url_query.addQueryItem("p", QString("enc:" + password_.toUtf8().toHex())); + url.setQuery(url_query); return url; } @@ -542,9 +545,14 @@ void SubsonicLibraryScanner::OnGetAlbumFinished(QNetworkReply* reply) { qint64 length = reader.attributes().value("duration").toString().toInt(); length *= kNsecPerSec; song.set_length_nanosec(length); - QUrl url = QUrl(QString("subsonic://%1").arg(id)); + QUrl url = QUrl(QString("subsonic://")); + QUrlQuery song_query(url.query()); + song_query.addQueryItem("id", id); + url.setQuery(song_query); QUrl cover_url = service_->BuildRequestUrl("getCoverArt"); - cover_url.addQueryItem("id", id); + QUrlQuery cover_url_query(url.query()); + cover_url_query.addQueryItem("id", id); + cover_url.setQuery(cover_url_query); song.set_art_automatic(cover_url.toEncoded()); song.set_url(url); song.set_filesize(reader.attributes().value("size").toString().toInt()); @@ -576,9 +584,11 @@ void SubsonicLibraryScanner::OnGetAlbumFinished(QNetworkReply* reply) { void SubsonicLibraryScanner::GetAlbumList(int offset) { QUrl url = service_->BuildRequestUrl("getAlbumList2"); - url.addQueryItem("type", "alphabeticalByName"); - url.addQueryItem("size", QString::number(kAlbumChunkSize)); - url.addQueryItem("offset", QString::number(offset)); + QUrlQuery url_query(url.query()); + url_query.addQueryItem("type", "alphabeticalByName"); + url_query.addQueryItem("size", QString::number(kAlbumChunkSize)); + url_query.addQueryItem("offset", QString::number(offset)); + url.setQuery(url_query); QNetworkReply* reply = service_->Send(url); NewClosure(reply, SIGNAL(finished()), this, SLOT(OnGetAlbumListFinished(QNetworkReply*, int)), reply, offset); @@ -586,10 +596,12 @@ void SubsonicLibraryScanner::GetAlbumList(int offset) { void SubsonicLibraryScanner::GetAlbum(const QString& id) { QUrl url = service_->BuildRequestUrl("getAlbum"); - url.addQueryItem("id", id); + QUrlQuery url_query(url.query()); + url_query.addQueryItem("id", id); if (service_->IsAmpache()) { - url.addQueryItem("ampache", "1"); + url_query.addQueryItem("ampache", "1"); } + url.setQuery(url_query); QNetworkReply* reply = service_->Send(url); NewClosure(reply, SIGNAL(finished()), this, SLOT(OnGetAlbumFinished(QNetworkReply*)), reply); diff --git a/src/internet/subsonic/subsonicurlhandler.cpp b/src/internet/subsonic/subsonicurlhandler.cpp index d2bbd4b17..f3a33faac 100644 --- a/src/internet/subsonic/subsonicurlhandler.cpp +++ b/src/internet/subsonic/subsonicurlhandler.cpp @@ -17,6 +17,8 @@ along with Clementine. If not, see . */ +#include + #include "subsonicservice.h" #include "subsonicurlhandler.h" @@ -28,7 +30,10 @@ UrlHandler::LoadResult SubsonicUrlHandler::StartLoading(const QUrl& url) { if (service_->login_state() != SubsonicService::LoginState_Loggedin) return LoadResult(url); + QUrlQuery id(url.query()); QUrl newurl = service_->BuildRequestUrl("stream"); - newurl.addQueryItem("id", url.host()); + QUrlQuery url_query(newurl.query()); + url_query.addQueryItem("id", id.queryItemValue("id")); + newurl.setQuery(url_query); return LoadResult(url, LoadResult::TrackAvailable, newurl); } diff --git a/src/library/librarybackend.cpp b/src/library/librarybackend.cpp index dced2a2d8..86ab57b3f 100644 --- a/src/library/librarybackend.cpp +++ b/src/library/librarybackend.cpp @@ -111,8 +111,8 @@ void LibraryBackend::ChangeDirPath(int id, const QString& old_path, ScopedTransaction t(&db); // Do the dirs table - QSqlQuery q( - QString("UPDATE %1 SET path=:path WHERE ROWID=:id").arg(dirs_table_), db); + QSqlQuery q(db); + q.prepare(QString("UPDATE %1 SET path=:path WHERE ROWID=:id").arg(dirs_table_)); q.bindValue(":path", new_path); q.bindValue(":id", id); q.exec(); @@ -124,24 +124,24 @@ void LibraryBackend::ChangeDirPath(int id, const QString& old_path, const int path_len = old_url.length(); // Do the subdirs table - q = QSqlQuery(QString( + q = QSqlQuery(db); + q.prepare(QString( "UPDATE %1 SET path=:path || substr(path, %2)" " WHERE directory=:id") .arg(subdirs_table_) - .arg(path_len), - db); + .arg(path_len)); q.bindValue(":path", new_url); q.bindValue(":id", id); q.exec(); if (db_->CheckErrors(q)) return; // Do the songs table - q = QSqlQuery(QString( + q = QSqlQuery(db); + q.prepare(QString( "UPDATE %1 SET filename=:path || substr(filename, %2)" " WHERE directory=:id") .arg(songs_table_) - .arg(path_len), - db); + .arg(path_len)); q.bindValue(":path", new_url); q.bindValue(":id", id); q.exec(); @@ -156,7 +156,8 @@ DirectoryList LibraryBackend::GetAllDirectories() { DirectoryList ret; - QSqlQuery q(QString("SELECT ROWID, path FROM %1").arg(dirs_table_), db); + QSqlQuery q(db); + q.prepare(QString("SELECT ROWID, path FROM %1").arg(dirs_table_)); q.exec(); if (db_->CheckErrors(q)) return ret; @@ -177,10 +178,10 @@ SubdirectoryList LibraryBackend::SubdirsInDirectory(int id) { } SubdirectoryList LibraryBackend::SubdirsInDirectory(int id, QSqlDatabase& db) { - QSqlQuery q(QString( + QSqlQuery q(db); + q.prepare(QString( "SELECT path, mtime FROM %1" - " WHERE directory = :dir").arg(subdirs_table_), - db); + " WHERE directory = :dir").arg(subdirs_table_)); q.bindValue(":dir", id); q.exec(); if (db_->CheckErrors(q)) return SubdirectoryList(); @@ -201,9 +202,9 @@ void LibraryBackend::UpdateTotalSongCount() { QMutexLocker l(db_->Mutex()); QSqlDatabase db(db_->Connect()); - QSqlQuery q(QString("SELECT COUNT(*) FROM %1 WHERE unavailable = 0") - .arg(songs_table_), - db); + QSqlQuery q(db); + q.prepare(QString("SELECT COUNT(*) FROM %1 WHERE unavailable = 0") + .arg(songs_table_)); q.exec(); if (db_->CheckErrors(q)) return; if (!q.next()) return; @@ -225,10 +226,10 @@ void LibraryBackend::AddDirectory(const QString& path) { QMutexLocker l(db_->Mutex()); QSqlDatabase db(db_->Connect()); - QSqlQuery q(QString( + QSqlQuery q(db); + q.prepare(QString( "INSERT INTO %1 (path, subdirs)" - " VALUES (:path, 1)").arg(dirs_table_), - db); + " VALUES (:path, 1)").arg(dirs_table_)); q.bindValue(":path", db_path); q.exec(); if (db_->CheckErrors(q)) return; @@ -250,15 +251,15 @@ void LibraryBackend::RemoveDirectory(const Directory& dir) { ScopedTransaction transaction(&db); // Delete the subdirs that were in this directory - QSqlQuery q( - QString("DELETE FROM %1 WHERE directory = :id").arg(subdirs_table_), db); + QSqlQuery q(db); + q.prepare(QString("DELETE FROM %1 WHERE directory = :id").arg(subdirs_table_)); q.bindValue(":id", dir.id); q.exec(); if (db_->CheckErrors(q)) return; // Now remove the directory itself - q = QSqlQuery(QString("DELETE FROM %1 WHERE ROWID = :id").arg(dirs_table_), - db); + q = QSqlQuery(db); + q.prepare(QString("DELETE FROM %1 WHERE ROWID = :id").arg(dirs_table_)); q.bindValue(":id", dir.id); q.exec(); if (db_->CheckErrors(q)) return; @@ -272,10 +273,10 @@ SongList LibraryBackend::FindSongsInDirectory(int id) { QMutexLocker l(db_->Mutex()); QSqlDatabase db(db_->Connect()); - QSqlQuery q( + QSqlQuery q(db); + q.prepare( QString("SELECT ROWID, " + Song::kColumnSpec + - " FROM %1 WHERE directory = :directory").arg(songs_table_), - db); + " FROM %1 WHERE directory = :directory").arg(songs_table_)); q.bindValue(":directory", id); q.exec(); if (db_->CheckErrors(q)) return SongList(); @@ -302,25 +303,22 @@ void LibraryBackend::SongPathChanged(const Song& song, void LibraryBackend::AddOrUpdateSubdirs(const SubdirectoryList& subdirs) { QMutexLocker l(db_->Mutex()); QSqlDatabase db(db_->Connect()); - QSqlQuery find_query( - QString( + QSqlQuery find_query(db); + find_query.prepare(QString( "SELECT ROWID FROM %1" - " WHERE directory = :id AND path = :path").arg(subdirs_table_), - db); - QSqlQuery add_query(QString( + " WHERE directory = :id AND path = :path").arg(subdirs_table_)); + QSqlQuery add_query(db); + add_query.prepare(QString( "INSERT INTO %1 (directory, path, mtime)" - " VALUES (:id, :path, :mtime)").arg(subdirs_table_), - db); - QSqlQuery update_query( - QString( + " VALUES (:id, :path, :mtime)").arg(subdirs_table_)); + QSqlQuery update_query(db); + update_query.prepare(QString( "UPDATE %1 SET mtime = :mtime" - " WHERE directory = :id AND path = :path").arg(subdirs_table_), - db); - QSqlQuery delete_query( - QString( + " WHERE directory = :id AND path = :path").arg(subdirs_table_)); + QSqlQuery delete_query(db); + delete_query.prepare(QString( "DELETE FROM %1" - " WHERE directory = :id AND path = :path").arg(subdirs_table_), - db); + " WHERE directory = :id AND path = :path").arg(subdirs_table_)); ScopedTransaction transaction(&db); for (const Subdirectory& subdir : subdirs) { @@ -359,25 +357,24 @@ void LibraryBackend::AddOrUpdateSongs(const SongList& songs) { QMutexLocker l(db_->Mutex()); QSqlDatabase db(db_->Connect()); - QSqlQuery check_dir( - QString("SELECT ROWID FROM %1 WHERE ROWID = :id").arg(dirs_table_), db); - QSqlQuery add_song(QString("INSERT INTO %1 (" + Song::kColumnSpec + + QSqlQuery check_dir(db); + check_dir.prepare(QString("SELECT ROWID FROM %1 WHERE ROWID = :id").arg(dirs_table_)); + QSqlQuery add_song(db); + add_song.prepare(QString("INSERT INTO %1 (" + Song::kColumnSpec + ")" " VALUES (" + - Song::kBindSpec + ")").arg(songs_table_), - db); - QSqlQuery update_song(QString("UPDATE %1 SET " + Song::kUpdateSpec + - " WHERE ROWID = :id").arg(songs_table_), - db); - QSqlQuery add_song_fts( - QString("INSERT INTO %1 (ROWID, " + Song::kFtsColumnSpec + + Song::kBindSpec + ")").arg(songs_table_)); + QSqlQuery update_song(db); + update_song.prepare(QString("UPDATE %1 SET " + Song::kUpdateSpec + + " WHERE ROWID = :id").arg(songs_table_)); + QSqlQuery add_song_fts(db); + add_song_fts.prepare(QString("INSERT INTO %1 (ROWID, " + Song::kFtsColumnSpec + ")" " VALUES (:id, " + - Song::kFtsBindSpec + ")").arg(fts_table_), - db); - QSqlQuery update_song_fts(QString("UPDATE %1 SET " + Song::kFtsUpdateSpec + - " WHERE ROWID = :id").arg(fts_table_), - db); + Song::kFtsBindSpec + ")").arg(fts_table_)); + QSqlQuery update_song_fts(db); + update_song_fts.prepare(QString("UPDATE %1 SET " + Song::kFtsUpdateSpec + + " WHERE ROWID = :id").arg(fts_table_)); ScopedTransaction transaction(&db); @@ -450,9 +447,9 @@ void LibraryBackend::UpdateMTimesOnly(const SongList& songs) { QMutexLocker l(db_->Mutex()); QSqlDatabase db(db_->Connect()); - QSqlQuery q(QString("UPDATE %1 SET mtime = :mtime WHERE ROWID = :id") - .arg(songs_table_), - db); + QSqlQuery q(db); + q.prepare(QString("UPDATE %1 SET mtime = :mtime WHERE ROWID = :id") + .arg(songs_table_)); ScopedTransaction transaction(&db); for (const Song& song : songs) { @@ -468,10 +465,10 @@ void LibraryBackend::DeleteSongs(const SongList& songs) { QMutexLocker l(db_->Mutex()); QSqlDatabase db(db_->Connect()); - QSqlQuery remove( - QString("DELETE FROM %1 WHERE ROWID = :id").arg(songs_table_), db); - QSqlQuery remove_fts( - QString("DELETE FROM %1 WHERE ROWID = :id").arg(fts_table_), db); + QSqlQuery remove(db); + remove.prepare(QString("DELETE FROM %1 WHERE ROWID = :id").arg(songs_table_)); + QSqlQuery remove_fts(db); + remove_fts.prepare(QString("DELETE FROM %1 WHERE ROWID = :id").arg(fts_table_)); ScopedTransaction transaction(&db); for (const Song& song : songs) { @@ -495,10 +492,10 @@ void LibraryBackend::MarkSongsUnavailable(const SongList& songs, QMutexLocker l(db_->Mutex()); QSqlDatabase db(db_->Connect()); - QSqlQuery remove(QString("UPDATE %1 SET unavailable = %2 WHERE ROWID = :id") + QSqlQuery remove(db); + remove.prepare(QString("UPDATE %1 SET unavailable = %2 WHERE ROWID = :id") .arg(songs_table_) - .arg(int(unavailable)), - db); + .arg(int(unavailable))); ScopedTransaction transaction(&db); for (const Song& song : songs) { @@ -643,14 +640,14 @@ SongList LibraryBackend::GetSongsByForeignId(const QStringList& ids, QString in = ids.join(","); - QSqlQuery q( - QString( + QSqlQuery q(db); + q.prepare( + QString( "SELECT %2.ROWID, " + Song::kColumnSpec + ", %2.%3" " FROM %2, %1" " WHERE %2.%3 IN (%4) AND %1.ROWID = %2.ROWID AND unavailable = 0") - .arg(songs_table_, table, column, in), - db); + .arg(songs_table_, table, column, in)); q.exec(); if (db_->CheckErrors(q)) return SongList(); @@ -675,10 +672,10 @@ SongList LibraryBackend::GetSongsById(const QStringList& ids, QSqlDatabase& db) { QString in = ids.join(","); - QSqlQuery q(QString("SELECT ROWID, " + Song::kColumnSpec + + QSqlQuery q(db); + q.prepare(QString("SELECT ROWID, " + Song::kColumnSpec + " FROM %1" - " WHERE ROWID IN (%2)").arg(songs_table_, in), - db); + " WHERE ROWID IN (%2)").arg(songs_table_, in)); q.exec(); if (db_->CheckErrors(q)) return SongList(); @@ -753,11 +750,11 @@ void LibraryBackend::UpdateCompilations() { // in the same // directory - QSqlQuery q( + QSqlQuery q(db); + q.prepare( QString( "SELECT effective_albumartist, album, filename, sampler " - "FROM %1 WHERE unavailable = 0 ORDER BY album").arg(songs_table_), - db); + "FROM %1 WHERE unavailable = 0 ORDER BY album").arg(songs_table_)); q.exec(); if (db_->CheckErrors(q)) return; @@ -785,21 +782,21 @@ void LibraryBackend::UpdateCompilations() { } // Now mark the songs that we think are in compilations - QSqlQuery update( + QSqlQuery update(db); + update.prepare( QString( "UPDATE %1" " SET sampler = :sampler," " effective_compilation = ((compilation OR :sampler OR " "forced_compilation_on) AND NOT forced_compilation_off) + 0" - " WHERE album = :album AND unavailable = 0").arg(songs_table_), - db); - QSqlQuery find_songs( + " WHERE album = :album AND unavailable = 0").arg(songs_table_)); + QSqlQuery find_songs(db); + find_songs.prepare( QString( "SELECT ROWID, " + Song::kColumnSpec + " FROM %1" " WHERE album = :album AND sampler = :sampler AND unavailable = 0") - .arg(songs_table_), - db); + .arg(songs_table_)); SongList deleted_songs; SongList added_songs; @@ -993,7 +990,8 @@ void LibraryBackend::UpdateManualAlbumArt(const QString& artist, sql += " AND artist = :artist"; } - QSqlQuery q(sql, db); + QSqlQuery q(db); + q.prepare(sql); q.bindValue(":art", art); q.bindValue(":album", album); if (!albumartist.isNull() && !albumartist.isEmpty()) { @@ -1052,7 +1050,8 @@ void LibraryBackend::ForceCompilation(const QString& album, " WHERE album = :album AND unavailable = 0").arg(songs_table_)); if (!artist.isEmpty()) sql += " AND artist = :artist"; - QSqlQuery q(sql, db); + QSqlQuery q(db); + q.prepare(sql); q.bindValue(":forced_compilation_on", on ? 1 : 0); q.bindValue(":forced_compilation_off", on ? 0 : 1); q.bindValue(":album", album); @@ -1090,7 +1089,8 @@ SongList LibraryBackend::FindSongs(const smart_playlists::Search& search) { // Run the query SongList ret; - QSqlQuery query(sql, db); + QSqlQuery query(db); + query.prepare(sql); query.exec(); if (db_->CheckErrors(query)) return ret; @@ -1117,13 +1117,13 @@ void LibraryBackend::IncrementPlayCount(int id) { QMutexLocker l(db_->Mutex()); QSqlDatabase db(db_->Connect()); - QSqlQuery q(QString( + QSqlQuery q(db); + q.prepare(QString( "UPDATE %1 SET playcount = playcount + 1," " lastplayed = :now," " score = " + QString(kNewScoreSql).arg("1.0") + - " WHERE ROWID = :id").arg(songs_table_), - db); + " WHERE ROWID = :id").arg(songs_table_)); q.bindValue(":now", QDateTime::currentDateTime().toTime_t()); q.bindValue(":id", id); q.exec(); @@ -1140,12 +1140,12 @@ void LibraryBackend::IncrementSkipCount(int id, float progress) { QMutexLocker l(db_->Mutex()); QSqlDatabase db(db_->Connect()); - QSqlQuery q(QString( + QSqlQuery q(db); + q.prepare(QString( "UPDATE %1 SET skipcount = skipcount + 1," " score = " + QString(kNewScoreSql).arg(progress) + - " WHERE ROWID = :id").arg(songs_table_), - db); + " WHERE ROWID = :id").arg(songs_table_)); q.bindValue(":id", id); q.exec(); if (db_->CheckErrors(q)) return; @@ -1160,11 +1160,11 @@ void LibraryBackend::ResetStatistics(int id) { QMutexLocker l(db_->Mutex()); QSqlDatabase db(db_->Connect()); - QSqlQuery q(QString( + QSqlQuery q(db); + q.prepare(QString( "UPDATE %1 SET playcount = 0, skipcount = 0," " lastplayed = -1, score = 0" - " WHERE ROWID = :id").arg(songs_table_), - db); + " WHERE ROWID = :id").arg(songs_table_)); q.bindValue(":id", id); q.exec(); if (db_->CheckErrors(q)) return; @@ -1193,10 +1193,10 @@ void LibraryBackend::UpdateSongsRating(const QList& id_list, id_str_list << QString::number(i); } QString ids = id_str_list.join(","); - QSqlQuery q(QString( + QSqlQuery q(db); + q.prepare(QString( "UPDATE %1 SET rating = :rating" - " WHERE ROWID IN (%2)").arg(songs_table_, ids), - db); + " WHERE ROWID IN (%2)").arg(songs_table_, ids)); q.bindValue(":rating", rating); q.exec(); if (db_->CheckErrors(q)) return; diff --git a/src/library/librarymodel.cpp b/src/library/librarymodel.cpp index 709154ccc..6e7dd0461 100644 --- a/src/library/librarymodel.cpp +++ b/src/library/librarymodel.cpp @@ -164,7 +164,8 @@ void LibraryModel::Init(bool async) { new LibraryItem(LibraryItem::Type_LoadingIndicator, root_); loading->display_text = tr("Loading..."); loading->lazy_loaded = true; - reset(); + beginResetModel(); + endResetModel(); // Show a loading indicator in the status bar too. init_task_id_ = app_->task_manager()->StartTask(tr("Loading songs")); diff --git a/src/library/libraryquery.cpp b/src/library/libraryquery.cpp index 0ebc3ddb0..fea6d0d6c 100644 --- a/src/library/libraryquery.cpp +++ b/src/library/libraryquery.cpp @@ -252,7 +252,8 @@ QSqlQuery LibraryQuery::Exec(QSqlDatabase db, const QString& songs_table, sql.replace("%fts_table_noprefix", fts_table.section('.', -1, -1)); sql.replace("%fts_table", fts_table); - query_ = QSqlQuery(sql, db); + query_ = QSqlQuery(db); + query_.prepare(sql); // Bind values for (const QVariant& value : bound_values_) { diff --git a/src/main.cpp b/src/main.cpp index 0959c8ce1..edb883a12 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -20,9 +20,11 @@ #include #ifdef Q_OS_WIN32 -#define _WIN32_WINNT 0x0600 -#include -#include +# ifndef _WIN32_WINNT +# define _WIN32_WINNT 0x0600 +# endif +# include +# include #endif // Q_OS_WIN32 #ifdef Q_OS_UNIX @@ -95,33 +97,22 @@ const QDBusArgument& operator>>(const QDBusArgument& arg, QImage& image); #endif #ifdef Q_OS_WIN32 -#include +#include #endif // Load sqlite plugin on windows and mac. #include -Q_IMPORT_PLUGIN(qsqlite) +Q_IMPORT_PLUGIN(QSQLiteDriverPlugin) namespace { void LoadTranslation(const QString& prefix, const QString& path, const QString& language) { -#if QT_VERSION < 0x040700 - // QTranslator::load will try to open and read "clementine" if it exists, - // without checking if it's a file first. - // This was fixed in Qt 4.7 - QFileInfo maybe_clementine_directory(path + "/clementine"); - if (maybe_clementine_directory.exists() && - !maybe_clementine_directory.isFile()) - return; -#endif - QTranslator* t = new PoTranslator; if (t->load(prefix + "_" + language, path)) QCoreApplication::installTranslator(t); else delete t; - QTextCodec::setCodecForTr(QTextCodec::codecForLocale()); } void IncreaseFDLimit() { @@ -164,10 +155,10 @@ void SetGstreamerEnvironment() { // On windows and mac we bundle the gstreamer plugins with clementine #ifdef USE_BUNDLE #if defined(Q_OS_DARWIN) - scanner_path = QCoreApplication::applicationDirPath() + "/" + USE_BUNDLE_DIR + - "/gst-plugin-scanner"; - plugin_path = QCoreApplication::applicationDirPath() + "/" + USE_BUNDLE_DIR + - "/gstreamer"; + scanner_path = + QCoreApplication::applicationDirPath() + "/" + USE_BUNDLE_DIR + "/gst-plugin-scanner"; + plugin_path = + QCoreApplication::applicationDirPath() + "/" + USE_BUNDLE_DIR + "/gstreamer"; #elif defined(Q_OS_WIN32) plugin_path = QCoreApplication::applicationDirPath() + "/gstreamer-plugins"; #endif @@ -191,8 +182,8 @@ void SetGstreamerEnvironment() { } #if defined(Q_OS_DARWIN) && defined(USE_BUNDLE) - SetEnv("GIO_EXTRA_MODULES", QCoreApplication::applicationDirPath() + "/" + - USE_BUNDLE_DIR + "/gio-modules"); + SetEnv("GIO_EXTRA_MODULES", + QCoreApplication::applicationDirPath() + "/" + USE_BUNDLE_DIR + "/gio-modules"); #endif SetEnv("PULSE_PROP_media.role", "music"); @@ -325,7 +316,7 @@ int main(int argc, char* argv[]) { // Output the version, so when people attach log output to bug reports they // don't have to tell us which version they're using. - qLog(Info) << "Clementine" << CLEMENTINE_VERSION_DISPLAY; + qLog(Info) << "Clementine-qt5" << CLEMENTINE_VERSION_DISPLAY; // Seed the random number generators. time_t t = time(nullptr); @@ -353,18 +344,15 @@ int main(int argc, char* argv[]) { } #if defined(Q_OS_DARWIN) && defined(USE_BUNDLE) - qLog(Debug) << "Looking for resources in" + - QCoreApplication::applicationDirPath() + "/" + - USE_BUNDLE_DIR; - QCoreApplication::setLibraryPaths(QStringList() - << QCoreApplication::applicationDirPath() + - "/" + USE_BUNDLE_DIR); + qLog(Debug) << "Looking for resources in" + QCoreApplication::applicationDirPath() + "/" + USE_BUNDLE_DIR; + QCoreApplication::setLibraryPaths( + QStringList() << QCoreApplication::applicationDirPath() + "/" + USE_BUNDLE_DIR); #endif a.setQuitOnLastWindowClosed(false); - // Do this check again because another instance might have started by now - if (a.isRunning() && a.sendMessage(options.Serialize(), 5000)) { + if (a.isRunning() && + a.sendMessage(QString::fromLatin1(options.Serialize()), 5000)) { return 0; } @@ -374,8 +362,6 @@ int main(int argc, char* argv[]) { QCoreApplication::setAttribute(Qt::AA_DontShowIconsInMenus, false); #else QCoreApplication::setAttribute(Qt::AA_DontShowIconsInMenus, true); - // Fixes focus issue with NSSearchField, see QTBUG-11401 - QCoreApplication::setAttribute(Qt::AA_NativeWindows, true); #endif SetGstreamerEnvironment(); @@ -444,6 +430,7 @@ int main(int argc, char* argv[]) { QtConcurrent::run(&ParseAProto); Application app; + QObject::connect(&a, SIGNAL(aboutToQuit()), &app, SLOT(SaveSettings_())); app.set_language_name(language); // Network proxy @@ -477,8 +464,8 @@ int main(int argc, char* argv[]) { #ifdef HAVE_DBUS QObject::connect(&mpris, SIGNAL(RaiseMainWindow()), &w, SLOT(Raise())); #endif - QObject::connect(&a, SIGNAL(messageReceived(QByteArray)), &w, - SLOT(CommandlineOptionsReceived(QByteArray))); + QObject::connect(&a, SIGNAL(messageReceived(QString)), &w, + SLOT(CommandlineOptionsReceived(QString))); int ret = a.exec(); @@ -494,7 +481,11 @@ int main(int argc, char* argv[]) { QFile self_maps("/proc/self/maps"); if (self_maps.open(QIODevice::ReadOnly)) { QByteArray data = self_maps.readAll(); - if (data.contains("libnvidia-tls.so.")) { + if (data.contains("libnvidia-tls.so.304.37") || + data.contains("libnvidia-tls.so.285.03") || + data.contains("libnvidia-tls.so.280.13") || + data.contains("libnvidia-tls.so.275.28") || + data.contains("libnvidia-tls.so.275.19")) { qLog(Warning) << "Exiting immediately to work around NVIDIA driver bug"; _exit(ret); } diff --git a/src/moodbar/moodbaritemdelegate.cpp b/src/moodbar/moodbaritemdelegate.cpp index 953dfce6a..f17b4a466 100644 --- a/src/moodbar/moodbaritemdelegate.cpp +++ b/src/moodbar/moodbaritemdelegate.cpp @@ -21,7 +21,6 @@ #include "moodbarrenderer.h" #include "core/application.h" #include "core/closure.h" -#include "core/qhash_qurl.h" #include "playlist/playlist.h" #include "playlist/playlistview.h" diff --git a/src/moodbar/moodbarloader.cpp b/src/moodbar/moodbarloader.cpp index 5b50ed9e7..6bc23d8ee 100644 --- a/src/moodbar/moodbarloader.cpp +++ b/src/moodbar/moodbarloader.cpp @@ -31,7 +31,6 @@ #include "core/application.h" #include "core/closure.h" #include "core/logging.h" -#include "core/qhash_qurl.h" #include "core/utilities.h" #ifdef Q_OS_WIN32 diff --git a/src/moodbar/moodbarpipeline.cpp b/src/moodbar/moodbarpipeline.cpp index bddbf678c..7d15f4d6d 100644 --- a/src/moodbar/moodbarpipeline.cpp +++ b/src/moodbar/moodbarpipeline.cpp @@ -58,7 +58,7 @@ bool MoodbarPipeline::IsAvailable() { GstElement* MoodbarPipeline::CreateElement(const QString& factory_name) { GstElement* ret = - gst_element_factory_make(factory_name.toAscii().constData(), nullptr); + gst_element_factory_make(factory_name.toLatin1().constData(), nullptr); if (ret) { gst_bin_add(GST_BIN(pipeline_), ret); diff --git a/src/musicbrainz/acoustidclient.cpp b/src/musicbrainz/acoustidclient.cpp index 346fdb708..8fa8fa6ee 100644 --- a/src/musicbrainz/acoustidclient.cpp +++ b/src/musicbrainz/acoustidclient.cpp @@ -22,8 +22,11 @@ #include #include #include - -#include +#include +#include +#include +#include +#include #include "core/closure.h" #include "core/logging.h" @@ -52,7 +55,9 @@ void AcoustidClient::Start(int id, const QString& fingerprint, << Param("fingerprint", fingerprint); QUrl url(kUrl); - url.setQueryItems(parameters); + QUrlQuery url_query; + url_query.setQueryItems(parameters); + url.setQuery(url_query); QNetworkRequest req(url); QNetworkReply* reply = network_->get(req); @@ -96,15 +101,17 @@ void AcoustidClient::RequestFinished(QNetworkReply* reply, int request_id) { return; } - QJson::Parser parser; - bool ok = false; - QVariantMap result = parser.parse(reply, &ok).toMap(); - if (!ok) { + QJsonParseError error; + QJsonDocument json_document = QJsonDocument::fromJson(reply->readAll(), &error); + + if (error.error != QJsonParseError::NoError) { emit Finished(request_id, QStringList()); return; } - QString status = result["status"].toString(); + QJsonObject json_object = json_document.object(); + + QString status = json_object["status"].toString(); if (status != "ok") { emit Finished(request_id, QStringList()); return; @@ -115,18 +122,18 @@ void AcoustidClient::RequestFinished(QNetworkReply* reply, int request_id) { // -then sort results by number of sources (the results are originally // unsorted but results with more sources are likely to be more accurate) // -keep only the ids, as sources where useful only to sort the results - QVariantList results = result["results"].toList(); + QJsonArray json_results = json_object["results"].toArray(); // List of pairs QList id_source_list; - for (const QVariant& v : results) { - QVariantMap r = v.toMap(); - if (r.contains("recordings")) { - QVariantList recordings = r["recordings"].toList(); - for (const QVariant& recording : recordings) { - QVariantMap o = recording.toMap(); - if (o.contains("id")) { + for (const QJsonValue& v : json_results) { + QJsonObject r = v.toObject(); + if (!r["recordings"].isUndefined()) { + QJsonArray json_recordings = r["recordings"].toArray(); + for (const QJsonValue& recording : json_recordings) { + QJsonObject o = recording.toObject(); + if (!o["id"].isUndefined()) { id_source_list << IdSource(o["id"].toString(), o["sources"].toInt()); } } diff --git a/src/musicbrainz/chromaprinter.cpp b/src/musicbrainz/chromaprinter.cpp index 2f474c50e..1a4d3ccec 100644 --- a/src/musicbrainz/chromaprinter.cpp +++ b/src/musicbrainz/chromaprinter.cpp @@ -29,6 +29,10 @@ #include "core/logging.h" #include "core/signalchecker.h" +#ifndef u_int32_t +typedef unsigned int u_int32_t; +#endif + static const int kDecodeRate = 11025; static const int kDecodeChannels = 1; static const int kPlayLengthSecs = 30; @@ -42,7 +46,7 @@ Chromaprinter::~Chromaprinter() {} GstElement* Chromaprinter::CreateElement(const QString& factory_name, GstElement* bin) { GstElement* ret = gst_element_factory_make( - factory_name.toAscii().constData(), factory_name.toAscii().constData()); + factory_name.toLatin1().constData(), factory_name.toLatin1().constData()); if (ret && bin) gst_bin_add(GST_BIN(bin), ret); diff --git a/src/musicbrainz/musicbrainzclient.cpp b/src/musicbrainz/musicbrainzclient.cpp index 6eceebd37..f2dd7683e 100644 --- a/src/musicbrainz/musicbrainzclient.cpp +++ b/src/musicbrainz/musicbrainzclient.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include "core/closure.h" #include "core/logging.h" @@ -52,7 +53,9 @@ void MusicBrainzClient::Start(int id, const QStringList& mbid_list) { parameters << Param("inc", "artists+releases+media"); QUrl url(kTrackUrl + mbid); - url.setQueryItems(parameters); + QUrlQuery url_query; + url_query.setQueryItems(parameters); + url.setQuery(url_query); QNetworkRequest req(url); QNetworkReply* reply = network_->get(req); @@ -76,7 +79,9 @@ void MusicBrainzClient::StartDiscIdRequest(const QString& discid) { parameters << Param("inc", "artists+recordings"); QUrl url(kDiscUrl + discid); - url.setQueryItems(parameters); + QUrlQuery url_query; + url_query.setQueryItems(parameters); + url.setQuery(url_query); QNetworkRequest req(url); QNetworkReply* reply = network_->get(req); diff --git a/src/networkremote/networkremote.cpp b/src/networkremote/networkremote.cpp index 0ec86e454..91b324833 100644 --- a/src/networkremote/networkremote.cpp +++ b/src/networkremote/networkremote.cpp @@ -197,6 +197,10 @@ bool NetworkRemote::IpIsPrivate(const QHostAddress& address) { address.isInSubnet(QHostAddress::parseSubnet("192.168.0.0/16")) || address.isInSubnet(QHostAddress::parseSubnet("172.16.0.0/12")) || address.isInSubnet(QHostAddress::parseSubnet("10.0.0.0/8")) || + // Private v4 range translated to v6 + address.isInSubnet(QHostAddress::parseSubnet("::ffff:192.168.0.0/112")) || + address.isInSubnet(QHostAddress::parseSubnet("::ffff:172.16.0.0/108")) || + address.isInSubnet(QHostAddress::parseSubnet("::ffff:10.0.0.0/104")) || // Private v6 range address.isInSubnet(QHostAddress::parseSubnet("fc00::/7")); } diff --git a/src/networkremote/outgoingdatacreator.cpp b/src/networkremote/outgoingdatacreator.cpp index 8ad04cf82..595170394 100644 --- a/src/networkremote/outgoingdatacreator.cpp +++ b/src/networkremote/outgoingdatacreator.cpp @@ -183,7 +183,7 @@ void OutgoingDataCreator::SendClementineInfo() { QString version = QString("%1 %2").arg(QCoreApplication::applicationName(), QCoreApplication::applicationVersion()); - info->set_version(version.toAscii()); + info->set_version(version.toLatin1()); SendDataToClients(&msg); } diff --git a/src/playlist/playlist.cpp b/src/playlist/playlist.cpp index 07848e643..05c63f8ae 100644 --- a/src/playlist/playlist.cpp +++ b/src/playlist/playlist.cpp @@ -39,7 +39,6 @@ #include "core/closure.h" #include "core/logging.h" #include "core/player.h" -#include "core/qhash_qurl.h" #include "core/tagreaderclient.h" #include "core/timeconstants.h" #include "internet/core/internetmimedata.h" diff --git a/src/playlist/playlistbackend.cpp b/src/playlist/playlistbackend.cpp index d8f3d3fd7..bb5d065a5 100644 --- a/src/playlist/playlistbackend.cpp +++ b/src/playlist/playlistbackend.cpp @@ -78,14 +78,13 @@ PlaylistBackend::PlaylistList PlaylistBackend::GetPlaylists( condition = " WHERE " + condition_list.join(" OR "); } - QSqlQuery q( - "SELECT ROWID, name, last_played, dynamic_playlist_type," + QSqlQuery q(db); + q.prepare("SELECT ROWID, name, last_played, dynamic_playlist_type," " dynamic_playlist_data, dynamic_playlist_backend," " special_type, ui_path, is_favorite" " FROM playlists" " " + - condition + " ORDER BY ui_order", - db); + condition + " ORDER BY ui_order"); q.exec(); if (db_->CheckErrors(q)) return ret; @@ -110,13 +109,12 @@ PlaylistBackend::Playlist PlaylistBackend::GetPlaylist(int id) { QMutexLocker l(db_->Mutex()); QSqlDatabase db(db_->Connect()); - QSqlQuery q( - "SELECT ROWID, name, last_played, dynamic_playlist_type," + QSqlQuery q(db); + q.prepare("SELECT ROWID, name, last_played, dynamic_playlist_type," " dynamic_playlist_data, dynamic_playlist_backend," " special_type, ui_path, is_favorite" " FROM playlists" - " WHERE ROWID=:id", - db); + " WHERE ROWID=:id"); q.bindValue(":id", id); q.exec(); if (db_->CheckErrors(q)) return Playlist(); @@ -293,23 +291,22 @@ void PlaylistBackend::SavePlaylist(int playlist, const PlaylistItemList& items, qLog(Debug) << "Saving playlist" << playlist; - QSqlQuery clear("DELETE FROM playlist_items WHERE playlist = :playlist", db); - QSqlQuery insert( - "INSERT INTO playlist_items" + QSqlQuery clear(db); + clear.prepare("DELETE FROM playlist_items WHERE playlist = :playlist"); + QSqlQuery insert(db); + insert.prepare("INSERT INTO playlist_items" " (playlist, type, library_id, radio_service, " + Song::kColumnSpec + ")" " VALUES (:playlist, :type, :library_id, :radio_service, " + - Song::kBindSpec + ")", - db); - QSqlQuery update( - "UPDATE playlists SET " + Song::kBindSpec + ")"); + QSqlQuery update(db); + update.prepare("UPDATE playlists SET " " last_played=:last_played," " dynamic_playlist_type=:dynamic_type," " dynamic_playlist_data=:dynamic_data," " dynamic_playlist_backend=:dynamic_backend" - " WHERE ROWID=:playlist", - db); + " WHERE ROWID=:playlist"); ScopedTransaction transaction(&db); @@ -350,10 +347,10 @@ int PlaylistBackend::CreatePlaylist(const QString& name, QMutexLocker l(db_->Mutex()); QSqlDatabase db(db_->Connect()); - QSqlQuery q( + QSqlQuery q(db); + q.prepare( "INSERT INTO playlists (name, special_type)" - " VALUES (:name, :special_type)", - db); + " VALUES (:name, :special_type)"); q.bindValue(":name", name); q.bindValue(":special_type", special_type); q.exec(); @@ -365,8 +362,10 @@ int PlaylistBackend::CreatePlaylist(const QString& name, void PlaylistBackend::RemovePlaylist(int id) { QMutexLocker l(db_->Mutex()); QSqlDatabase db(db_->Connect()); - QSqlQuery delete_playlist("DELETE FROM playlists WHERE ROWID=:id", db); - QSqlQuery delete_items("DELETE FROM playlist_items WHERE playlist=:id", db); + QSqlQuery delete_playlist(db); + delete_playlist.prepare("DELETE FROM playlists WHERE ROWID=:id"); + QSqlQuery delete_items(db); + delete_items.prepare("DELETE FROM playlist_items WHERE playlist=:id"); delete_playlist.bindValue(":id", id); delete_items.bindValue(":id", id); @@ -385,7 +384,8 @@ void PlaylistBackend::RemovePlaylist(int id) { void PlaylistBackend::RenamePlaylist(int id, const QString& new_name) { QMutexLocker l(db_->Mutex()); QSqlDatabase db(db_->Connect()); - QSqlQuery q("UPDATE playlists SET name=:name WHERE ROWID=:id", db); + QSqlQuery q(db); + q.prepare("UPDATE playlists SET name=:name WHERE ROWID=:id"); q.bindValue(":name", new_name); q.bindValue(":id", id); @@ -396,8 +396,8 @@ void PlaylistBackend::RenamePlaylist(int id, const QString& new_name) { void PlaylistBackend::FavoritePlaylist(int id, bool is_favorite) { QMutexLocker l(db_->Mutex()); QSqlDatabase db(db_->Connect()); - QSqlQuery q("UPDATE playlists SET is_favorite=:is_favorite WHERE ROWID=:id", - db); + QSqlQuery q(db); + q.prepare("UPDATE playlists SET is_favorite=:is_favorite WHERE ROWID=:id"); q.bindValue(":is_favorite", is_favorite ? 1 : 0); q.bindValue(":id", id); @@ -410,11 +410,12 @@ void PlaylistBackend::SetPlaylistOrder(const QList& ids) { QSqlDatabase db(db_->Connect()); ScopedTransaction transaction(&db); - QSqlQuery q("UPDATE playlists SET ui_order=-1", db); + QSqlQuery q(db); + q.prepare("UPDATE playlists SET ui_order=-1"); q.exec(); if (db_->CheckErrors(q)) return; - q = QSqlQuery("UPDATE playlists SET ui_order=:index WHERE ROWID=:id", db); + q.prepare("UPDATE playlists SET ui_order=:index WHERE ROWID=:id"); for (int i = 0; i < ids.count(); ++i) { q.bindValue(":index", i); q.bindValue(":id", ids[i]); @@ -428,7 +429,8 @@ void PlaylistBackend::SetPlaylistOrder(const QList& ids) { void PlaylistBackend::SetPlaylistUiPath(int id, const QString& path) { QMutexLocker l(db_->Mutex()); QSqlDatabase db(db_->Connect()); - QSqlQuery q("UPDATE playlists SET ui_path=:path WHERE ROWID=:id", db); + QSqlQuery q(db); + q.prepare("UPDATE playlists SET ui_path=:path WHERE ROWID=:id"); ScopedTransaction transaction(&db); diff --git a/src/playlist/playlistcontainer.cpp b/src/playlist/playlistcontainer.cpp index 8d649f2db..ad92e3edc 100644 --- a/src/playlist/playlistcontainer.cpp +++ b/src/playlist/playlistcontainer.cpp @@ -16,6 +16,7 @@ */ #include "core/appearance.h" +#include "core/application.h" #include "core/logging.h" #include "core/player.h" #include "core/timeconstants.h" @@ -25,6 +26,7 @@ #include "ui/iconloader.h" #include "ui_playlistcontainer.h" +#include #include #include #include @@ -42,6 +44,7 @@ const int PlaylistContainer::kFilterDelayPlaylistSizeThreshold = 5000; PlaylistContainer::PlaylistContainer(QWidget* parent) : QWidget(parent), + app_(nullptr), ui_(new Ui_PlaylistContainer), manager_(nullptr), undo_(nullptr), @@ -51,7 +54,8 @@ PlaylistContainer::PlaylistContainer(QWidget* parent) tab_bar_visible_(false), tab_bar_animation_(new QTimeLine(500, this)), no_matches_label_(nullptr), - filter_timer_(new QTimer(this)) { + filter_timer_(new QTimer(this)), + dirty_(false) { ui_->setupUi(this); no_matches_label_ = new QLabel(ui_->playlist); @@ -95,7 +99,7 @@ PlaylistContainer::PlaylistContainer(QWidget* parent) ui_->tab_bar->setMaximumHeight(0); // Connections - connect(ui_->tab_bar, SIGNAL(currentChanged(int)), SLOT(Save())); + connect(ui_->tab_bar, SIGNAL(currentChanged(int)), SLOT(DirtyTabBar())); connect(ui_->tab_bar, SIGNAL(Save(int)), SLOT(SavePlaylist(int))); // set up timer for delayed filter updates @@ -110,7 +114,17 @@ PlaylistContainer::PlaylistContainer(QWidget* parent) ui_->filter->installEventFilter(this); } -PlaylistContainer::~PlaylistContainer() { delete ui_; } +PlaylistContainer::~PlaylistContainer() { + delete ui_; +} + +void PlaylistContainer::SetApplication(Application* app) { + Q_ASSERT(app); + app_ = app; + SetManager(app_->playlist_manager()); + ui_->playlist->SetApplication(app_); + connect(app_, SIGNAL(SaveSettings(QSettings*)), SLOT(Save(QSettings*))); +} PlaylistView* PlaylistContainer::view() const { return ui_->playlist; } @@ -331,10 +345,18 @@ void PlaylistContainer::GoToPreviousPlaylistTab() { manager_->SetCurrentPlaylist(id_previous); } -void PlaylistContainer::Save() { - if (starting_up_) return; +void PlaylistContainer::DirtyTabBar() { + dirty_ = true; + app_->DirtySettings(); +} - settings_.setValue("current_playlist", ui_->tab_bar->current_id()); +void PlaylistContainer::Save(QSettings* settings_) { + if (starting_up_ || !dirty_) return; + dirty_ = false; + + settings_->beginGroup(kSettingsGroup); + settings_->setValue("current_playlist", ui_->tab_bar->current_id()); + settings_->endGroup(); } void PlaylistContainer::SetTabBarVisible(bool visible) { diff --git a/src/playlist/playlistcontainer.h b/src/playlist/playlistcontainer.h index 804c10445..76a6cded7 100644 --- a/src/playlist/playlistcontainer.h +++ b/src/playlist/playlistcontainer.h @@ -23,6 +23,7 @@ class Ui_PlaylistContainer; +class Application; class LineEditInterface; class Playlist; class PlaylistManager; @@ -41,6 +42,7 @@ class PlaylistContainer : public QWidget { static const char* kSettingsGroup; + void SetApplication(Application* app); void SetActions(QAction* new_playlist, QAction* load_playlist, QAction* save_playlist, QAction* next_playlist, QAction* previous_playlist); @@ -83,7 +85,8 @@ signals: void ActivePaused(); void ActiveStopped(); - void Save(); + void DirtyTabBar(); + void Save(QSettings* settings_); void SetTabBarVisible(bool visible); void SetTabBarHeight(int height); @@ -103,6 +106,7 @@ signals: static const int kFilterDelayMs; static const int kFilterDelayPlaylistSizeThreshold; + Application* app_; Ui_PlaylistContainer* ui_; PlaylistManager* manager_; @@ -119,6 +123,8 @@ signals: QLabel* no_matches_label_; QTimer* filter_timer_; + + bool dirty_; }; #endif // PLAYLISTCONTAINER_H diff --git a/src/playlist/playlistdelegates.cpp b/src/playlist/playlistdelegates.cpp index 64e84ba00..ab48157c4 100644 --- a/src/playlist/playlistdelegates.cpp +++ b/src/playlist/playlistdelegates.cpp @@ -182,7 +182,7 @@ void PlaylistDelegateBase::paint(QPainter* painter, } } -QStyleOptionViewItemV4 PlaylistDelegateBase::Adjusted( +QStyleOptionViewItem PlaylistDelegateBase::Adjusted( const QStyleOptionViewItem& option, const QModelIndex& index) const { if (!view_) return option; @@ -192,7 +192,7 @@ QStyleOptionViewItemV4 PlaylistDelegateBase::Adjusted( if (view_->header()->logicalIndexAt(top_left) != index.column()) return option; - QStyleOptionViewItemV4 ret(option); + QStyleOptionViewItem ret(option); if (index.data(Playlist::Role_IsCurrent).toBool()) { // Move the text in a bit on the first column for the song that's currently @@ -219,7 +219,7 @@ bool PlaylistDelegateBase::helpEvent(QHelpEvent* event, QAbstractItemView* view, // Special case: we want newlines in the comment tooltip if (index.column() == Playlist::Column_Comment) { - text = Qt::escape(index.data(Qt::ToolTipRole).toString()); + text = index.data(Qt::ToolTipRole).toString().toHtmlEscaped(); text.replace("\\r\\n", "
"); text.replace("\\n", "
"); text.replace("\r\n", "
"); @@ -320,10 +320,8 @@ void RatingItemDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const { // Draw the background - const QStyleOptionViewItemV3* vopt = - qstyleoption_cast(&option); - vopt->widget->style()->drawPrimitive(QStyle::PE_PanelItemViewItem, vopt, - painter, vopt->widget); + option.widget->style()->drawPrimitive(QStyle::PE_PanelItemViewItem, &option, + painter, option.widget); // Don't draw anything else if the user can't set the rating of this item if (!index.data(Playlist::Role_CanSetRating).toBool()) return; @@ -429,7 +427,7 @@ QString NativeSeparatorsDelegate::displayText(const QVariant& value, if (value.type() == QVariant::Url) { url = value.toUrl(); } else if (string_value.contains("://")) { - url = QUrl::fromEncoded(string_value.toAscii()); + url = QUrl::fromEncoded(string_value.toLatin1()); } else { return QDir::toNativeSeparators(string_value); } diff --git a/src/playlist/playlistdelegates.h b/src/playlist/playlistdelegates.h index bf42d5184..6314f2483 100644 --- a/src/playlist/playlistdelegates.h +++ b/src/playlist/playlistdelegates.h @@ -63,7 +63,7 @@ class PlaylistDelegateBase : public QueuedItemDelegate { QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const; - QStyleOptionViewItemV4 Adjusted(const QStyleOptionViewItem& option, + QStyleOptionViewItem Adjusted(const QStyleOptionViewItem& option, const QModelIndex& index) const; static const int kMinHeight; diff --git a/src/playlist/playlistview.cpp b/src/playlist/playlistview.cpp index fe932fb62..97308602b 100644 --- a/src/playlist/playlistview.cpp +++ b/src/playlist/playlistview.cpp @@ -28,7 +28,7 @@ #include "ui/qt_blurimage.h" #include "ui/iconloader.h" -#include +#include #include #include #include @@ -40,6 +40,7 @@ #include #include #include +#include #include #include @@ -62,7 +63,7 @@ const int PlaylistView::kDefaultBlurRadius = 0; const int PlaylistView::kDefaultOpacityLevel = 40; PlaylistProxyStyle::PlaylistProxyStyle(QStyle* base) - : QProxyStyle(base), cleanlooks_(new QCleanlooksStyle) {} + : QProxyStyle(base), common_style_(new QCommonStyle) {} void PlaylistProxyStyle::drawControl(ControlElement element, const QStyleOption* option, @@ -87,7 +88,7 @@ void PlaylistProxyStyle::drawControl(ControlElement element, } if (element == CE_ItemViewItem) - cleanlooks_->drawControl(element, option, painter, widget); + common_style_->drawControl(element, option, painter, widget); else QProxyStyle::drawControl(element, option, painter, widget); } @@ -98,7 +99,7 @@ void PlaylistProxyStyle::drawPrimitive(PrimitiveElement element, const QWidget* widget) const { if (element == QStyle::PE_PanelItemViewRow || element == QStyle::PE_PanelItemViewItem) - cleanlooks_->drawPrimitive(element, option, painter, widget); + common_style_->drawPrimitive(element, option, painter, widget); else QProxyStyle::drawPrimitive(element, option, painter, widget); } @@ -113,6 +114,7 @@ PlaylistView::PlaylistView(QWidget* parent) upgrading_from_qheaderview_(false), read_only_settings_(true), upgrading_from_version_(-1), + header_loaded_(false), background_initialized_(false), background_image_type_(Default), blur_radius_(kDefaultBlurRadius), @@ -133,27 +135,33 @@ PlaylistView::PlaylistView(QWidget* parent) cached_current_row_row_(-1), drop_indicator_row_(-1), drag_over_(false), + dirty_geometry_(false), + dirty_settings_(false), dynamic_controls_(new DynamicPlaylistControls(this)) { setHeader(header_); - header_->setMovable(true); + header_->setSectionsMovable(true); +#if QT_VERSION >= QT_VERSION_CHECK(5, 11, 0) + header_->setFirstSectionMovable(true); +#endif setStyle(style_); setMouseTracking(true); QIcon currenttrack_play = IconLoader::Load("currenttrack_play", IconLoader::Other); currenttrack_play_ = - currenttrack_play.pixmap(currenttrack_play.availableSizes().last()); + currenttrack_play.pixmap(currenttrack_play.actualSize(QSize(32, 32))); QIcon currenttrack_pause = IconLoader::Load("currenttrack_pause", IconLoader::Other); currenttrack_pause_ = - currenttrack_pause.pixmap(currenttrack_pause.availableSizes().last()); + currenttrack_pause.pixmap(currenttrack_pause.actualSize(QSize(32, 32))); - connect(header_, SIGNAL(sectionResized(int, int, int)), SLOT(SaveGeometry())); - connect(header_, SIGNAL(sectionMoved(int, int, int)), SLOT(SaveGeometry())); + connect(header_, SIGNAL(sectionResized(int, int, int)), + SLOT(DirtyGeometry())); + connect(header_, SIGNAL(sectionMoved(int, int, int)), SLOT(DirtyGeometry())); connect(header_, SIGNAL(sortIndicatorChanged(int, Qt::SortOrder)), - SLOT(SaveGeometry())); + SLOT(DirtyGeometry())); connect(header_, SIGNAL(SectionVisibilityChanged(int, bool)), - SLOT(SaveGeometry())); + SLOT(DirtyGeometry())); connect(header_, SIGNAL(SectionRatingLockStatusChanged(bool)), SLOT(SetRatingLockStatus(bool))); connect(header_, SIGNAL(sectionResized(int, int, int)), @@ -162,7 +170,7 @@ PlaylistView::PlaylistView(QWidget* parent) SLOT(InvalidateCachedCurrentPixmap())); connect(header_, SIGNAL(SectionVisibilityChanged(int, bool)), SLOT(InvalidateCachedCurrentPixmap())); - connect(header_, SIGNAL(StretchEnabledChanged(bool)), SLOT(SaveSettings())); + connect(header_, SIGNAL(StretchEnabledChanged(bool)), SLOT(DirtySettings())); connect(header_, SIGNAL(StretchEnabledChanged(bool)), SLOT(StretchChanged(bool))); connect(header_, SIGNAL(MouseEntered()), SLOT(RatingHoverOut())); @@ -190,6 +198,10 @@ PlaylistView::PlaylistView(QWidget* parent) fade_animation_->setDirection(QTimeLine::Backward); // 1.0 -> 0.0 } +PlaylistView::~PlaylistView() { + delete style_; +} + void PlaylistView::SetApplication(Application* app) { Q_ASSERT(app); app_ = app; @@ -200,6 +212,10 @@ void PlaylistView::SetApplication(Application* app) { connect(app_->player(), SIGNAL(Playing()), SLOT(StartGlowing())); connect(app_->player(), SIGNAL(Stopped()), SLOT(StopGlowing())); connect(app_->player(), SIGNAL(Stopped()), SLOT(PlayerStopped())); + connect(app_, SIGNAL(SaveSettings(QSettings*)), + SLOT(SaveGeometry(QSettings*))); + connect(app_, SIGNAL(SaveSettings(QSettings*)), + SLOT(SaveSettings(QSettings*))); } void PlaylistView::SetItemDelegates(LibraryBackend* backend) { @@ -326,6 +342,7 @@ void PlaylistView::setModel(QAbstractItemModel* m) { void PlaylistView::LoadGeometry() { QSettings settings; + header_loaded_ = true; settings.beginGroup(Playlist::kSettingsGroup); QByteArray state(settings.value("state").toByteArray()); @@ -405,13 +422,19 @@ void PlaylistView::LoadRatingLockStatus() { ratings_locked_ = s.value("RatingLocked", false).toBool(); } -void PlaylistView::SaveGeometry() { - if (read_only_settings_) return; +void PlaylistView::DirtyGeometry() { + dirty_geometry_ = true; + app_->DirtySettings(); +} - QSettings settings; - settings.beginGroup(Playlist::kSettingsGroup); - settings.setValue("state", header_->SaveState()); - settings.setValue("state_version", kStateVersion); +void PlaylistView::SaveGeometry(QSettings* settings) { + if (!dirty_geometry_ || read_only_settings_ || !header_loaded_) return; + dirty_geometry_ = false; + + settings->beginGroup(Playlist::kSettingsGroup); + settings->setValue("state", header_->SaveState()); + settings->setValue("state_version", kStateVersion); + settings->endGroup(); } void PlaylistView::SetRatingLockStatus(bool state) { @@ -464,7 +487,7 @@ void PlaylistView::drawTree(QPainter* painter, const QRegion& region) const { void PlaylistView::drawRow(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const { - QStyleOptionViewItemV4 opt(option); + QStyleOptionViewItem opt(option); bool is_current = index.data(Playlist::Role_IsCurrent).toBool(); bool is_paused = index.data(Playlist::Role_IsPaused).toBool(); @@ -543,7 +566,7 @@ void PlaylistView::drawRow(QPainter* painter, } } -void PlaylistView::UpdateCachedCurrentRowPixmap(QStyleOptionViewItemV4 option, +void PlaylistView::UpdateCachedCurrentRowPixmap(QStyleOptionViewItem option, const QModelIndex& index) { cached_current_row_rect_ = option.rect; cached_current_row_row_ = index.row(); @@ -1168,20 +1191,28 @@ void PlaylistView::ReloadSettings() { setEditTriggers(editTriggers() | QAbstractItemView::SelectedClicked); } -void PlaylistView::SaveSettings() { - if (read_only_settings_) return; +void PlaylistView::DirtySettings() { + dirty_settings_ = true; + app_->DirtySettings(); +} - QSettings s; - s.beginGroup(Playlist::kSettingsGroup); - s.setValue("glow_effect", glow_enabled_); - s.setValue("column_alignments", QVariant::fromValue(column_alignment_)); - s.setValue(kSettingBackgroundImageType, background_image_type_); +void PlaylistView::SaveSettings(QSettings* settings) { + if (!dirty_settings_ || read_only_settings_) return; + dirty_settings_ = false; + + settings->beginGroup(Playlist::kSettingsGroup); + settings->setValue("glow_effect", glow_enabled_); + settings->setValue("column_alignments", + QVariant::fromValue(column_alignment_)); + settings->setValue(kSettingBackgroundImageType, background_image_type_); + settings->endGroup(); } void PlaylistView::StretchChanged(bool stretch) { setHorizontalScrollBarPolicy(stretch ? Qt::ScrollBarAlwaysOff : Qt::ScrollBarAsNeeded); - SaveGeometry(); + dirty_geometry_ = true; + app_->DirtySettings(); } void PlaylistView::DynamicModeChanged(bool dynamic) { @@ -1250,7 +1281,8 @@ void PlaylistView::SetColumnAlignment(int section, Qt::Alignment alignment) { column_alignment_[section] = alignment; emit ColumnAlignmentChanged(column_alignment_); - SaveSettings(); + dirty_settings_ = true; + app_->DirtySettings(); } Qt::Alignment PlaylistView::column_alignment(int section) const { diff --git a/src/playlist/playlistview.h b/src/playlist/playlistview.h index beea33ea3..8e24e6b46 100644 --- a/src/playlist/playlistview.h +++ b/src/playlist/playlistview.h @@ -26,7 +26,7 @@ #include "playlist.h" -class QCleanlooksStyle; +class QCommonStyle; class Application; class DynamicPlaylistControls; @@ -40,7 +40,7 @@ class QTimeLine; // that uses Gtk to paint row backgrounds, ignoring any custom brush or palette // the caller set in the QStyleOption. That breaks our currently playing track // animation, which relies on the background painted by Qt to be transparent. -// This proxy style uses QCleanlooksStyle to paint the affected elements. +// This proxy style uses QCommonStyle to paint the affected elements. // This class is used by the global search view as well. class PlaylistProxyStyle : public QProxyStyle { public: @@ -51,12 +51,14 @@ class PlaylistProxyStyle : public QProxyStyle { QPainter* painter, const QWidget* widget) const; private: - std::unique_ptr cleanlooks_; + std::unique_ptr common_style_; }; class PlaylistView : public QTreeView { Q_OBJECT public: + ~PlaylistView(); + enum BackgroundImageType { Default, None, Custom, AlbumCover }; PlaylistView(QWidget* parent = nullptr); @@ -143,7 +145,9 @@ signals: private slots: void LoadGeometry(); void LoadRatingLockStatus(); - void SaveGeometry(); + void DirtyGeometry(); + void DirtySettings(); + void SaveGeometry(QSettings* settings); void SetRatingLockStatus(bool state); void GlowIntensityChanged(); void InhibitAutoscrollTimeout(); @@ -151,7 +155,7 @@ signals: void InvalidateCachedCurrentPixmap(); void PlaylistDestroyed(); - void SaveSettings(); + void SaveSettings(QSettings* s); void StretchChanged(bool stretch); void RatingHoverIn(const QModelIndex& index, const QPoint& pos); @@ -162,7 +166,7 @@ signals: private: void ReloadBarPixmaps(); QList LoadBarPixmap(const QString& filename); - void UpdateCachedCurrentRowPixmap(QStyleOptionViewItemV4 option, + void UpdateCachedCurrentRowPixmap(QStyleOptionViewItem option, const QModelIndex& index); void set_background_image_type(BackgroundImageType bg) { @@ -194,6 +198,7 @@ signals: bool upgrading_from_qheaderview_; bool read_only_settings_; int upgrading_from_version_; + bool header_loaded_; bool background_initialized_; BackgroundImageType background_image_type_; @@ -248,6 +253,9 @@ signals: int drop_indicator_row_; bool drag_over_; + bool dirty_geometry_; + bool dirty_settings_; + bool ratings_locked_; // To store Ratings section lock status DynamicPlaylistControls* dynamic_controls_; diff --git a/src/ripper/ripcddialog.cpp b/src/ripper/ripcddialog.cpp index bde2f98fc..522becfb2 100644 --- a/src/ripper/ripcddialog.cpp +++ b/src/ripper/ripcddialog.cpp @@ -63,11 +63,11 @@ RipCDDialog::RipCDDialog(QWidget* parent) ui_->setupUi(this); // Set column widths in the QTableWidget. - ui_->tableWidget->horizontalHeader()->setResizeMode( + ui_->tableWidget->horizontalHeader()->setSectionResizeMode( kCheckboxColumn, QHeaderView::ResizeToContents); - ui_->tableWidget->horizontalHeader()->setResizeMode( + ui_->tableWidget->horizontalHeader()->setSectionResizeMode( kTrackNumberColumn, QHeaderView::ResizeToContents); - ui_->tableWidget->horizontalHeader()->setResizeMode(kTrackTitleColumn, + ui_->tableWidget->horizontalHeader()->setSectionResizeMode(kTrackTitleColumn, QHeaderView::Stretch); // Add a rip button diff --git a/src/smartplaylists/searchtermwidget.cpp b/src/smartplaylists/searchtermwidget.cpp index b358e9e95..1dc4f9875 100644 --- a/src/smartplaylists/searchtermwidget.cpp +++ b/src/smartplaylists/searchtermwidget.cpp @@ -120,7 +120,7 @@ SearchTermWidget::SearchTermWidget(LibraryBackend* library, QWidget* parent) // Set stylesheet QFile stylesheet_file(":/smartplaylistsearchterm.css"); stylesheet_file.open(QIODevice::ReadOnly); - QString stylesheet = QString::fromAscii(stylesheet_file.readAll()); + QString stylesheet = QString::fromLatin1(stylesheet_file.readAll()); const QColor base(222, 97, 97, 128); stylesheet.replace("%light2", Utilities::ColorToRgba(base.lighter(140))); stylesheet.replace("%light", Utilities::ColorToRgba(base.lighter(120))); @@ -397,7 +397,7 @@ void SearchTermWidget::Overlay::Grab() { hide(); // Take a "screenshot" of the window - QPixmap pixmap = QPixmap::grabWidget(parent_); + QPixmap pixmap = parent_->grab(); QImage image = pixmap.toImage(); // Blur it diff --git a/src/songinfo/artistbiography.cpp b/src/songinfo/artistbiography.cpp index 64d09b817..33fcec221 100644 --- a/src/songinfo/artistbiography.cpp +++ b/src/songinfo/artistbiography.cpp @@ -18,8 +18,12 @@ #include "artistbiography.h" #include - -#include +#include +#include +#include +#include +#include +#include #include "core/closure.h" #include "core/latch.h" @@ -59,8 +63,10 @@ void ArtistBiography::FetchInfo(int id, const Song& metadata) { } QUrl url(kArtistBioUrl); - url.addQueryItem("artist", metadata.artist()); - url.addQueryItem("lang", GetLocale()); + QUrlQuery url_query(url); + url_query.addQueryItem("artist", metadata.artist()); + url_query.addQueryItem("lang", GetLocale()); + url.setQuery(url_query); qLog(Debug) << "Biography url: " << url; @@ -70,8 +76,8 @@ void ArtistBiography::FetchInfo(int id, const Song& metadata) { NewClosure(reply, SIGNAL(finished()), [this, reply, id]() { reply->deleteLater(); - QJson::Parser parser; - QVariantMap response = parser.parse(reply).toMap(); + QJsonDocument json_document = QJsonDocument::fromJson(reply->readAll()); + QJsonObject response = json_document.object(); QString body = response["articleBody"].toString(); QString url = response["url"].toString(); @@ -112,15 +118,15 @@ void ArtistBiography::FetchInfo(int id, const Song& metadata) { namespace { -QStringList ExtractImageTitles(const QVariantMap& json) { +QStringList ExtractImageTitles(const QJsonObject& json) { QStringList ret; for (auto it = json.constBegin(); it != json.constEnd(); ++it) { - if (it.value().type() == QVariant::Map) { - ret.append(ExtractImageTitles(it.value().toMap())); - } else if (it.key() == "images" && it.value().type() == QVariant::List) { - QVariantList images = it.value().toList(); - for (QVariant i : images) { - QVariantMap image = i.toMap(); + if (it.value().type() == QJsonValue::Object) { + ret.append(ExtractImageTitles(it.value().toObject())); + } else if (it.key() == "images" && it.value().type() == QJsonValue::Array) { + QJsonArray images = it.value().toArray(); + for (const QJsonValue& i : images) { + QJsonObject image = i.toObject(); QString image_title = image["title"].toString(); if (!image_title.isEmpty() && ( @@ -135,31 +141,31 @@ QStringList ExtractImageTitles(const QVariantMap& json) { return ret; } -QUrl ExtractImageUrl(const QVariantMap& json) { +QUrl ExtractImageUrl(const QJsonObject& json) { for (auto it = json.constBegin(); it != json.constEnd(); ++it) { - if (it.value().type() == QVariant::Map) { - QUrl r = ExtractImageUrl(it.value().toMap()); + if (it.value().type() == QJsonValue::Object) { + QUrl r = ExtractImageUrl(it.value().toObject()); if (!r.isEmpty()) { return r; } } else if (it.key() == "imageinfo") { - QVariantList imageinfos = it.value().toList(); - QVariantMap imageinfo = imageinfos.first().toMap(); + QJsonArray imageinfos = it.value().toArray(); + QJsonObject imageinfo = imageinfos.first().toObject(); int width = imageinfo["width"].toInt(); int height = imageinfo["height"].toInt(); if (width < kMinimumImageSize || height < kMinimumImageSize) { return QUrl(); } - return QUrl::fromEncoded(imageinfo["url"].toByteArray()); + return QUrl::fromEncoded(imageinfo["url"].toVariant().toByteArray()); } } return QUrl(); } -QString ExtractExtract(const QVariantMap& json) { +QString ExtractExtract(const QJsonObject& json) { for (auto it = json.constBegin(); it != json.constEnd(); ++it) { - if (it.value().type() == QVariant::Map) { - QString extract = ExtractExtract(it.value().toMap()); + if (it.value().type() == QJsonValue::Object) { + QString extract = ExtractExtract(it.value().toObject()); if (!extract.isEmpty()) { return extract; } @@ -184,7 +190,9 @@ void ArtistBiography::FetchWikipediaImages(int id, const QString& wikipedia_url, QString wiki_title = QUrl::fromPercentEncoding(regex.cap(2).toUtf8()); QString language = regex.cap(1); QUrl url(QString(kWikipediaImageListUrl).arg(language)); - url.addQueryItem("titles", wiki_title); + QUrlQuery url_query(url); + url_query.addQueryItem("titles", wiki_title); + url.setQuery(url_query); qLog(Debug) << "Wikipedia images:" << url; @@ -193,23 +201,25 @@ void ArtistBiography::FetchWikipediaImages(int id, const QString& wikipedia_url, NewClosure(reply, SIGNAL(finished()), [this, id, reply, language, latch]() { reply->deleteLater(); - QJson::Parser parser; - QVariantMap response = parser.parse(reply).toMap(); + QJsonDocument json_document = QJsonDocument::fromJson(reply->readAll()); + QJsonObject response = json_document.object(); QStringList image_titles = ExtractImageTitles(response); for (const QString& image_title : image_titles) { latch->Wait(); QUrl url(QString(kWikipediaImageInfoUrl).arg(language)); - url.addQueryItem("titles", image_title); + QUrlQuery url_query(url); + url_query.addQueryItem("titles", image_title); + url.setQuery(url_query); qLog(Debug) << "Image info:" << url; QNetworkRequest request(url); QNetworkReply* reply = network_->get(request); NewClosure(reply, SIGNAL(finished()), [this, id, reply, latch]() { reply->deleteLater(); - QJson::Parser parser; - QVariantMap json = parser.parse(reply).toMap(); + QJsonDocument json_document = QJsonDocument::fromJson(reply->readAll()); + QJsonObject json = json_document.object(); QUrl url = ExtractImageUrl(json); qLog(Debug) << "Found wikipedia image url:" << url; if (!url.isEmpty()) { @@ -236,18 +246,20 @@ void ArtistBiography::FetchWikipediaArticle(int id, QString language = regex.cap(1); QUrl url(QString(kWikipediaExtractUrl).arg(language)); - url.addQueryItem("titles", wiki_title); + QUrlQuery url_query(url); + url_query.addQueryItem("titles", wiki_title); + url.setQuery(url_query); QNetworkRequest request(url); QNetworkReply* reply = network_->get(request); qLog(Debug) << "Article url:" << url; NewClosure(reply, SIGNAL(finished()), [this, id, reply, wikipedia_url, - wiki_title, latch]() { + wiki_title, latch]() { reply->deleteLater(); - QJson::Parser parser; - QVariantMap json = parser.parse(reply).toMap(); + QJsonDocument json_document = QJsonDocument::fromJson(reply->readAll()); + QJsonObject json = json_document.object(); QString html = ExtractExtract(json); CollapsibleInfoPane::Data data; @@ -258,7 +270,7 @@ void ArtistBiography::FetchWikipediaArticle(int id, QString text; text += "

" + - tr("Open in your browser") + "

"; + tr("Open in your browser") + "

"; text += html; diff --git a/src/songinfo/artistinfoview.cpp b/src/songinfo/artistinfoview.cpp index 8a1f77582..af1f5d0c4 100644 --- a/src/songinfo/artistinfoview.cpp +++ b/src/songinfo/artistinfoview.cpp @@ -20,8 +20,8 @@ #include "songinfo/artistbiography.h" #include "songinfo/songinfofetcher.h" #include "songinfo/songkickconcerts.h" -#include "songinfo/spotifyimages.h" #include "widgets/prettyimageview.h" +#include "songinfo/spotifyimages.h" ArtistInfoView::ArtistInfoView(QWidget* parent) : SongInfoBase(parent) { fetcher_->AddProvider(new SongkickConcerts); diff --git a/src/songinfo/songinfobase.cpp b/src/songinfo/songinfobase.cpp index f412bfa05..1f28919a3 100644 --- a/src/songinfo/songinfobase.cpp +++ b/src/songinfo/songinfobase.cpp @@ -59,7 +59,7 @@ SongInfoBase::SongInfoBase(QWidget* parent) // Set stylesheet QFile stylesheet(":/songinfo.css"); stylesheet.open(QIODevice::ReadOnly); - setStyleSheet(QString::fromAscii(stylesheet.readAll())); + setStyleSheet(QString::fromLatin1(stylesheet.readAll())); connect(fetcher_, SIGNAL(ResultReady(int, SongInfoFetcher::Result)), SLOT(ResultReady(int, SongInfoFetcher::Result))); diff --git a/src/songinfo/songkickconcerts.cpp b/src/songinfo/songkickconcerts.cpp index 043ddb4bc..e6b1685bb 100644 --- a/src/songinfo/songkickconcerts.cpp +++ b/src/songinfo/songkickconcerts.cpp @@ -20,8 +20,11 @@ #include #include #include - -#include +#include +#include +#include +#include +#include #include "core/closure.h" #include "core/logging.h" @@ -52,8 +55,10 @@ void SongkickConcerts::FetchInfo(int id, const Song& metadata) { } QUrl url(kSongkickArtistSearchUrl); - url.addQueryItem("apikey", kSongkickApiKey); - url.addQueryItem("query", metadata.artist()); + QUrlQuery url_query; + url_query.addQueryItem("apikey", kSongkickApiKey); + url_query.addQueryItem("query", metadata.artist()); + url.setQuery(url_query); QNetworkRequest request(url); QNetworkReply* reply = network_.get(request); @@ -64,19 +69,19 @@ void SongkickConcerts::FetchInfo(int id, const Song& metadata) { void SongkickConcerts::ArtistSearchFinished(QNetworkReply* reply, int id) { reply->deleteLater(); - QJson::Parser parser; - QVariantMap json = parser.parse(reply).toMap(); + QJsonDocument document = QJsonDocument::fromBinaryData(reply->readAll()); + QJsonObject json = document.object(); - QVariantMap results_page = json["resultsPage"].toMap(); - QVariantMap results = results_page["results"].toMap(); - QVariantList artists = results["artist"].toList(); + QJsonObject results_page = json["resultsPage"].toObject(); + QJsonObject results = results_page["results"].toObject(); + QJsonArray artists = results["artist"].toArray(); if (artists.isEmpty()) { emit Finished(id); return; } - QVariantMap artist = artists.first().toMap(); + QJsonObject artist = artists.first().toObject(); QString artist_id = artist["id"].toString(); FetchSongkickCalendar(artist_id, id); @@ -84,8 +89,10 @@ void SongkickConcerts::ArtistSearchFinished(QNetworkReply* reply, int id) { void SongkickConcerts::FetchSongkickCalendar(const QString& artist_id, int id) { QUrl url(QString(kSongkickArtistCalendarUrl).arg(artist_id)); - url.addQueryItem("per_page", "5"); - url.addQueryItem("apikey", kSongkickApiKey); + QUrlQuery url_query; + url_query.addQueryItem("per_page", "5"); + url_query.addQueryItem("apikey", kSongkickApiKey); + url.setQuery(url_query); qLog(Debug) << url; QNetworkReply* reply = network_.get(QNetworkRequest(url)); NewClosure(reply, SIGNAL(finished()), this, @@ -93,22 +100,23 @@ void SongkickConcerts::FetchSongkickCalendar(const QString& artist_id, int id) { } void SongkickConcerts::CalendarRequestFinished(QNetworkReply* reply, int id) { - QJson::Parser parser; - bool ok = false; - QVariant result = parser.parse(reply, &ok); + reply->deleteLater(); - if (!ok) { + QJsonParseError error; + QJsonDocument json_document = QJsonDocument::fromJson(reply->readAll(), &error); + + if (error.error != QJsonParseError::NoError) { qLog(Error) << "Error parsing Songkick reply"; emit Finished(id); return; } - QVariantMap root = result.toMap(); - QVariantMap results_page = root["resultsPage"].toMap(); - QVariantMap results = results_page["results"].toMap(); - QVariantList events = results["event"].toList(); + QJsonObject json_root = json_document.object(); + QJsonObject json_results_page = json_root["resultsPage"].toObject(); + QJsonObject json_results = json_results_page["results"].toObject(); + QJsonArray json_events = json_results["event"].toArray(); - if (events.isEmpty()) { + if (json_events.isEmpty()) { emit Finished(id); return; } @@ -116,21 +124,21 @@ void SongkickConcerts::CalendarRequestFinished(QNetworkReply* reply, int id) { QWidget* container = new QWidget; QVBoxLayout* layout = new QVBoxLayout(container); - for (const QVariant& v : events) { - QVariantMap event = v.toMap(); - QString display_name = event["displayName"].toString(); - QString start_date = event["start"].toMap()["date"].toString(); - QString city = event["location"].toMap()["city"].toString(); - QString uri = event["uri"].toString(); + for (const QJsonValue& v : json_events) { + QJsonObject json_event = v.toObject(); + QString display_name = json_event["displayName"].toString(); + QString start_date = json_event["start"].toObject()["date"].toString(); + QString city = json_event["location"].toObject()["city"].toString(); + QString uri = json_event["uri"].toString(); // Try to get the lat/lng coordinates of the venue. - QVariantMap venue = event["venue"].toMap(); - const bool valid_latlng = venue["lng"].isValid() && venue["lat"].isValid(); + QJsonObject json_venue = json_event["venue"].toObject(); + const bool valid_latlng = !json_venue["lng"].isUndefined() && !json_venue["lat"].isUndefined(); if (valid_latlng && latlng_.IsValid()) { static const int kFilterDistanceMetres = 250 * 1e3; // 250km - Geolocator::LatLng latlng(venue["lat"].toString(), - venue["lng"].toString()); + Geolocator::LatLng latlng(json_venue["lat"].toString(), + json_venue["lng"].toString()); if (latlng_.IsValid() && latlng.IsValid()) { int distance_metres = latlng_.Distance(latlng); if (distance_metres > kFilterDistanceMetres) { @@ -145,8 +153,8 @@ void SongkickConcerts::CalendarRequestFinished(QNetworkReply* reply, int id) { widget->Init(display_name, uri, start_date, city); if (valid_latlng) { - widget->SetMap(venue["lat"].toString(), venue["lng"].toString(), - venue["displayName"].toString()); + widget->SetMap(json_venue["lat"].toString(), json_venue["lng"].toString(), + json_venue["displayName"].toString()); } layout->addWidget(widget); diff --git a/src/songinfo/songkickconcertwidget.cpp b/src/songinfo/songkickconcertwidget.cpp index 691f9fb02..21655f1f0 100644 --- a/src/songinfo/songkickconcertwidget.cpp +++ b/src/songinfo/songkickconcertwidget.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include "songinfotextview.h" #include "ui_songkickconcertwidget.h" @@ -58,7 +59,7 @@ void SongKickConcertWidget::ReloadSettings() { void SongKickConcertWidget::Init(const QString& title, const QString& url, const QString& date, const QString& location) { ui_->title->setText( - QString("%2").arg(Qt::escape(url), Qt::escape(title))); + QString("%2").arg(url.toHtmlEscaped(), title.toHtmlEscaped())); if (!location.isEmpty()) { ui_->location->setText(location); @@ -96,10 +97,12 @@ void SongKickConcertWidget::SetMap(const QString& lat, const QString& lng, ui_->map->show(); map_url_ = QUrl("https://maps.google.com/"); - map_url_.addQueryItem("ll", QString("%1,%2").arg(lat, lng)); + QUrlQuery map_url_query; + map_url_query.addQueryItem("ll", QString("%1,%2").arg(lat, lng)); if (!venue_name.isEmpty()) { - map_url_.addQueryItem("q", venue_name); + map_url_query.addQueryItem("q", venue_name); } + map_url_.setQuery(map_url_query); // Request the static map image const QUrl url(QString(kStaticMapUrl).arg(QString::number(kStaticMapWidth), diff --git a/src/songinfo/spotifyimages.cpp b/src/songinfo/spotifyimages.cpp index 5a5ba2927..8ab671e91 100644 --- a/src/songinfo/spotifyimages.cpp +++ b/src/songinfo/spotifyimages.cpp @@ -2,9 +2,12 @@ #include -#include - #include +#include +#include +#include +#include +#include #include "core/closure.h" #include "core/logging.h" @@ -25,26 +28,31 @@ void SpotifyImages::FetchInfo(int id, const Song& metadata) { return; } + // Fetch artist id. QUrl url(kSpotifyImagesUrl); - url.addQueryItem("artist", metadata.artist()); + QUrlQuery url_query; + url_query.addQueryItem("artist", metadata.artist()); + url.setQuery(url_query); + + qLog(Debug) << "Fetching artist:" << url; QNetworkRequest request(url); QNetworkReply* reply = network_->get(request); NewClosure(reply, SIGNAL(finished()), [this, id, reply]() { reply->deleteLater(); - QJson::Parser parser; - bool ok = false; - QVariant result = parser.parse(reply, &ok); - if (!ok || result.type() != QVariant::List) { + + QJsonParseError error; + QJsonDocument json_document = QJsonDocument::fromJson(reply->readAll(), &error); + if (error.error != QJsonParseError::NoError) { emit Finished(id); return; } - QVariantList results = result.toList(); + QJsonArray results = json_document.array(); QList> image_candidates; - for (QVariant v : results) { - QVariantMap image = v.toMap(); - QUrl url = image["url"].toUrl(); + for (const QJsonValue &v : results) { + QJsonObject image = v.toObject(); + QUrl url = image["url"].toVariant().toUrl(); int height = image["height"].toInt(); int width = image["width"].toInt(); image_candidates.append(qMakePair(url, QSize(width, height))); diff --git a/src/songinfo/ultimatelyricsprovider.cpp b/src/songinfo/ultimatelyricsprovider.cpp index e3a51b7eb..443f372df 100644 --- a/src/songinfo/ultimatelyricsprovider.cpp +++ b/src/songinfo/ultimatelyricsprovider.cpp @@ -37,7 +37,7 @@ UltimateLyricsProvider::UltimateLyricsProvider() void UltimateLyricsProvider::FetchInfo(int id, const Song& metadata) { // Get the text codec const QTextCodec* codec = - QTextCodec::codecForName(charset_.toAscii().constData()); + QTextCodec::codecForName(charset_.toLatin1().constData()); if (!codec) { qLog(Warning) << "Invalid codec" << charset_; emit Finished(id); @@ -100,7 +100,7 @@ void UltimateLyricsProvider::LyricsFetched() { } const QTextCodec* codec = - QTextCodec::codecForName(charset_.toAscii().constData()); + QTextCodec::codecForName(charset_.toLatin1().constData()); const QString original_content = codec->toUnicode(reply->readAll()); QString lyrics; diff --git a/src/transcoder/transcodedialog.cpp b/src/transcoder/transcodedialog.cpp index 7263e8cc4..cbec3d16f 100644 --- a/src/transcoder/transcodedialog.cpp +++ b/src/transcoder/transcodedialog.cpp @@ -56,7 +56,7 @@ TranscodeDialog::TranscodeDialog(QWidget* parent) finished_success_(0), finished_failed_(0) { ui_->setupUi(this); - ui_->files->header()->setResizeMode(QHeaderView::ResizeToContents); + ui_->files->header()->setSectionResizeMode(QHeaderView::ResizeToContents); log_ui_->setupUi(log_dialog_); QPushButton* clear_button = diff --git a/src/transcoder/transcoder.cpp b/src/transcoder/transcoder.cpp index 45ee349d7..e070ea591 100644 --- a/src/transcoder/transcoder.cpp +++ b/src/transcoder/transcoder.cpp @@ -48,9 +48,9 @@ TranscoderPreset::TranscoderPreset(Song::FileType type, const QString& name, GstElement* Transcoder::CreateElement(const QString& factory_name, GstElement* bin, const QString& name) { GstElement* ret = gst_element_factory_make( - factory_name.toAscii().constData(), - name.isNull() ? factory_name.toAscii().constData() - : name.toAscii().constData()); + factory_name.toLatin1().constData(), + name.isNull() ? factory_name.toLatin1().constData() + : name.toLatin1().constData()); if (ret && bin) gst_bin_add(GST_BIN(bin), ret); diff --git a/src/ui/albumcoverchoicecontroller.cpp b/src/ui/albumcoverchoicecontroller.cpp index 8bb9cf317..e5decb124 100644 --- a/src/ui/albumcoverchoicecontroller.cpp +++ b/src/ui/albumcoverchoicecontroller.cpp @@ -39,6 +39,7 @@ #include #include #include +#include const char* AlbumCoverChoiceController::kLoadImageFileFilter = QT_TR_NOOP( "Images (*.png *.jpg *.jpeg *.bmp *.gif *.xpm *.pbm *.pgm *.ppm *.xbm)"); @@ -276,7 +277,7 @@ void AlbumCoverChoiceController::AlbumCoverPopupClosed() { void AlbumCoverChoiceController::SearchCoverAutomatically(const Song& song) { qint64 id = cover_fetcher_->FetchAlbumCover(song.effective_albumartist(), - song.effective_album()); + song.effective_album(), false); cover_fetching_tasks_[id] = song; } diff --git a/src/ui/albumcovermanager.cpp b/src/ui/albumcovermanager.cpp index 374abebe7..3a0ff4b97 100644 --- a/src/ui/albumcovermanager.cpp +++ b/src/ui/albumcovermanager.cpp @@ -432,7 +432,8 @@ void AlbumCoverManager::FetchAlbumCovers() { if (ItemHasCover(*item)) continue; quint64 id = cover_fetcher_->FetchAlbumCover( - EffectiveAlbumArtistName(*item), item->data(Role_AlbumName).toString()); + EffectiveAlbumArtistName(*item), item->data(Role_AlbumName).toString(), + true); cover_fetching_tasks_[id] = item; jobs_++; } @@ -568,7 +569,8 @@ void AlbumCoverManager::ShowCover() { void AlbumCoverManager::FetchSingleCover() { for (QListWidgetItem* item : context_menu_items_) { quint64 id = cover_fetcher_->FetchAlbumCover( - EffectiveAlbumArtistName(*item), item->data(Role_AlbumName).toString()); + EffectiveAlbumArtistName(*item), item->data(Role_AlbumName).toString(), + false); cover_fetching_tasks_[id] = item; jobs_++; } diff --git a/src/ui/behavioursettingspage.cpp b/src/ui/behavioursettingspage.cpp index bb5a6c17a..b32816891 100644 --- a/src/ui/behavioursettingspage.cpp +++ b/src/ui/behavioursettingspage.cpp @@ -40,6 +40,15 @@ BehaviourSettingsPage::BehaviourSettingsPage(SettingsDialog* dialog) connect(ui_->b_show_tray_icon_, SIGNAL(toggled(bool)), SLOT(ShowTrayIconToggled(bool))); + connect(ui_->max_numprocs_tagclients, SIGNAL(valueChanged(int)), + SLOT(MaxNumProcsTagClientsChanged(int))); + ui_->max_numprocs_tagclients_value_label->setMinimumWidth( + QFontMetrics(ui_->max_numprocs_tagclients_value_label->font()) + .width("WWW")); + + // Limit max tag clients to number of CPU cores. + ui_->max_numprocs_tagclients->setMaximum(QThread::idealThreadCount()); + ui_->doubleclick_addmode->setItemData(0, MainWindow::AddBehaviour_Append); ui_->doubleclick_addmode->setItemData(1, MainWindow::AddBehaviour_Load); ui_->doubleclick_addmode->setItemData(2, MainWindow::AddBehaviour_OpenInNew); @@ -78,12 +87,10 @@ BehaviourSettingsPage::BehaviourSettingsPage(SettingsDialog* dialog) .replace("_TW", "_Hant_TW"); QString language_name = QLocale::languageToString(QLocale(lookup_code).language()); -#if QT_VERSION >= 0x040800 QString native_name = QLocale(lookup_code).nativeLanguageName(); if (!native_name.isEmpty()) { language_name = native_name; } -#endif QString name = QString("%1 (%2)").arg(language_name, code); language_map_[name] = code; @@ -173,6 +180,12 @@ void BehaviourSettingsPage::Load() { .toInt())); ui_->seek_step_sec->setValue(s.value("seek_step_sec", 10).toInt()); + int max_numprocs_tagclients = + s.value("max_numprocs_tagclients", QThread::idealThreadCount()).toInt(); + ui_->max_numprocs_tagclients->setValue(max_numprocs_tagclients); + ui_->max_numprocs_tagclients_value_label->setText( + QString::number(max_numprocs_tagclients)); + if (s.value("play_count_short_duration", false).toBool()) { ui_->b_play_count_short_duration->setChecked(true); ui_->b_play_count_normal_duration->setChecked(false); @@ -285,6 +298,7 @@ void BehaviourSettingsPage::Save() { ui_->stop_play_if_fail_->isChecked()); s.setValue("menu_previousmode", menu_previousmode); s.setValue("seek_step_sec", ui_->seek_step_sec->value()); + s.setValue("max_numprocs_tagclients", ui_->max_numprocs_tagclients->value()); if (ui_->b_play_count_short_duration->isChecked()) { s.setValue("play_count_short_duration", true); @@ -323,3 +337,7 @@ void BehaviourSettingsPage::ShowTrayIconToggled(bool on) { ui_->b_keep_running_->setChecked(on); ui_->b_scroll_tray_icon_->setEnabled(on); } + +void BehaviourSettingsPage::MaxNumProcsTagClientsChanged(int value) { + ui_->max_numprocs_tagclients_value_label->setText(QString::number(value)); +} diff --git a/src/ui/behavioursettingspage.h b/src/ui/behavioursettingspage.h index 9f73c0f77..36be11880 100644 --- a/src/ui/behavioursettingspage.h +++ b/src/ui/behavioursettingspage.h @@ -36,6 +36,7 @@ class BehaviourSettingsPage : public SettingsPage { private slots: void ShowTrayIconToggled(bool on); + void MaxNumProcsTagClientsChanged(int value); private: Ui_BehaviourSettingsPage* ui_; diff --git a/src/ui/behavioursettingspage.ui b/src/ui/behavioursettingspage.ui index e9e42f1e5..38931124d 100644 --- a/src/ui/behavioursettingspage.ui +++ b/src/ui/behavioursettingspage.ui @@ -339,6 +339,48 @@ + + + + Maximum number of child processes for tag handling (requires restart) + + + + + + Number of processes: + + + + + + + + + + + + + + 1 + + + 32 + + + 4 + + + Qt::Horizontal + + + 1 + + + + + + diff --git a/src/ui/edittagdialog.cpp b/src/ui/edittagdialog.cpp index 5d0853686..0f7eab415 100644 --- a/src/ui/edittagdialog.cpp +++ b/src/ui/edittagdialog.cpp @@ -472,21 +472,20 @@ void EditTagDialog::UpdateSummaryTab(const Song& song) { app_->album_cover_loader()->LoadImageAsync(cover_options_, song); QString summary = - "" + Qt::escape(song.PrettyTitleWithArtist()) + "
"; + "" + song.PrettyTitleWithArtist().toHtmlEscaped() + "
"; bool art_is_set = true; if (song.has_manually_unset_cover()) { - summary += Qt::escape(tr("Cover art manually unset")); + summary += tr("Cover art manually unset").toHtmlEscaped(); art_is_set = false; } else if (!song.art_manual().isEmpty()) { - summary += Qt::escape(tr("Cover art set from %1").arg(song.art_manual())); + summary += tr("Cover art set from %1").arg(song.art_manual()).toHtmlEscaped(); } else if (song.has_embedded_cover()) { - summary += Qt::escape(tr("Cover art from embedded image")); + summary += tr("Cover art from embedded image"); } else if (!song.art_automatic().isEmpty()) { - summary += Qt::escape( - tr("Cover art loaded automatically from %1").arg(song.art_automatic())); + summary += tr("Cover art loaded automatically from %1").arg(song.art_automatic()).toHtmlEscaped(); } else { - summary += Qt::escape(tr("Cover art not set")); + summary += tr("Cover art not set").toHtmlEscaped(); art_is_set = false; } diff --git a/src/ui/flowlayout.cpp b/src/ui/flowlayout.cpp index cccb1a1c4..582ec92bd 100644 --- a/src/ui/flowlayout.cpp +++ b/src/ui/flowlayout.cpp @@ -38,7 +38,7 @@ ** ****************************************************************************/ -#include +#include #include "flowlayout.h" //! [1] diff --git a/src/ui/globalshortcutssettingspage.cpp b/src/ui/globalshortcutssettingspage.cpp index d4e4c1d26..c60a9561d 100644 --- a/src/ui/globalshortcutssettingspage.cpp +++ b/src/ui/globalshortcutssettingspage.cpp @@ -24,6 +24,7 @@ #include "ui/iconloader.h" #include "ui/settingsdialog.h" +#include #include #include #include @@ -39,7 +40,7 @@ GlobalShortcutsSettingsPage::GlobalShortcutsSettingsPage(SettingsDialog* dialog) grabber_(new GlobalShortcutGrabber) { ui_->setupUi(this); ui_->shortcut_options->setEnabled(false); - ui_->list->header()->setResizeMode(QHeaderView::ResizeToContents); + ui_->list->header()->setSectionResizeMode(QHeaderView::ResizeToContents); setWindowIcon(IconLoader::Load("input-keyboard", IconLoader::Base)); settings_.beginGroup(GlobalShortcuts::kSettingsGroup); diff --git a/src/ui/iconloader.cpp b/src/ui/iconloader.cpp index 5073a4e9a..f69150414 100644 --- a/src/ui/iconloader.cpp +++ b/src/ui/iconloader.cpp @@ -110,13 +110,10 @@ QIcon IconLoader::Load(const QString& name, const IconType& icontype) { // Should never be reached qLog(Warning) << "Couldn't recognize IconType" << name; } - // Load icon from system theme only if it hasn't been found if (ret.isNull()) { -#if QT_VERSION >= 0x040600 ret = QIcon::fromTheme(name); if (!ret.isNull()) return ret; -#endif qLog(Warning) << "Couldn't load icon" << name; } diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index a9c66d8a3..526f1d899 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -40,7 +40,7 @@ #include #ifdef Q_OS_WIN32 -#include +#include #endif #include "core/appearance.h" @@ -223,6 +223,8 @@ MainWindow::MainWindow(Application* app, SystemTrayIcon* tray_icon, OSD* osd, track_position_timer_(new QTimer(this)), track_slider_timer_(new QTimer(this)), initialized_(false), + dirty_geometry_(false), + dirty_playback_(false), saved_playback_position_(0), saved_playback_state_(Engine::Empty), doubleclick_addmode_(AddBehaviour_Append), @@ -258,6 +260,9 @@ MainWindow::MainWindow(Application* app, SystemTrayIcon* tray_icon, OSD* osd, connect(global_search_view_, SIGNAL(AddToPlaylist(QMimeData*)), SLOT(AddToPlaylist(QMimeData*))); + // Set up the settings group early + settings_.beginGroup(kSettingsGroup); + // Add tabs to the fancy tab widget ui_->tabs->addTab(global_search_view_, IconLoader::Load("search", IconLoader::Base), @@ -292,7 +297,7 @@ MainWindow::MainWindow(Application* app, SystemTrayIcon* tray_icon, OSD* osd, ui_->tabs->setBackgroundPixmap(QPixmap(":/sidebar_background.png")); // Do this only after all default tabs have been added - ui_->tabs->loadSettings(kSettingsGroup); + ui_->tabs->loadSettings(settings_); track_position_timer_->setInterval(kTrackPositionUpdateTimeMs); connect(track_position_timer_, SIGNAL(timeout()), @@ -301,6 +306,9 @@ MainWindow::MainWindow(Application* app, SystemTrayIcon* tray_icon, OSD* osd, connect(track_slider_timer_, SIGNAL(timeout()), SLOT(UpdateTrackSliderPosition())); + connect(app_, SIGNAL(SaveSettings(QSettings*)), + SLOT(SaveSettings(QSettings*))); + // Start initialising the player qLog(Debug) << "Initialising player"; app_->player()->Init(); @@ -317,8 +325,7 @@ MainWindow::MainWindow(Application* app, SystemTrayIcon* tray_icon, OSD* osd, connect(ui_->playlist, SIGNAL(ViewSelectionModelChanged()), SLOT(PlaylistViewSelectionModelChanged())); - ui_->playlist->SetManager(app_->playlist_manager()); - ui_->playlist->view()->SetApplication(app_); + ui_->playlist->SetApplication(app_); library_view_->view()->setModel(library_sort_model_); library_view_->view()->SetApplication(app_); @@ -436,7 +443,7 @@ MainWindow::MainWindow(Application* app, SystemTrayIcon* tray_icon, OSD* osd, connect(ui_->action_remove_from_playlist, SIGNAL(triggered()), SLOT(PlaylistRemoveCurrent())); connect(ui_->action_toggle_show_sidebar, SIGNAL(toggled(bool)), - ui_->sidebar_layout, SLOT(setShown(bool))); + ui_->sidebar_layout, SLOT(setVisible(bool))); connect(ui_->action_edit_track, SIGNAL(triggered()), SLOT(EditTracks())); connect(ui_->action_renumber_tracks, SIGNAL(triggered()), SLOT(RenumberTracks())); @@ -875,11 +882,6 @@ MainWindow::MainWindow(Application* app, SystemTrayIcon* tray_icon, OSD* osd, connect(global_shortcuts_, SIGNAL(RemoveCurrentSong()), app_->playlist_manager(), SLOT(RemoveCurrentSong())); - // Fancy tabs - connect(ui_->tabs, SIGNAL(ModeChanged(FancyTabWidget::Mode)), - SLOT(SaveGeometry())); - connect(ui_->tabs, SIGNAL(CurrentChanged(int)), SLOT(SaveGeometry())); - // Lyrics ConnectInfoView(song_info_view_); ConnectInfoView(artist_info_view_); @@ -982,7 +984,6 @@ MainWindow::MainWindow(Application* app, SystemTrayIcon* tray_icon, OSD* osd, // Load settings qLog(Debug) << "Loading settings"; - settings_.beginGroup(kSettingsGroup); // Set last used geometry to position window on the correct monitor // Set window state only if the window was last maximized @@ -1069,13 +1070,11 @@ MainWindow::MainWindow(Application* app, SystemTrayIcon* tray_icon, OSD* osd, if (!options.contains_play_options()) LoadPlaybackStatus(); initialized_ = true; - SaveGeometry(); qLog(Debug) << "Started"; } MainWindow::~MainWindow() { - SaveGeometry(); delete ui_; } @@ -1090,21 +1089,18 @@ void MainWindow::ReloadSettings() { show(); #endif - QSettings s; - s.beginGroup(kSettingsGroup); - - doubleclick_addmode_ = - AddBehaviour(s.value("doubleclick_addmode", AddBehaviour_Append).toInt()); + doubleclick_addmode_ = AddBehaviour( + settings_.value("doubleclick_addmode", AddBehaviour_Append).toInt()); doubleclick_playmode_ = PlayBehaviour( - s.value("doubleclick_playmode", PlayBehaviour_IfStopped).toInt()); - doubleclick_playlist_addmode_ = - PlaylistAddBehaviour(s.value("doubleclick_playlist_addmode", - PlaylistAddBehaviour_Play).toInt()); - menu_playmode_ = - PlayBehaviour(s.value("menu_playmode", PlayBehaviour_IfStopped).toInt()); + settings_.value("doubleclick_playmode", PlayBehaviour_IfStopped).toInt()); + doubleclick_playlist_addmode_ = PlaylistAddBehaviour( + settings_.value("doubleclick_playlist_addmode", PlaylistAddBehaviour_Play) + .toInt()); + menu_playmode_ = PlayBehaviour( + settings_.value("menu_playmode", PlayBehaviour_IfStopped).toInt()); bool show_sidebar = settings_.value("show_sidebar", true).toBool(); - ui_->sidebar_layout->setShown(show_sidebar); + ui_->sidebar_layout->setVisible(show_sidebar); ui_->action_toggle_show_sidebar->setChecked(show_sidebar); } @@ -1283,54 +1279,61 @@ void MainWindow::ScrobbleButtonVisibilityChanged(bool value) { } } -void MainWindow::changeEvent(QEvent*) { +void MainWindow::SaveSettings(QSettings* settings) { if (!initialized_) return; - SaveGeometry(); + settings->beginGroup(kSettingsGroup); + if (dirty_geometry_) SaveGeometry(settings); + if (dirty_playback_) SavePlaybackStatus(settings); + settings->endGroup(); +} + +void MainWindow::changeEvent(QEvent*) { + dirty_geometry_ = true; + app_->DirtySettings(); } void MainWindow::resizeEvent(QResizeEvent*) { - if (!initialized_) return; - SaveGeometry(); + dirty_geometry_ = true; + app_->DirtySettings(); } -void MainWindow::SaveGeometry() { +void MainWindow::SaveGeometry(QSettings* settings) { if (!initialized_) return; + dirty_geometry_ = false; was_maximized_ = isMaximized(); - settings_.setValue("maximized", was_maximized_); + settings->setValue("maximized", was_maximized_); // Save the geometry only when mainwindow is not in maximized state if (!was_maximized_) { - settings_.setValue("geometry", saveGeometry()); + settings->setValue("geometry", saveGeometry()); } - settings_.setValue("splitter_state", ui_->splitter->saveState()); - settings_.setValue("current_tab", ui_->tabs->currentIndex()); - settings_.setValue("tab_mode", ui_->tabs->mode()); + settings->setValue("splitter_state", ui_->splitter->saveState()); + settings->setValue("current_tab", ui_->tabs->currentIndex()); + settings->setValue("tab_mode", ui_->tabs->mode()); - ui_->tabs->saveSettings(kSettingsGroup); + // Leaving this here for now + ui_->tabs->saveSettings(settings); } -void MainWindow::SavePlaybackStatus() { - QSettings settings; - settings.beginGroup(MainWindow::kSettingsGroup); - settings.setValue("playback_state", app_->player()->GetState()); +void MainWindow::SavePlaybackStatus(QSettings* settings) { + dirty_playback_ = false; + settings->setValue("playback_state", app_->player()->GetState()); if (app_->player()->GetState() == Engine::Playing || app_->player()->GetState() == Engine::Paused) { - settings.setValue( + settings->setValue( "playback_position", app_->player()->engine()->position_nanosec() / kNsecPerSec); } else { - settings.setValue("playback_position", 0); + settings->setValue("playback_position", 0); } } void MainWindow::LoadPlaybackStatus() { - QSettings settings; - settings.beginGroup(MainWindow::kSettingsGroup); bool resume_playback = - settings.value("resume_playback_after_start", false).toBool(); + settings_.value("resume_playback_after_start", false).toBool(); saved_playback_state_ = static_cast( - settings.value("playback_state", Engine::Empty).toInt()); - saved_playback_position_ = settings.value("playback_position", 0).toDouble(); + settings_.value("playback_state", Engine::Empty).toInt()); + saved_playback_position_ = settings_.value("playback_position", 0).toDouble(); if (!resume_playback || saved_playback_state_ == Engine::Empty || saved_playback_state_ == Engine::Idle) { return; @@ -1438,12 +1441,10 @@ void MainWindow::StopAfterCurrent() { } void MainWindow::closeEvent(QCloseEvent* event) { - QSettings s; - s.beginGroup(kSettingsGroup); - bool keep_running(false); if (tray_icon_) - keep_running = s.value("keeprunning", tray_icon_->IsVisible()).toBool(); + keep_running = + settings_.value("keeprunning", tray_icon_->IsVisible()).toBool(); if (keep_running && event->spontaneous()) { event->ignore(); @@ -1459,7 +1460,7 @@ void MainWindow::SetHiddenInTray(bool hidden) { // Some window managers don't remember maximized state between calls to // hide() and show(), so we have to remember it ourself. if (hidden) { - hide(); + QTimer::singleShot(0, this, &QWidget::hide); } else { if (was_maximized_) showMaximized(); @@ -2196,15 +2197,9 @@ void MainWindow::PlaylistEditFinished(const QModelIndex& index) { if (index == playlist_menu_index_) SelectionSetValue(); } -void MainWindow::CommandlineOptionsReceived( - const QByteArray& serialized_options) { - if (serialized_options == "wake up!") { - // Old versions of Clementine sent this - just ignore it - return; - } - +void MainWindow::CommandlineOptionsReceived(const QString& string_options) { CommandlineOptions options; - options.Load(serialized_options); + options.Load(string_options.toLatin1()); if (options.is_empty()) { show(); @@ -2805,10 +2800,13 @@ bool MainWindow::winEvent(MSG* msg, long*) { #endif // Q_OS_WIN32 void MainWindow::Exit() { - SaveGeometry(); - SavePlaybackStatus(); + // FIXME: This may add an extra write. + dirty_playback_ = true; settings_.setValue("show_sidebar", ui_->action_toggle_show_sidebar->isChecked()); + settings_.endGroup(); + SaveSettings(&settings_); + settings_.sync(); if (app_->player()->engine()->is_fadeout_enabled()) { // To shut down the application when fadeout will be finished diff --git a/src/ui/mainwindow.h b/src/ui/mainwindow.h index d14417f0e..74a6ff8cb 100644 --- a/src/ui/mainwindow.h +++ b/src/ui/mainwindow.h @@ -151,6 +151,7 @@ signals: private slots: void FilePathChanged(const QString& path); + void SaveSettings(QSettings* settings); void MediaStopped(); void MediaPaused(); void MediaPlaying(); @@ -240,7 +241,7 @@ signals: void AddCDTracks(); void AddPodcast(); - void CommandlineOptionsReceived(const QByteArray& serialized_options); + void CommandlineOptionsReceived(const QString& string_options); void CheckForUpdates(); @@ -266,8 +267,8 @@ signals: void OpenSettingsDialogAtPage(SettingsDialog::Page page); void ShowSongInfoConfig(); - void SaveGeometry(); - void SavePlaybackStatus(); + void SaveGeometry(QSettings* settings); + void SavePlaybackStatus(QSettings* settings); void LoadPlaybackStatus(); void ResumePlayback(); @@ -380,6 +381,10 @@ signals: QSettings settings_; bool initialized_; + + bool dirty_geometry_; + bool dirty_playback_; + bool was_maximized_; int saved_playback_position_; Engine::State saved_playback_state_; diff --git a/src/ui/qtsystemtrayicon.cpp b/src/ui/qtsystemtrayicon.cpp index 001bccf17..2fb1e5728 100644 --- a/src/ui/qtsystemtrayicon.cpp +++ b/src/ui/qtsystemtrayicon.cpp @@ -58,7 +58,7 @@ QtSystemTrayIcon::QtSystemTrayIcon(QObject* parent) QFile pattern_file(":/now_playing_tooltip.txt"); pattern_file.open(QIODevice::ReadOnly); - pattern_ = QString::fromAscii(pattern_file.readAll()); + pattern_ = QString::fromLatin1(pattern_file.readAll()); connect(tray_, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), SLOT(Clicked(QSystemTrayIcon::ActivationReason))); @@ -231,7 +231,7 @@ void QtSystemTrayIcon::SetVisible(bool visible) { tray_->setVisible(visible); } void QtSystemTrayIcon::SetNowPlaying(const Song& song, const QString& image_path) { -#ifdef Q_WS_WIN +#ifdef Q_OS_WIN // Windows doesn't support HTML in tooltips, so just show something basic tray_->setToolTip(song.PrettyTitleWithArtist()); return; @@ -245,14 +245,14 @@ void QtSystemTrayIcon::SetNowPlaying(const Song& song, clone.replace("%appName", QCoreApplication::applicationName()); clone.replace("%titleKey", tr("Title") % ":"); - clone.replace("%titleValue", Qt::escape(song.PrettyTitle())); + clone.replace("%titleValue", song.PrettyTitle().toHtmlEscaped()); clone.replace("%artistKey", tr("Artist") % ":"); - clone.replace("%artistValue", Qt::escape(song.artist())); + clone.replace("%artistValue", song.artist().toHtmlEscaped()); clone.replace("%albumKey", tr("Album") % ":"); - clone.replace("%albumValue", Qt::escape(song.album())); + clone.replace("%albumValue", song.album().toHtmlEscaped()); clone.replace("%lengthKey", tr("Length") % ":"); - clone.replace("%lengthValue", Qt::escape(song.PrettyLength())); + clone.replace("%lengthValue", song.PrettyLength().toHtmlEscaped()); if (columns == 2) { QString final_path = diff --git a/src/ui/ripcd.cpp b/src/ui/ripcd.cpp new file mode 100644 index 000000000..cbcd62670 --- /dev/null +++ b/src/ui/ripcd.cpp @@ -0,0 +1,520 @@ +/* This file is part of Clementine. + Copyright 2014, Andre Siviero + + Clementine is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Clementine is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Clementine. If not, see . + */ + +#include "ripcd.h" +#include "config.h" +#include "ui_ripcd.h" +#include "transcoder/transcoder.h" +#include "transcoder/transcoderoptionsdialog.h" +#include "ui/iconloader.h" +#include "core/closure.h" +#include "core/logging.h" +#include "core/tagreaderclient.h" +#include "core/utilities.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// winspool.h defines this :( +#ifdef AddJob +#undef AddJob +#endif + +namespace { +bool ComparePresetsByName(const TranscoderPreset& left, + const TranscoderPreset& right) { + return left.name_ < right.name_; +} + +const char kWavHeaderRiffMarker[] = "RIFF"; +const char kWavFileTypeFormatChunk[] = "WAVEfmt "; +const char kWavDataString[] = "data"; + +const int kCheckboxColumn = 0; +const int kTrackNumberColumn = 1; +const int kTrackTitleColumn = 2; +} +const char* RipCD::kSettingsGroup = "Transcoder"; +const int RipCD::kProgressInterval = 500; +const int RipCD::kMaxDestinationItems = 10; + +RipCD::RipCD(QWidget* parent) + : QDialog(parent), + transcoder_(new Transcoder(this)), + queued_(0), + finished_success_(0), + finished_failed_(0), + ui_(new Ui_RipCD), + cancel_requested_(false), + files_tagged_(0) { + cdio_ = cdio_open(NULL, DRIVER_UNKNOWN); + // Init + ui_->setupUi(this); + + // Set column widths in the QTableWidget. + ui_->tableWidget->horizontalHeader()->setSectionResizeMode( + kCheckboxColumn, QHeaderView::ResizeToContents); + ui_->tableWidget->horizontalHeader()->setSectionResizeMode( + kTrackNumberColumn, QHeaderView::ResizeToContents); + ui_->tableWidget->horizontalHeader()->setSectionResizeMode(kTrackTitleColumn, + QHeaderView::Stretch); + + // Add a rip button + rip_button_ = ui_->button_box->addButton(tr("Start ripping"), + QDialogButtonBox::ActionRole); + cancel_button_ = ui_->button_box->button(QDialogButtonBox::Cancel); + close_button_ = ui_->button_box->button(QDialogButtonBox::Close); + + // Hide elements + cancel_button_->hide(); + ui_->progress_group->hide(); + + connect(ui_->select_all_button, SIGNAL(clicked()), SLOT(SelectAll())); + connect(ui_->select_none_button, SIGNAL(clicked()), SLOT(SelectNone())); + connect(ui_->invert_selection_button, SIGNAL(clicked()), + SLOT(InvertSelection())); + connect(rip_button_, SIGNAL(clicked()), SLOT(ClickedRipButton())); + connect(cancel_button_, SIGNAL(clicked()), SLOT(Cancel())); + connect(close_button_, SIGNAL(clicked()), SLOT(hide())); + + connect(transcoder_, SIGNAL(JobComplete(QString, QString, bool)), + SLOT(TranscodingJobComplete(QString, QString, bool))); + connect(transcoder_, SIGNAL(AllJobsComplete()), + SLOT(AllTranscodingJobsComplete())); + connect(transcoder_, SIGNAL(LogLine(QString)), SLOT(LogLine(QString))); + connect(this, SIGNAL(RippingComplete()), SLOT(ThreadedTranscoding())); + connect(this, SIGNAL(SignalUpdateProgress()), SLOT(UpdateProgress())); + + connect(ui_->options, SIGNAL(clicked()), SLOT(Options())); + connect(ui_->select, SIGNAL(clicked()), SLOT(AddDestination())); + + setWindowTitle(tr("Rip CD")); + AddDestinationDirectory(QDir::homePath()); + + // Get presets + QList presets = Transcoder::GetAllPresets(); + qSort(presets.begin(), presets.end(), ComparePresetsByName); + for (const TranscoderPreset& preset : presets) { + ui_->format->addItem( + QString("%1 (.%2)").arg(preset.name_, preset.extension_), + QVariant::fromValue(preset)); + } + + // Load settings + QSettings s; + s.beginGroup(kSettingsGroup); + last_add_dir_ = s.value("last_add_dir", QDir::homePath()).toString(); + + QString last_output_format = s.value("last_output_format", "ogg").toString(); + for (int i = 0; i < ui_->format->count(); ++i) { + if (last_output_format == + ui_->format->itemData(i).value().extension_) { + ui_->format->setCurrentIndex(i); + break; + } + } + + ui_->progress_bar->setValue(0); + ui_->progress_bar->setMaximum(100); +} + +RipCD::~RipCD() { cdio_destroy(cdio_); } + +/* + * WAV Header documentation + * as taken from: + * http://www.topherlee.com/software/pcm-tut-wavformat.html + * Pos Value Description + * 0-3 | "RIFF" | Marks the file as a riff file. + * | Characters are each 1 byte long. + * 4-7 | File size (integer) | Size of the overall file - 8 bytes, + * | in bytes (32-bit integer). + * 8-11 | "WAVE" | File Type Header. For our purposes, + * | it always equals "WAVE". + * 13-16 | "fmt " | Format chunk marker. Includes trailing null. + * 17-20 | 16 | Length of format data as listed above + * 21-22 | 1 | Type of format (1 is PCM) - 2 byte integer + * 23-24 | 2 | Number of Channels - 2 byte integer + * 25-28 | 44100 | Sample Rate - 32 byte integer. Common values + * | are 44100 (CD), 48000 (DAT). + * | Sample Rate = Number of Samples per second, or Hertz. + * 29-32 | 176400 | (Sample Rate * BitsPerSample * Channels) / 8. + * 33-34 | 4 | (BitsPerSample * Channels) / 8.1 - 8 bit mono2 - 8 bit stereo/16 + * bit mono4 - 16 bit stereo + * 35-36 | 16 | Bits per sample + * 37-40 | "data" | "data" chunk header. + * | Marks the beginning of the data section. + * 41-44 | File size (data) | Size of the data section. + */ +void RipCD::WriteWAVHeader(QFile* stream, int32_t i_bytecount) { + QDataStream data_stream(stream); + data_stream.setByteOrder(QDataStream::LittleEndian); + // sizeof() - 1 to avoid including "\0" in the file too + data_stream.writeRawData(kWavHeaderRiffMarker, + sizeof(kWavHeaderRiffMarker) - 1); /* 0-3 */ + data_stream << qint32(i_bytecount + 44 - 8); /* 4-7 */ + data_stream.writeRawData(kWavFileTypeFormatChunk, + sizeof(kWavFileTypeFormatChunk) - 1); /* 8-15 */ + data_stream << (qint32)16; /* 16-19 */ + data_stream << (qint16)1; /* 20-21 */ + data_stream << (qint16)2; /* 22-23 */ + data_stream << (qint32)44100; /* 24-27 */ + data_stream << (qint32)(44100 * 2 * 2); /* 28-31 */ + data_stream << (qint16)4; /* 32-33 */ + data_stream << (qint16)16; /* 34-35 */ + data_stream.writeRawData(kWavDataString, + sizeof(kWavDataString) - 1); /* 36-39 */ + data_stream << (qint32)i_bytecount; /* 40-43 */ +} + +int RipCD::NumTracksToRip() { + int k = 0; + for (int i = 0; i < checkboxes_.length(); i++) { + if (checkboxes_.value(i)->isChecked()) { + k++; + } + } + return k; +} + +void RipCD::ThreadClickedRipButton() { + temporary_directory_ = Utilities::MakeTempDir() + "/"; + finished_success_ = 0; + finished_failed_ = 0; + ui_->progress_bar->setMaximum(NumTracksToRip() * 2 * 100); + + // Set up progress bar + emit(SignalUpdateProgress()); + + for (const TrackInformation& track : tracks_) { + QString filename = + QString("%1%2.wav").arg(temporary_directory_).arg(track.track_number); + QFile* destination_file = new QFile(filename); + destination_file->open(QIODevice::WriteOnly); + + lsn_t i_first_lsn = cdio_get_track_lsn(cdio_, track.track_number); + lsn_t i_last_lsn = cdio_get_track_last_lsn(cdio_, track.track_number); + WriteWAVHeader(destination_file, + (i_last_lsn - i_first_lsn + 1) * CDIO_CD_FRAMESIZE_RAW); + + QByteArray buffered_input_bytes(CDIO_CD_FRAMESIZE_RAW, '\0'); + for (lsn_t i_cursor = i_first_lsn; i_cursor <= i_last_lsn; i_cursor++) { + { + QMutexLocker l(&mutex_); + if (cancel_requested_) { + qLog(Debug) << "CD ripping canceled."; + return; + } + } + if (cdio_read_audio_sector(cdio_, buffered_input_bytes.data(), + i_cursor) == DRIVER_OP_SUCCESS) { + destination_file->write(buffered_input_bytes.data(), + buffered_input_bytes.size()); + } else { + qLog(Error) << "CD read error"; + break; + } + } + finished_success_++; + emit(SignalUpdateProgress()); + TranscoderPreset preset = ui_->format->itemData(ui_->format->currentIndex()) + .value(); + + transcoder_->AddJob(filename, preset, track.transcoded_filename); + } + emit(RippingComplete()); +} + +QString RipCD::GetOutputFileName(const QString& basename) const { + QString path = + ui_->destination->itemData(ui_->destination->currentIndex()).toString(); + QString extension = ui_->format->itemData(ui_->format->currentIndex()) + .value() + .extension_; + return path + '/' + basename + '.' + extension; +} + +QString RipCD::ParseFileFormatString(const QString& file_format, + int track_no) const { + QString to_return = file_format; + to_return.replace(QString("%artist%"), ui_->artistLineEdit->text()); + to_return.replace(QString("%album%"), ui_->albumLineEdit->text()); + to_return.replace(QString("%genre%"), ui_->genreLineEdit->text()); + to_return.replace(QString("%year%"), ui_->yearLineEdit->text()); + to_return.replace(QString("%tracknum%"), QString::number(track_no)); + to_return.replace(QString("%track%"), + track_names_.value(track_no - 1)->text()); + return to_return; +} + +void RipCD::UpdateProgress() { + int progress = (finished_success_ + finished_failed_) * 100; + QMap current_jobs = transcoder_->GetProgress(); + for (float value : current_jobs.values()) { + progress += qBound(0, static_cast(value * 100), 99); + } + + ui_->progress_bar->setValue(progress); +} + +void RipCD::ThreadedTranscoding() { + transcoder_->Start(); + TranscoderPreset preset = ui_->format->itemData(ui_->format->currentIndex()) + .value(); + // Save the last output format + QSettings s; + s.beginGroup(kSettingsGroup); + s.setValue("last_output_format", preset.extension_); +} + +void RipCD::ClickedRipButton() { + if (cdio_ && cdio_get_media_changed(cdio_)) { + QMessageBox cdio_fail(QMessageBox::Critical, tr("Error Ripping CD"), + tr("Media has changed. Reloading")); + cdio_fail.exec(); + if (CheckCDIOIsValid()) { + BuildTrackListTable(); + } else { + ui_->tableWidget->clearContents(); + } + return; + } + + // Add tracks to the rip list. + tracks_.clear(); + for (int i = 1; i <= i_tracks_; ++i) { + if (!checkboxes_.value(i - 1)->isChecked()) { + continue; + } + QString transcoded_filename = GetOutputFileName( + ParseFileFormatString(ui_->format_filename->text(), i)); + QString title = track_names_.value(i - 1)->text(); + AddTrack(i, title, transcoded_filename); + } + + // Do nothing if no tracks are selected. + if (tracks_.isEmpty()) + return; + + // Start ripping. + SetWorking(true); + { + QMutexLocker l(&mutex_); + cancel_requested_ = false; + } + QtConcurrent::run(this, &RipCD::ThreadClickedRipButton); +} + +void RipCD::AddTrack(int track_number, const QString& title, + const QString& transcoded_filename) { + TrackInformation track(track_number, title, transcoded_filename); + tracks_.append(track); +} + +void RipCD::TranscodingJobComplete(const QString& input, const QString& output, bool success) { + (*(success ? &finished_success_ : &finished_failed_))++; + emit(SignalUpdateProgress()); +} + +void RipCD::AllTranscodingJobsComplete() { + RemoveTemporaryDirectory(); + + // Save tags. + TranscoderPreset preset = ui_->format->itemData(ui_->format->currentIndex()) + .value(); + AlbumInformation album( + ui_->albumLineEdit->text(), ui_->artistLineEdit->text(), + ui_->genreLineEdit->text(), ui_->yearLineEdit->text().toInt(), + ui_->discLineEdit->text().toInt(), preset.type_); + TagFiles(album, tracks_); +} + +void RipCD::TagFiles(const AlbumInformation& album, + const QList& tracks) { + files_tagged_ = 0; + for (const TrackInformation& track : tracks_) { + Song song; + song.InitFromFilePartial(track.transcoded_filename); + song.set_track(track.track_number); + song.set_title(track.title); + song.set_album(album.album); + song.set_artist(album.artist); + song.set_genre(album.genre); + song.set_year(album.year); + song.set_disc(album.disc); + song.set_filetype(album.type); + + TagReaderReply* reply = + TagReaderClient::Instance()->SaveFile(song.url().toLocalFile(), song); + NewClosure(reply, SIGNAL(Finished(bool)), this, + SLOT(FileTagged(TagReaderReply*)), reply); + } +} + +void RipCD::FileTagged(TagReaderReply* reply) { + files_tagged_++; + qLog(Debug) << "Tagged" << files_tagged_ << "of" << tracks_.length() + << "files"; + + // Stop working if all files are tagged. + if (files_tagged_ == tracks_.length()) { + qLog(Debug) << "CD ripper finished."; + SetWorking(false); + } + + reply->deleteLater(); +} + +void RipCD::Options() { + TranscoderPreset preset = ui_->format->itemData(ui_->format->currentIndex()) + .value(); + + TranscoderOptionsDialog dialog(preset.type_, this); + if (dialog.is_valid()) { + dialog.exec(); + } +} + +// Adds a folder to the destination box. +void RipCD::AddDestination() { + int index = ui_->destination->currentIndex(); + QString initial_dir = (!ui_->destination->itemData(index).isNull() + ? ui_->destination->itemData(index).toString() + : QDir::homePath()); + QString dir = + QFileDialog::getExistingDirectory(this, tr("Add folder"), initial_dir); + + if (!dir.isEmpty()) { + // Keep only a finite number of items in the box. + while (ui_->destination->count() >= kMaxDestinationItems) { + ui_->destination->removeItem(0); // The oldest item. + } + AddDestinationDirectory(dir); + } +} + +// Adds a directory to the 'destination' combo box. +void RipCD::AddDestinationDirectory(QString dir) { + QIcon icon = IconLoader::Load("folder"); + QVariant data = QVariant::fromValue(dir); + // Do not insert duplicates. + int duplicate_index = ui_->destination->findData(data); + if (duplicate_index == -1) { + ui_->destination->addItem(icon, dir, data); + ui_->destination->setCurrentIndex(ui_->destination->count() - 1); + } else { + ui_->destination->setCurrentIndex(duplicate_index); + } +} + +void RipCD::Cancel() { + { + QMutexLocker l(&mutex_); + cancel_requested_ = true; + } + ui_->progress_bar->setValue(0); + transcoder_->Cancel(); + RemoveTemporaryDirectory(); + SetWorking(false); +} + +bool RipCD::CheckCDIOIsValid() { + if (cdio_) { + cdio_destroy(cdio_); + } + cdio_ = cdio_open(NULL, DRIVER_UNKNOWN); + // Refresh the status of the cd media. This will prevent unnecessary + // rebuilds of the track list table. + cdio_get_media_changed(cdio_); + return cdio_; +} + +void RipCD::SetWorking(bool working) { + rip_button_->setVisible(!working); + cancel_button_->setVisible(working); + close_button_->setVisible(!working); + ui_->input_group->setEnabled(!working); + ui_->output_group->setEnabled(!working); + ui_->progress_group->setVisible(true); +} + +void RipCD::SelectAll() { + for (QCheckBox* checkbox : checkboxes_) { + checkbox->setCheckState(Qt::Checked); + } +} + +void RipCD::SelectNone() { + for (QCheckBox* checkbox : checkboxes_) { + checkbox->setCheckState(Qt::Unchecked); + } +} + +void RipCD::InvertSelection() { + for (QCheckBox* checkbox : checkboxes_) { + if (checkbox->isChecked()) { + checkbox->setCheckState(Qt::Unchecked); + } else { + checkbox->setCheckState(Qt::Checked); + } + } +} + +void RipCD::RemoveTemporaryDirectory() { + if (!temporary_directory_.isEmpty()) + Utilities::RemoveRecursive(temporary_directory_); + temporary_directory_.clear(); +} + +void RipCD::BuildTrackListTable() { + checkboxes_.clear(); + track_names_.clear(); + + i_tracks_ = cdio_get_num_tracks(cdio_); + // Build an empty table if there is an error, e.g. no medium found. + if (i_tracks_ == CDIO_INVALID_TRACK) + i_tracks_ = 0; + + ui_->tableWidget->setRowCount(i_tracks_); + for (int i = 1; i <= i_tracks_; i++) { + QCheckBox* checkbox_i = new QCheckBox(ui_->tableWidget); + checkbox_i->setCheckState(Qt::Checked); + checkboxes_.append(checkbox_i); + ui_->tableWidget->setCellWidget(i - 1, kCheckboxColumn, checkbox_i); + ui_->tableWidget->setCellWidget(i - 1, kTrackNumberColumn, + new QLabel(QString::number(i))); + QString track_title = QString("Track %1").arg(i); + QLineEdit* line_edit_track_title_i = + new QLineEdit(track_title, ui_->tableWidget); + track_names_.append(line_edit_track_title_i); + ui_->tableWidget->setCellWidget(i - 1, kTrackTitleColumn, + line_edit_track_title_i); + } +} + +void RipCD::LogLine(const QString& message) { qLog(Debug) << message; } + +void RipCD::showEvent(QShowEvent* event) { BuildTrackListTable(); } diff --git a/src/ui/windows7thumbbar.cpp b/src/ui/windows7thumbbar.cpp index 4eb754e40..50b2254d5 100644 --- a/src/ui/windows7thumbbar.cpp +++ b/src/ui/windows7thumbbar.cpp @@ -22,10 +22,12 @@ #include #ifdef Q_OS_WIN32 -#define _WIN32_WINNT 0x0600 -#include -#include -#include +# ifndef _WIN32_WINNT +# define _WIN32_WINNT 0x0600 +# endif +# include +# include +# include #endif // Q_OS_WIN32 const int Windows7ThumbBar::kIconSize = 16; @@ -53,10 +55,13 @@ void Windows7ThumbBar::SetActions(const QList& actions) { } #ifdef Q_OS_WIN32 + +extern HICON qt_pixmapToWinHICON(const QPixmap &p); + static void SetupButton(const QAction* action, THUMBBUTTON* button) { if (action) { button->hIcon = - action->icon().pixmap(Windows7ThumbBar::kIconSize).toWinHICON(); + qt_pixmapToWinHICON(action->icon().pixmap(Windows7ThumbBar::kIconSize)); button->dwFlags = action->isEnabled() ? THBF_ENABLED : THBF_DISABLED; // This is unsafe - doesn't obey 260-char restriction action->text().toWCharArray(button->szTip); @@ -130,7 +135,7 @@ void Windows7ThumbBar::HandleWinEvent(MSG* msg) { } qLog(Debug) << "Adding buttons"; - hr = taskbar_list->ThumbBarAddButtons(widget_->winId(), actions_.count(), + hr = taskbar_list->ThumbBarAddButtons((HWND)widget_->winId(), actions_.count(), buttons); if (hr != S_OK) qLog(Debug) << "Failed to add buttons" << hex << DWORD(hr); for (int i = 0; i < actions_.count(); i++) { @@ -164,7 +169,7 @@ void Windows7ThumbBar::ActionChanged() { if (buttons->hIcon > 0) DestroyIcon(buttons->hIcon); } - taskbar_list->ThumbBarUpdateButtons(widget_->winId(), actions_.count(), + taskbar_list->ThumbBarUpdateButtons((HWND)widget_->winId(), actions_.count(), buttons); #endif // Q_OS_WIN32 } diff --git a/src/widgets/errordialog.cpp b/src/widgets/errordialog.cpp index eb6e0bef8..3fd590840 100644 --- a/src/widgets/errordialog.cpp +++ b/src/widgets/errordialog.cpp @@ -18,6 +18,8 @@ #include "errordialog.h" #include "ui_errordialog.h" +#include + ErrorDialog::ErrorDialog(QWidget* parent) : QDialog(parent), ui_(new Ui_ErrorDialog) { ui_->setupUi(this); @@ -53,7 +55,7 @@ void ErrorDialog::UpdateContent() { QString html; for (const QString& message : current_messages_) { if (!html.isEmpty()) html += "
"; - html += Qt::escape(message); + html += message.toHtmlEscaped(); } ui_->messages->setHtml(html); } diff --git a/src/widgets/fancytabwidget.cpp b/src/widgets/fancytabwidget.cpp index 945b01dac..98f4b2daf 100644 --- a/src/widgets/fancytabwidget.cpp +++ b/src/widgets/fancytabwidget.cpp @@ -52,7 +52,7 @@ public: QSize size(QTabBar::sizeHint()); FancyTabWidget *tabWidget = (FancyTabWidget*) parentWidget(); - if(tabWidget->mode() == FancyTabWidget::Mode_Tabs || + if(tabWidget->mode() == FancyTabWidget::Mode_Tabs || tabWidget->mode() == FancyTabWidget::Mode_IconOnlyTabs) return size; @@ -76,10 +76,10 @@ protected: if(tabWidget->mode() != FancyTabWidget::Mode_LargeSidebar) { size = QTabBar::tabSizeHint(index); } - + return size; } - + void leaveEvent(QEvent * event) { mouseHoverTabIndex = -1; update(); @@ -124,7 +124,7 @@ protected: QStylePainter p(this); - + for (int index = 0; index < count(); index++) { const bool selected = tabWidget->currentIndex() == index;; @@ -174,7 +174,7 @@ protected: p.restore(); } - // Label (Icon and Text) + // Label (Icon and Text) { p.save(); QTransform m; @@ -212,12 +212,12 @@ protected: boldFont.setBold(true); p.setFont(boldFont); - // Text drop shadow color + // Text drop shadow color p.setPen(selected ? QColor(255,255,255,160) : QColor(0,0,0,110) ); p.translate(0, 3); p.drawText(tabrectText, textFlags, tabText(index)); - // Text foreground color + // Text foreground color p.translate(0, -1); p.setPen(selected ? QColor(60, 60, 60) : Utils::StyleHelper::panelTextColor()); p.drawText(tabrectText, textFlags, tabText(index)); @@ -228,13 +228,13 @@ protected: const int PADDING = 5; if(verticalTextTabs) { tabrectIcon = tabrectLabel; - tabrectIcon.setSize(FancyTabWidget::IconSize_SmallSidebar); + tabrectIcon.setSize(FancyTabWidget::IconSize_SmallSidebar); tabrectIcon.translate(PADDING,PADDING); } else { tabrectIcon = tabrectLabel; - tabrectIcon.setSize(FancyTabWidget::IconSize_LargeSidebar); + tabrectIcon.setSize(FancyTabWidget::IconSize_LargeSidebar); // Center the icon - const int moveRight = (FancyTabWidget::TabSize_LargeSidebar.width() - + const int moveRight = (FancyTabWidget::TabSize_LargeSidebar.width() - FancyTabWidget::IconSize_LargeSidebar.width() -1)/2; tabrectIcon.translate(moveRight,PADDING); } @@ -244,7 +244,7 @@ protected: } } }; - + // Spacers are just disabled pages void FancyTabWidget::addSpacer() { QWidget *spacer = new QWidget(); @@ -259,7 +259,7 @@ void FancyTabWidget::setBackgroundPixmap(const QPixmap& pixmap) { void FancyTabWidget::setCurrentIndex(int index) { QWidget* currentPage = widget(index); - + QLayout *layout = currentPage->layout(); if(bottom_widget_ != nullptr) layout->addWidget(bottom_widget_); @@ -270,14 +270,14 @@ void FancyTabWidget::setCurrentIndex(int index) { // Slot void FancyTabWidget::currentTabChanged(int index) { QWidget* currentPage = currentWidget(); - + QLayout *layout = currentPage->layout(); if(bottom_widget_ != nullptr) layout->addWidget(bottom_widget_); emit CurrentChanged(index); } -FancyTabWidget::FancyTabWidget(QWidget* parent) : QTabWidget(parent), +FancyTabWidget::FancyTabWidget(QWidget* parent) : QTabWidget(parent), menu_(nullptr), mode_(Mode_None), bottom_widget_(nullptr) { @@ -290,33 +290,27 @@ FancyTabWidget::FancyTabWidget(QWidget* parent) : QTabWidget(parent), connect(tabBar, SIGNAL(currentChanged(int)), this, SLOT(currentTabChanged(int))); } -void FancyTabWidget::loadSettings(const char *kSettingsGroup) { - QSettings settings; - settings.beginGroup(kSettingsGroup); +void FancyTabWidget::loadSettings(const QSettings& settings) { + for (int i = 0; i < count(); i++) { + int originalIndex = tabBar()->tabData(i).toInt(); + QString k = "tab_index_" + QString::number(originalIndex); - for(int i =0;itabData(i).toInt(); - std::string k = "tab_index_" + std::to_string(originalIndex); + int newIndex = settings.value(k, i).toInt(); - int newIndex = settings.value(QString::fromStdString(k), i).toInt(); - - if(newIndex >= 0) - tabBar()->moveTab(i,newIndex); - else - removeTab(i); // Does not delete page - } + if (newIndex >= 0) + tabBar()->moveTab(i, newIndex); + else + removeTab(i); // Does not delete page + } } -void FancyTabWidget::saveSettings(const char *kSettingsGroup) { - QSettings settings; - settings.beginGroup(kSettingsGroup); +void FancyTabWidget::saveSettings(QSettings* settings) { + for (int i = 0; i < count(); i++) { + int originalIndex = tabBar()->tabData(i).toInt(); + QString k = "tab_index_" + QString::number(originalIndex); - for(int i =0;itabData(i).toInt(); - std::string k = "tab_index_" + std::to_string(originalIndex); - - settings.setValue(QString::fromStdString(k), i); - } + settings->setValue(k, i); + } } @@ -329,7 +323,7 @@ int FancyTabWidget::addTab(QWidget * page, const QIcon & icon, const QString & l } int FancyTabWidget::insertTab(int index, QWidget * page, const QIcon & icon, const QString & label) { - // In order to achieve the same effect as the "Bottom Widget" of the + // In order to achieve the same effect as the "Bottom Widget" of the // old Nokia based FancyTabWidget a VBoxLayout is used on each page QVBoxLayout *layout = new QVBoxLayout(); layout->setSpacing(0); @@ -340,7 +334,7 @@ int FancyTabWidget::insertTab(int index, QWidget * page, const QIcon & icon, con newPage->setLayout(layout); const int actualIndex = QTabWidget::insertTab(index,newPage,icon,label); - + // Remember the original index. Needed to save order of tabs tabBar()->setTabData(actualIndex,QVariant(actualIndex)); return actualIndex; @@ -354,14 +348,14 @@ void FancyTabWidget::paintEvent(QPaintEvent *pe) { } QStylePainter p(this); - // The brown color (Ubuntu) you see on the background gradient + // The brown color (Ubuntu) you see on the background gradient QColor baseColor = StyleHelper::baseColor(); QRect backgroundRect = rect(); backgroundRect.setWidth(((FancyTabBar*)tabBar())->width()); p.fillRect(backgroundRect,baseColor); - // Horizontal gradient over the sidebar from transparent to dark + // Horizontal gradient over the sidebar from transparent to dark Utils::StyleHelper::verticalGradient(&p,backgroundRect,backgroundRect,false); // Draw the translucent png graphics over the gradient fill @@ -401,7 +395,7 @@ void FancyTabWidget::tabBarUpdateGeometry() { void FancyTabWidget::SetMode(FancyTabWidget::Mode mode) { mode_ = mode; - if(mode == FancyTabWidget::Mode_Tabs || + if(mode == FancyTabWidget::Mode_Tabs || mode == FancyTabWidget::Mode_IconOnlyTabs) { setTabPosition(QTabWidget::North); } else { @@ -411,7 +405,7 @@ void FancyTabWidget::SetMode(FancyTabWidget::Mode mode) { tabBar()->updateGeometry(); updateGeometry(); - // There appears to be a bug in QTabBar which causes tabSizeHint + // There appears to be a bug in QTabBar which causes tabSizeHint // to be ignored thus the need for this second shot repaint QTimer::singleShot(1,this,SLOT(tabBarUpdateGeometry())); diff --git a/src/widgets/fancytabwidget.h b/src/widgets/fancytabwidget.h index e426ef46f..c18de5221 100644 --- a/src/widgets/fancytabwidget.h +++ b/src/widgets/fancytabwidget.h @@ -25,6 +25,7 @@ class QActionGroup; class QMenu; +class QSettings; class QSignalMapper; namespace Core { @@ -43,8 +44,8 @@ class FancyTabWidget : public QTabWidget { void setBackgroundPixmap(const QPixmap& pixmap); void addSpacer(); - void loadSettings(const char *); - void saveSettings(const char *); + void loadSettings(const QSettings&); + void saveSettings(QSettings*); // Values are persisted - only add to the end enum Mode { Mode_None = 0, diff --git a/src/widgets/forcescrollperpixel.cpp b/src/widgets/forcescrollperpixel.cpp index 065c1e47b..f7aea32c1 100644 --- a/src/widgets/forcescrollperpixel.cpp +++ b/src/widgets/forcescrollperpixel.cpp @@ -29,8 +29,7 @@ ForceScrollPerPixel::ForceScrollPerPixel(QAbstractItemView* item_view, bool ForceScrollPerPixel::eventFilter(QObject* object, QEvent* event) { if (object == item_view_ && event->type() != QEvent::Destroy && - event->type() != QEvent::WinIdChange && - event->type() != QEvent::AccessibilityPrepare) { + event->type() != QEvent::WinIdChange) { item_view_->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel); item_view_->verticalScrollBar()->setSingleStep(20); } diff --git a/src/widgets/groupediconview.cpp b/src/widgets/groupediconview.cpp index d6cb0ed33..77801acb1 100644 --- a/src/widgets/groupediconview.cpp +++ b/src/widgets/groupediconview.cpp @@ -113,7 +113,7 @@ void GroupedIconView::rowsInserted(const QModelIndex& parent, int start, } void GroupedIconView::dataChanged(const QModelIndex& topLeft, - const QModelIndex& bottomRight) { + const QModelIndex& bottomRight, const QVector &) { QListView::dataChanged(topLeft, bottomRight); LayoutItems(); } @@ -214,8 +214,8 @@ void GroupedIconView::paintEvent(QPaintEvent* e) { // This code was adapted from QListView::paintEvent(), changed to use the // visualRect() of items, and to draw headers. - QStyleOptionViewItemV4 option(viewOptions()); - if (isWrapping()) option.features = QStyleOptionViewItemV2::WrapText; + QStyleOptionViewItem option(viewOptions()); + if (isWrapping()) option.features = QStyleOptionViewItem::WrapText; option.locale = locale(); option.locale.setNumberOptions(QLocale::OmitGroupSeparator); option.widget = this; diff --git a/src/widgets/groupediconview.h b/src/widgets/groupediconview.h index 42e08bf1f..025e5584d 100644 --- a/src/widgets/groupediconview.h +++ b/src/widgets/groupediconview.h @@ -72,7 +72,7 @@ class GroupedIconView : public QListView { void resizeEvent(QResizeEvent* e); // QAbstractItemView - void dataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight); + void dataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight, const QVector& = QVector()); QModelIndex indexAt(const QPoint& p) const; void rowsInserted(const QModelIndex& parent, int start, int end); void setSelection(const QRect& rect, diff --git a/src/widgets/nowplayingwidget.cpp b/src/widgets/nowplayingwidget.cpp index c508626c9..5a86f7196 100644 --- a/src/widgets/nowplayingwidget.cpp +++ b/src/widgets/nowplayingwidget.cpp @@ -292,8 +292,8 @@ void NowPlayingWidget::UpdateDetailsText() { // TODO: Make this configurable html += QString("%1
%2
%3").arg( - Qt::escape(metadata_.PrettyTitle()), Qt::escape(metadata_.artist()), - Qt::escape(metadata_.album())); + metadata_.PrettyTitle().toHtmlEscaped(), metadata_.artist().toHtmlEscaped(), + metadata_.album().toHtmlEscaped()); html += "

"; details_->setHtml(html); diff --git a/src/widgets/osd.cpp b/src/widgets/osd.cpp index e67c95745..7cd74dfbf 100644 --- a/src/widgets/osd.cpp +++ b/src/widgets/osd.cpp @@ -237,8 +237,6 @@ void OSD::ShowMessage(const QString& summary, const QString& message, void OSD::CallFinished(QDBusPendingCallWatcher*) {} #endif -#ifdef HAVE_WIIMOTEDEV - void OSD::WiiremoteActived(int id) { ShowMessage(QString(tr("%1: Wiimotedev module")) .arg(QCoreApplication::applicationName()), @@ -277,8 +275,6 @@ void OSD::WiiremoteCriticalBattery(int id, int live) { .arg(QString::number(id), QString::number(live))); } -#endif - void OSD::ShuffleModeChanged(PlaylistSequence::ShuffleMode mode) { if (show_on_play_mode_change_) { QString current_mode = QString(); diff --git a/src/widgets/osd.h b/src/widgets/osd.h index 5d938e358..fc2e0575c 100644 --- a/src/widgets/osd.h +++ b/src/widgets/osd.h @@ -82,14 +82,12 @@ class OSD : public QObject { void ReshowCurrentSong(); -#ifdef HAVE_WIIMOTEDEV void WiiremoteActived(int id); void WiiremoteDeactived(int id); void WiiremoteConnected(int id); void WiiremoteDisconnected(int id); void WiiremoteLowBattery(int id, int live); void WiiremoteCriticalBattery(int id, int live); -#endif void ShowPreview(const Behaviour type, const QString& line1, const QString& line2, const Song& song); diff --git a/src/widgets/osd_x11.cpp b/src/widgets/osd_x11.cpp index 8577b1fe6..55bf7db0e 100644 --- a/src/widgets/osd_x11.cpp +++ b/src/widgets/osd_x11.cpp @@ -66,7 +66,7 @@ QDBusArgument& operator<<(QDBusArgument& arg, const QImage& image) { int channels = i.isGrayscale() ? 1 : (i.hasAlphaChannel() ? 4 : 3); arg << i.depth() / channels; arg << channels; - arg << QByteArray(reinterpret_cast(i.bits()), i.numBytes()); + arg << QByteArray(reinterpret_cast(i.bits()), i.byteCount()); arg.endStructure(); return arg; } diff --git a/src/widgets/osdpretty.cpp b/src/widgets/osdpretty.cpp index 0440b6a3f..9d95716d8 100644 --- a/src/widgets/osdpretty.cpp +++ b/src/widgets/osdpretty.cpp @@ -15,6 +15,7 @@ along with Clementine. If not, see . */ +#include "config.h" #include "osdpretty.h" #include "ui_osdpretty.h" @@ -31,12 +32,14 @@ #include -#ifdef Q_WS_X11 +#ifdef HAVE_X11 #include #endif +#ifdef Q_OS_WIN32 +# include +#endif #ifdef Q_OS_WIN32 -#include "qtwin.h" #include #endif @@ -76,9 +79,9 @@ OSDPretty::OSDPretty(Mode mode, QWidget* parent) #ifdef Q_OS_WIN32 // Don't show the window in the taskbar. Qt::ToolTip does this too, but it // adds an extra ugly shadow. - int ex_style = GetWindowLong(winId(), GWL_EXSTYLE); + int ex_style = GetWindowLong((HWND)winId(), GWL_EXSTYLE); ex_style |= WS_EX_NOACTIVATE; - SetWindowLong(winId(), GWL_EXSTYLE, ex_style); + SetWindowLong((HWND)winId(), GWL_EXSTYLE, ex_style); #endif // Mode settings @@ -137,7 +140,7 @@ OSDPretty::OSDPretty(Mode mode, QWidget* parent) OSDPretty::~OSDPretty() { delete ui_; } bool OSDPretty::IsTransparencyAvailable() { -#ifdef Q_WS_X11 +#if defined(HAVE_X11) && (QT_VERSION >= QT_VERSION_CHECK(5, 7, 0)) return QX11Info::isCompositingManagerRunning(); #endif return true; @@ -346,7 +349,7 @@ void OSDPretty::Reposition() { #ifdef Q_OS_WIN32 // On windows, enable blurbehind on the masked area - QtWin::enableBlurBehindWindow(this, true, QRegion(mask)); + QtWin::enableBlurBehindWindow(this, QRegion(mask)); #endif } diff --git a/src/widgets/stretchheaderview.cpp b/src/widgets/stretchheaderview.cpp index 77d988873..e2f8838ee 100644 --- a/src/widgets/stretchheaderview.cpp +++ b/src/widgets/stretchheaderview.cpp @@ -39,11 +39,6 @@ StretchHeaderView::StretchHeaderView(Qt::Orientation orientation, void StretchHeaderView::setModel(QAbstractItemModel* model) { QHeaderView::setModel(model); - - if (stretch_enabled_) { - column_widths_.resize(count()); - std::fill(column_widths_.begin(), column_widths_.end(), 1.0 / count()); - } } void StretchHeaderView::NormaliseWidths(const QList& sections) { diff --git a/src/widgets/stylehelper.cpp b/src/widgets/stylehelper.cpp index 23ab4c697..87674af37 100644 --- a/src/widgets/stylehelper.cpp +++ b/src/widgets/stylehelper.cpp @@ -30,12 +30,12 @@ #include "stylehelper.h" #include -#include +#include #include #include -#include +#include #include -#include +#include #include // Clamps float color values within (0, 255) @@ -47,7 +47,7 @@ static int clamp(float x) { namespace Utils { qreal StyleHelper::sidebarFontSize() { -#if defined(Q_WS_MAC) +#if defined(Q_OS_MAC) return 10; #else return 7.5; diff --git a/src/widgets/stylehelper.h b/src/widgets/stylehelper.h index f73f4b442..77c62b9ec 100644 --- a/src/widgets/stylehelper.h +++ b/src/widgets/stylehelper.h @@ -30,8 +30,8 @@ #ifndef STYLEHELPER_H #define STYLEHELPER_H -#include -#include +#include +#include #include "ui/qt_blurimage.h" diff --git a/src/widgets/widgetfadehelper.cpp b/src/widgets/widgetfadehelper.cpp index adb1fcb67..407b7521f 100644 --- a/src/widgets/widgetfadehelper.cpp +++ b/src/widgets/widgetfadehelper.cpp @@ -76,7 +76,7 @@ void WidgetFadeHelper::StartBlur() { void WidgetFadeHelper::CaptureParent() { // Take a "screenshot" of the window - original_pixmap_ = QPixmap::grabWidget(parent_); + original_pixmap_ = parent_->grab(); QImage original_image = original_pixmap_.toImage(); // Blur it diff --git a/src/wiimotedev/wiimotesettingspage.cpp b/src/wiimotedev/wiimotesettingspage.cpp index f12937b06..8b086de32 100644 --- a/src/wiimotedev/wiimotesettingspage.cpp +++ b/src/wiimotedev/wiimotesettingspage.cpp @@ -27,7 +27,7 @@ WiimoteSettingsPage::WiimoteSettingsPage(SettingsDialog* dialog) : SettingsPage(dialog), ui_(new Ui_WiimoteSettingsPage) { ui_->setupUi(this); - ui_->list->header()->setResizeMode(QHeaderView::ResizeToContents); + ui_->list->header()->setSectionResizeMode(QHeaderView::ResizeToContents); setWindowIcon(IconLoader::Load("wiimotedev", IconLoader::Base)); ui_->wiimotedev_add_action->setIcon(IconLoader::Load("list-add", IconLoader::Base)); diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 4227bb48e..4474e7be5 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 2.6) +cmake_minimum_required(VERSION 2.8.11) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x -fpermissive -Wno-c++11-narrowing -U__STRICT_ANSI__") @@ -69,21 +69,21 @@ set(TESTUTILS-MOC-HEADERS testobjectdecorators.h ) -qt4_wrap_cpp(TESTUTILS-SOURCES-MOC ${TESTUTILS-MOC-HEADERS}) +qt5_wrap_cpp(TESTUTILS-SOURCES-MOC ${TESTUTILS-MOC-HEADERS}) add_library(test_utils STATIC EXCLUDE_FROM_ALL ${TESTUTILS-SOURCES} ${TESTUTILS-SOURCES-MOC}) target_link_libraries(test_utils ${GMOCK_LIBRARIES} ${QT_LIBRARIES} ${QT_QTTEST_LIBRARY}) -add_custom_target(test - echo "Running tests" +add_custom_target(clementine_test + echo "Running Clementine tests" WORKING_DIRECTORY ${CURRENT_BINARY_DIR} ) add_custom_target(build_tests WORKING_DIRECTORY ${CURRENT_BINARY_DIR} ) -add_dependencies(test build_tests) +add_dependencies(clementine_test build_tests) -qt4_add_resources(TEST-RESOURCE-SOURCES data/testdata.qrc) +qt5_add_resources(TEST-RESOURCE-SOURCES data/testdata.qrc) add_library(test_gui_main STATIC EXCLUDE_FROM_ALL ${TEST-RESOURCE-SOURCES} main.cpp) target_link_libraries(test_gui_main clementine_lib) @@ -99,7 +99,7 @@ macro(add_test_file test_source gui_required) EXCLUDE_FROM_ALL ${test_source} ) - target_link_libraries(${TEST_NAME} ${GMOCK_LIBRARIES} clementine_lib test_utils) + target_link_libraries(${TEST_NAME} ${GMOCK_LIBRARIES} clementine_lib test_utils Qt5::Test) set(GUI_REQUIRED ${gui_required}) if (GUI_REQUIRED) target_link_libraries(${TEST_NAME} test_gui_main) @@ -112,7 +112,7 @@ macro(add_test_file test_source gui_required) set_target_properties(${TEST_NAME} PROPERTIES COMPILE_FLAGS "-Wno-bool-conversions") endif (SUPPORTS_NOBOOL) - add_custom_command(TARGET test POST_BUILD + add_custom_command(TARGET clementine_test POST_BUILD COMMAND ./${TEST_NAME}${CMAKE_EXECUTABLE_SUFFIX}) add_dependencies(build_tests ${TEST_NAME}) endmacro (add_test_file) diff --git a/tests/albumcoverfetcher_test.cpp b/tests/albumcoverfetcher_test.cpp index a1a052c05..c96011fe8 100644 --- a/tests/albumcoverfetcher_test.cpp +++ b/tests/albumcoverfetcher_test.cpp @@ -18,7 +18,7 @@ #include "core/albumcoverfetcher.h" #include "core/networkaccessmanager.h" -#include +#include #include #include diff --git a/tests/main.cpp b/tests/main.cpp index eb058fbc6..85e42b93f 100644 --- a/tests/main.cpp +++ b/tests/main.cpp @@ -23,9 +23,9 @@ #include "metatypes_env.h" #include "resources_env.h" -#ifndef Q_WS_X11 +#if defined(Q_OS_WIN32) || defined(Q_OS_DARWIN) # include - Q_IMPORT_PLUGIN(qsqlite) + Q_IMPORT_PLUGIN(QSQLiteDriverPlugin) #endif int main(int argc, char** argv) { diff --git a/tests/mock_networkaccessmanager.cpp b/tests/mock_networkaccessmanager.cpp index 64d6d5f68..bb0224d39 100644 --- a/tests/mock_networkaccessmanager.cpp +++ b/tests/mock_networkaccessmanager.cpp @@ -18,6 +18,7 @@ #include "mock_networkaccessmanager.h" #include +#include #include using std::min; @@ -44,10 +45,11 @@ class RequestForUrlMatcher : public MatcherInterface { return false; } + QUrlQuery url_query(url); for (QMap::const_iterator it = expected_params_.constBegin(); it != expected_params_.constEnd(); ++it) { - if (!url.hasQueryItem(it.key()) || - url.queryItemValue(it.key()) != it.value()) { + if (!url_query.hasQueryItem(it.key()) || + url_query.queryItemValue(it.key()) != it.value()) { return false; } } diff --git a/tests/scopedtransaction_test.cpp b/tests/scopedtransaction_test.cpp index 2a7fa98da..3261574b9 100644 --- a/tests/scopedtransaction_test.cpp +++ b/tests/scopedtransaction_test.cpp @@ -63,13 +63,15 @@ TEST_F(ScopedTransactionTest, RollbackOnDtor) { ScopedTransaction t(&database_); database_.exec("INSERT INTO foo (bar) VALUES (42)"); - QSqlQuery q("SELECT * FROM foo", database_); + QSqlQuery q(database_); + q.prepare("SELECT * FROM foo"); ASSERT_TRUE(q.exec()); ASSERT_TRUE(q.next()); EXPECT_EQ(42, q.value(0).toInt()); } - QSqlQuery q("SELECT * FROM foo", database_); + QSqlQuery q(database_); + q.prepare("SELECT * FROM foo"); ASSERT_TRUE(q.exec()); ASSERT_FALSE(q.next()); } @@ -83,7 +85,8 @@ TEST_F(ScopedTransactionTest, Commit) { t.Commit(); } - QSqlQuery q("SELECT * FROM foo", database_); + QSqlQuery q(database_); + q.prepare("SELECT * FROM foo"); ASSERT_TRUE(q.exec()); ASSERT_TRUE(q.next()); EXPECT_EQ(42, q.value(0).toInt()); diff --git a/tests/zeroconf_test.cpp b/tests/zeroconf_test.cpp index 3448f8221..973953e25 100644 --- a/tests/zeroconf_test.cpp +++ b/tests/zeroconf_test.cpp @@ -21,7 +21,7 @@ static const char kLongMultiByteString[] = TEST(ZeroconfTest, TruncatesAscii) { QByteArray truncated = Zeroconf::TruncateName( - QString::fromAscii(k64CharAscii)); + QString::fromLatin1(k64CharAscii)); EXPECT_EQ(63, truncated.size()); EXPECT_TRUE(truncated.endsWith('\0')); } @@ -34,7 +34,7 @@ TEST(ZeroconfTest, DoesNotTruncateShortMultiByteUTF8) { TEST(ZeroconfTest, TruncatesLongMultiByteUTF8) { QByteArray truncated = Zeroconf::TruncateName( - QString::fromAscii(kLongMultiByteString)); + QString::fromLatin1(kLongMultiByteString)); EXPECT_LE(63, truncated.size()); EXPECT_TRUE(truncated.endsWith('\0')); }