diff options
73 files changed, 1270 insertions, 420 deletions
diff --git a/.gitignore b/.gitignore index 6c1df4de4..4ad955533 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,31 @@ +# Ignore the following files +.vscode +*~ +*.[oa] +*.diff +*.kate-swp +*.kdev4 +.kdev_include_paths +*.kdevelop.pcs +*.moc +*.moc.cpp +*.orig +*.user +.*.swp +.swp.* +Doxyfile +Makefile +avail +random_seed +/build*/ +CMakeLists.txt.user* +.clang-format +/compile_commands.json +.clangd +.idea +/cmake-build* +.cache apidocs doxygen.log -CMakeLists.txt.user .directory -*.kdev4 -/build*/ .cmake/ diff --git a/CMakeLists.txt b/CMakeLists.txt index e33f57e91..11ab06dda 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,13 +2,13 @@ cmake_minimum_required(VERSION 3.0) # KDE Application Version, managed by release script set (RELEASE_SERVICE_VERSION_MAJOR "21") -set (RELEASE_SERVICE_VERSION_MINOR "04") -set (RELEASE_SERVICE_VERSION_MICRO "2") +set (RELEASE_SERVICE_VERSION_MINOR "07") +set (RELEASE_SERVICE_VERSION_MICRO "70") set (RELEASE_SERVICE_VERSION "${RELEASE_SERVICE_VERSION_MAJOR}.${RELEASE_SERVICE_VERSION_MINOR}.${RELEASE_SERVICE_VERSION_MICRO}") project(Dolphin VERSION ${RELEASE_SERVICE_VERSION}) set(QT_MIN_VERSION "5.14.0") -set(KF5_MIN_VERSION "5.77.0") +set(KF5_MIN_VERSION "5.81.0") set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) @@ -53,7 +53,6 @@ find_package(Qt5 ${QT_MIN_VERSION} CONFIG REQUIRED COMPONENTS find_package(KF5 ${KF5_MIN_VERSION} REQUIRED COMPONENTS DocTools - Init KCMUtils NewStuff CoreAddons diff --git a/CMakePresets.json b/CMakePresets.json new file mode 100644 index 000000000..22e3de72e --- /dev/null +++ b/CMakePresets.json @@ -0,0 +1,83 @@ +{ + "version": 2, + "configurePresets": [ + { + "name": "dev", + "displayName": "Build as debug", + "generator": "Ninja", + "binaryDir": "${sourceDir}/build", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Debug", + "CMAKE_EXPORT_COMPILE_COMMANDS": "ON" + } + }, + { + "name": "asan", + "displayName": "Build with Asan support.", + "generator": "Ninja", + "binaryDir": "${sourceDir}/build-asan", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Debug", + "ECM_ENABLE_SANITIZERS" : "'address;undefined'", + "CMAKE_EXPORT_COMPILE_COMMANDS": "ON" + } + }, + { + "name": "unity", + "displayName": "Build with CMake unity support.", + "generator": "Ninja", + "binaryDir": "${sourceDir}/build-unity", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Debug", + "CMAKE_UNITY_BUILD": "ON", + "CMAKE_EXPORT_COMPILE_COMMANDS": "ON" + } + }, + { + "name": "release", + "displayName": "Build as release mode.", + "generator": "Ninja", + "binaryDir": "${sourceDir}/build-release", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Release" + } + }, + { + "name": "profile", + "displayName": "profile", + "generator": "Ninja", + "binaryDir": "${sourceDir}/build-profile", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "RelWithDebInfo", + "CMAKE_EXPORT_COMPILE_COMMANDS": "ON" + } + }, + { + "name": "clazy", + "displayName": "clazy", + "generator": "Ninja", + "binaryDir": "${sourceDir}/build-clazy", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Debug" + }, + "environment": { + "CXX": "clazy", + "CCACHE_DISABLE": "ON" + } + } + ], + "buildPresets": [ + { + "name": "dev", + "configurePreset": "dev" + }, + { + "name": "clazy", + "configurePreset": "clazy", + "environment": { + "CLAZY_CHECKS" : "level0,level1,detaching-member,ifndef-define-typo,isempty-vs-count,qrequiredresult-candidates,reserve-candidates,signal-with-return-value,unneeded-cast,function-args-by-ref,function-args-by-value,returning-void-expression,no-ctor-missing-parent-argument,isempty-vs-count,qhash-with-char-pointer-key,raw-environment-function,qproperty-type-mismatch,old-style-connect,qstring-allocations,container-inside-loop,heap-allocated-small-trivial-type,inefficient-qlist,qstring-varargs,level2,detaching-member,heap-allocated-small-trivial-type,isempty-vs-count,qstring-varargs,qvariant-template-instantiation,raw-environment-function,reserve-candidates,signal-with-return-value,thread-with-slots,no-ctor-missing-parent-argument,no-missing-typeinfo", + "CCACHE_DISABLE" : "ON" + } + } + ] +} diff --git a/LICENSES/LGPL-2.1-only.txt b/LICENSES/LGPL-2.1-only.txt new file mode 100644 index 000000000..c9aa53018 --- /dev/null +++ b/LICENSES/LGPL-2.1-only.txt @@ -0,0 +1,175 @@ +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. + +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. + + one line to give the library's name and an idea of what it does. + Copyright (C) year name of author + + 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. + +signature of Ty Coon, 1 April 1990 +Ty Coon, President of Vice +That's all there is to it! diff --git a/LICENSES/LGPL-3.0-only.txt b/LICENSES/LGPL-3.0-only.txt new file mode 100644 index 000000000..c9287dd36 --- /dev/null +++ b/LICENSES/LGPL-3.0-only.txt @@ -0,0 +1,71 @@ +GNU LESSER GENERAL PUBLIC LICENSE +Version 3, 29 June 2007 + +Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> + +Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. + +This version of the GNU Lesser General Public License incorporates the terms and conditions of version 3 of the GNU General Public License, supplemented by the additional permissions listed below. + +0. Additional Definitions. + +As used herein, "this License" refers to version 3 of the GNU Lesser General Public License, and the "GNU GPL" refers to version 3 of the GNU General Public License. + +"The Library" refers to a covered work governed by this License, other than an Application or a Combined Work as defined below. + +An "Application" is any work that makes use of an interface provided by the Library, but which is not otherwise based on the Library. Defining a subclass of a class defined by the Library is deemed a mode of using an interface provided by the Library. + +A "Combined Work" is a work produced by combining or linking an Application with the Library. The particular version of the Library with which the Combined Work was made is also called the "Linked Version". + +The "Minimal Corresponding Source" for a Combined Work means the Corresponding Source for the Combined Work, excluding any source code for portions of the Combined Work that, considered in isolation, are based on the Application, and not on the Linked Version. + +The "Corresponding Application Code" for a Combined Work means the object code and/or source code for the Application, including any data and utility programs needed for reproducing the Combined Work from the Application, but excluding the System Libraries of the Combined Work. + +1. Exception to Section 3 of the GNU GPL. +You may convey a covered work under sections 3 and 4 of this License without being bound by section 3 of the GNU GPL. + +2. Conveying Modified Versions. +If you modify a copy of the Library, and, in your modifications, a facility refers to a function or data to be supplied by an Application that uses the facility (other than as an argument passed when the facility is invoked), then you may convey a copy of the modified version: + + a) under this License, provided that you make a good faith effort to ensure that, in the event an Application does not supply the function or data, the facility still operates, and performs whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of this License applicable to that copy. + +3. Object Code Incorporating Material from Library Header Files. +The object code form of an Application may incorporate material from a header file that is part of the Library. You may convey such object code under terms of your choice, provided that, if the incorporated material is not limited to numerical parameters, data structure layouts and accessors, or small macros, inline functions and templates (ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the Library is used in it and that the Library and its use are covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license document. + +4. Combined Works. +You may convey a Combined Work under terms of your choice that, taken together, effectively do not restrict modification of the portions of the Library contained in the Combined Work and reverse engineering for debugging such modifications, if you also do each of the following: + + a) Give prominent notice with each copy of the Combined Work that the Library is used in it and that the Library and its use are covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license document. + + c) For a Combined Work that displays copyright notices during execution, include the copyright notice for the Library among these notices, as well as a reference directing the user to the copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this License, and the Corresponding Application Code in a form suitable for, and under terms that permit, the user to recombine or relink the Application with a modified version of the Linked Version to produce a modified Combined Work, in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (a) uses at run time a copy of the Library already present on the user's computer system, and (b) will operate properly with a modified version of the Library that is interface-compatible with the Linked Version. + + e) Provide Installation Information, but only if you would otherwise be required to provide such information under section 6 of the GNU GPL, and only to the extent that such information is necessary to install and execute a modified version of the Combined Work produced by recombining or relinking the Application with a modified version of the Linked Version. (If you use option 4d0, the Installation Information must accompany the Minimal Corresponding Source and Corresponding Application Code. If you use option 4d1, you must provide the Installation Information in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source.) + +5. Combined Libraries. +You may place library facilities that are a work based on the Library side by side in a single library together with other library facilities that are not Applications and are not covered by this License, and convey such a combined library under terms of your choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities, conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. + +6. Revised Versions of the GNU Lesser General Public License. +The Free Software Foundation may publish revised and/or new versions of the GNU Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library as you received it specifies that a certain numbered version of the GNU Lesser General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that published version or of any later version published by the Free Software Foundation. If the Library as you received it does not specify a version number of the GNU Lesser General Public License, you may choose any version of the GNU Lesser General Public License ever published by the Free Software Foundation. + +If the Library as you received it specifies that a proxy can decide whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is permanent authorization for you to choose that version for the Library. diff --git a/LICENSES/LicenseRef-KDE-Accepted-LGPL.txt b/LICENSES/LicenseRef-KDE-Accepted-LGPL.txt new file mode 100644 index 000000000..232b3c5da --- /dev/null +++ b/LICENSES/LicenseRef-KDE-Accepted-LGPL.txt @@ -0,0 +1,12 @@ +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 3 of the license or (at your option) any later version +that is accepted by the membership of KDE e.V. (or its successor +approved by the membership of KDE e.V.), which shall act as a +proxy as defined in Section 6 of version 3 of the license. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. diff --git a/doc/index.docbook b/doc/index.docbook index 79989c762..cb99abaa9 100644 --- a/doc/index.docbook +++ b/doc/index.docbook @@ -70,8 +70,8 @@ <legalnotice>&FDLNotice;</legalnotice> -<date>2020-12-29</date> -<releaseinfo>Applications 21.04</releaseinfo> +<date>2021-04-08</date> +<releaseinfo>Applications 21.08</releaseinfo> <abstract> <para> @@ -853,7 +853,10 @@ bar. This provides a very comfortable way for the user to shrink the number of search results.</para> <para>To start a search select one or more file types (<guilabel>Documents</guilabel>, <guilabel>Audio</guilabel>, <guilabel>Video</guilabel>, <guilabel>Images</guilabel>), - a time period and rating<!--FIXME readd when again implemented: and tag, if you have defined any.--></para> +a time period, rating, and tag, if you have defined any via +<userinput>tag:<replaceable>foo</replaceable></userinput> in the input box.</para> + + <para>It is possible to clear selection using the <guibutton>Clear Selection</guibutton> button.</para> <para>Alternatively you can use these options in the <guilabel>Places</guilabel> panel together with the <guilabel>Filter</guilabel> bar to find files using Baloo or limit @@ -862,11 +865,10 @@ the search to files matching the filter expression.</para> <para>Use the Save icon to save a search to the <guilabel>Search For</guilabel> section in the <guilabel>Places</guilabel> panel to quickly access it again in the future. </para> -<!--FIXME 16.12 -https://git.reviewboard.kde.org/r/123883/ -Add prototype of a "More search tools..." button ---> +<para> +Use the <guilabel>More Search Tools</guilabel> drop-down list to select other search tools than Baloo. +</para> </sect2> <sect2 id="mounting-storage-media"> @@ -1107,11 +1109,15 @@ the status bar is wide enough: <itemizedlist> <listitem><para> -A <guilabel>zoom slider</guilabel> which can be used to change the icon size quickly. +The <guilabel>Show status bar</guilabel> item can be used for toggling status bar visibility. +</para></listitem> + +<listitem><para> +The <guilabel>Show zoom slider</guilabel> item allows switching visibility of the icon size widget. </para></listitem> <listitem><para> -A bar that shows how much space is free on the current drive. +The <guilabel>Show space information</guilabel> item can be used to switch on and off a bar that shows how much space is free on the current drive. </para></listitem> </itemizedlist> @@ -1360,7 +1366,7 @@ several levels deeper in the folder hierarchy. </sect2> <sect2 id="preferences-dialog-context-menu"> -<title>Context Menu</title> +<title>Services</title> <para> This group offers a selection of services that can be shown in the @@ -1369,15 +1375,15 @@ appears when clicking a file or folder with the &RMB;. </para> <screenshot> -<screeninfo>Screenshot of the Context Menu settings in &dolphin;'s preferences dialog</screeninfo> +<screeninfo>Screenshot of the Services Menu settings in &dolphin;'s preferences dialog</screeninfo> <mediaobject> <imageobject> <imagedata fileref="preferences-context-menu.png" format="PNG"/> </imageobject> <textobject> -<phrase>Context Menu Settings.</phrase> +<phrase>Services Settings.</phrase> </textobject> -<caption><para>Context Menu Settings in &dolphin;'s Preferences Dialog.</para></caption> +<caption><para>Services Settings in &dolphin;'s Preferences Dialog.</para></caption> </mediaobject> </screenshot> @@ -1445,6 +1451,37 @@ largest files can be deleted automatically. </sect2> +<sect2 id="preferences-user-feedback"> +<title>Trash</title> + +<para> +This group contains settings which control your contributing information on the &dolphin; usage to its developers. + +<screenshot> +<screeninfo>Screenshot of the User Feedback settings in &dolphin;'s preferences dialog</screeninfo> +<mediaobject> +<imageobject> +<imagedata fileref="preferences-user-feedback.png" format="PNG"/> +</imageobject> +<textobject> +<phrase>User Feedback Settings.</phrase> +</textobject> +<caption><para>User Feedback Settings in &dolphin;'s Preferences Dialog.</para></caption> +</mediaobject> +</screenshot> + +<itemizedlist> + +<listitem><para> +You can contribute some feedback on &dolphin; if you wish. Use sliders to configure your level of participation. +</para></listitem> + +</itemizedlist> + +</para> + +</sect2> + </sect1> <!-- begin copy to konqueror filemanager.docbook --> <sect1 id="view-properties"> diff --git a/doc/preferences-context-menu.png b/doc/preferences-context-menu.png Binary files differindex 5b42fa394..16c46d913 100644 --- a/doc/preferences-context-menu.png +++ b/doc/preferences-context-menu.png diff --git a/doc/preferences-general-behavior.png b/doc/preferences-general-behavior.png Binary files differindex f3f68c4f0..e26d453d2 100644 --- a/doc/preferences-general-behavior.png +++ b/doc/preferences-general-behavior.png diff --git a/doc/preferences-navigation.png b/doc/preferences-navigation.png Binary files differindex dd74d813c..59f9605dc 100644 --- a/doc/preferences-navigation.png +++ b/doc/preferences-navigation.png diff --git a/doc/preferences-startup.png b/doc/preferences-startup.png Binary files differindex 192efe193..7ac228059 100644 --- a/doc/preferences-startup.png +++ b/doc/preferences-startup.png diff --git a/doc/preferences-trash.png b/doc/preferences-trash.png Binary files differindex d9e0a1513..bc4c92a62 100644 --- a/doc/preferences-trash.png +++ b/doc/preferences-trash.png diff --git a/doc/preferences-user-feedback.png b/doc/preferences-user-feedback.png Binary files differnew file mode 100644 index 000000000..5a2d45678 --- /dev/null +++ b/doc/preferences-user-feedback.png diff --git a/doc/preferences-viewmodes-icons.png b/doc/preferences-viewmodes-icons.png Binary files differindex b2a219ab4..ff5dd0b97 100644 --- a/doc/preferences-viewmodes-icons.png +++ b/doc/preferences-viewmodes-icons.png diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 3f3ecfff2..46dbaa152 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -21,11 +21,12 @@ remove_definitions( ########################################## -set(dolphinvcs_LIB_SRCS +add_library(dolphinvcs SHARED) + +target_sources(dolphinvcs PRIVATE views/versioncontrol/kversioncontrolplugin.cpp ) -add_library(dolphinvcs ${dolphinvcs_LIB_SRCS}) generate_export_header(dolphinvcs BASE_NAME dolphinvcs) target_link_libraries( @@ -34,7 +35,7 @@ target_link_libraries( ) set_target_properties(dolphinvcs PROPERTIES - VERSION ${DOLPHINVCS_VERSION_STRING} + VERSION ${DOLPHINVCS_VERSION} SOVERSION ${DOLPHINVCS_SOVERSION} EXPORT_NAME DolphinVcs ) @@ -55,7 +56,9 @@ install(FILES ${dolphinvcs_LIB_HEADERS} DESTINATION "${KDE_INSTALL_INCLUDEDIR}/D ########### next target ############### -set(dolphinprivate_LIB_SRCS +add_library(dolphinprivate SHARED) + +target_sources(dolphinprivate PRIVATE kitemviews/kfileitemlistview.cpp kitemviews/kfileitemlistwidget.cpp kitemviews/kfileitemmodel.cpp @@ -114,19 +117,23 @@ set(dolphinprivate_LIB_SRCS dolphinnewfilemenu.cpp ) -ecm_qt_declare_logging_category(dolphinprivate_LIB_SRCS HEADER dolphindebug.h IDENTIFIER DolphinDebug CATEGORY_NAME org.kde.dolphin - DESCRIPTION "dolphin" EXPORT DOLPHIN) +ecm_qt_declare_logging_category(dolphinprivate + HEADER dolphindebug.h + IDENTIFIER DolphinDebug + CATEGORY_NAME org.kde.dolphin + DESCRIPTION "dolphin" + EXPORT DOLPHIN +) if(HAVE_BALOO) - set(dolphinprivate_LIB_SRCS - ${dolphinprivate_LIB_SRCS} + target_sources(dolphinprivate PRIVATE views/tooltips/dolphinfilemetadatawidget.cpp views/tooltips/tooltipmanager.cpp kitemviews/private/kbaloorolesprovider.cpp ) endif() -kconfig_add_kcfg_files(dolphinprivate_LIB_SRCS GENERATE_MOC +kconfig_add_kcfg_files(dolphinprivate settings/dolphin_compactmodesettings.kcfgc settings/dolphin_directoryviewpropertysettings.kcfgc settings/dolphin_detailsmodesettings.kcfgc @@ -136,7 +143,6 @@ kconfig_add_kcfg_files(dolphinprivate_LIB_SRCS GENERATE_MOC settings/dolphin_versioncontrolsettings.kcfgc ) -add_library(dolphinprivate ${dolphinprivate_LIB_SRCS}) generate_export_header(dolphinprivate BASE_NAME dolphin) target_link_libraries( @@ -167,7 +173,7 @@ if(HAVE_BALOO) endif() set_target_properties(dolphinprivate PROPERTIES - VERSION ${DOLPHINPRIVATE_VERSION_STRING} + VERSION ${DOLPHINPRIVATE_VERSION} SOVERSION ${DOLPHINPRIVATE_SOVERSION} ) @@ -177,15 +183,16 @@ install(FILES ${CMAKE_CURRENT_BINARY_DIR}/dolphin_export.h DESTINATION ${KDE_INS ########################################## configure_file(dolphinpart.desktop.in ${CMAKE_CURRENT_BINARY_DIR}/dolphinpart.desktop @ONLY) -set(dolphinpart_SRCS - dolphinpart.cpp - dolphinpart_ext.cpp - dolphindebug.cpp -) +add_library(dolphinpart MODULE) -qt5_add_resources(dolphinpart_SRCS dolphinpart.qrc) +target_sources(dolphinpart PRIVATE + dolphinpart.cpp + dolphinpart_ext.cpp + dolphindebug.cpp + + dolphinpart.qrc +) -add_library(dolphinpart MODULE ${dolphinpart_SRCS}) kcoreaddons_desktop_to_json(dolphinpart ${CMAKE_CURRENT_BINARY_DIR}/dolphinpart.desktop) target_link_libraries(dolphinpart @@ -198,7 +205,9 @@ install(FILES ${CMAKE_CURRENT_BINARY_DIR}/dolphinpart.desktop DESTINATION ${KDE_ ########################################## -set(dolphinstatic_SRCS +add_library(dolphinstatic STATIC) + +target_sources(dolphinstatic PRIVATE dolphinbookmarkhandler.cpp dolphindockwidget.cpp dolphinmainwindow.cpp @@ -255,11 +264,11 @@ set(dolphinstatic_SRCS views/zoomlevelinfo.cpp dolphindebug.cpp global.cpp + dolphin.qrc ) if(HAVE_BALOO) - set(dolphinstatic_SRCS - ${dolphinstatic_SRCS} + target_sources(dolphinstatic PRIVATE panels/information/informationpanel.cpp panels/information/informationpanelcontent.cpp panels/information/pixmapviewer.cpp @@ -268,8 +277,7 @@ if(HAVE_BALOO) endif() if(HAVE_KUSERFEEDBACK) - set(dolphinstatic_SRCS - ${dolphinstatic_SRCS} + target_sources(dolphinstatic PRIVATE userfeedback/dolphinfeedbackprovider.cpp userfeedback/settingsdatasource.cpp userfeedback/placesdatasource.cpp @@ -277,27 +285,29 @@ if(HAVE_KUSERFEEDBACK) ) endif() -kconfig_add_kcfg_files(dolphinstatic_SRCS GENERATE_MOC +kconfig_add_kcfg_files(dolphinstatic panels/folders/dolphin_folderspanelsettings.kcfgc panels/information/dolphin_informationpanelsettings.kcfgc panels/places/dolphin_placespanelsettings.kcfgc settings/dolphin_compactmodesettings.kcfgc settings/dolphin_detailsmodesettings.kcfgc - settings/dolphin_generalsettings.kcfgc settings/dolphin_contextmenusettings.kcfgc settings/dolphin_iconsmodesettings.kcfgc search/dolphin_searchsettings.kcfgc settings/dolphin_versioncontrolsettings.kcfgc ) - -qt5_add_resources(dolphinstatic_SRCS dolphin.qrc) +kconfig_add_kcfg_files(dolphinstatic GENERATE_MOC + settings/dolphin_generalsettings.kcfgc +) qt5_generate_dbus_interface(${CMAKE_CURRENT_SOURCE_DIR}/dolphinmainwindow.h org.kde.DolphinMainWindow.xml) -qt5_add_dbus_adaptor(dolphinstatic_SRCS ${CMAKE_CURRENT_BINARY_DIR}/org.kde.DolphinMainWindow.xml dolphinmainwindow.h DolphinMainWindow) -qt5_add_dbus_interface(dolphinstatic_SRCS ${CMAKE_CURRENT_BINARY_DIR}/org.kde.DolphinMainWindow.xml dolphinmainwindowinterface) -qt5_add_dbus_interface(dolphinstatic_SRCS panels/terminal/org.kde.KIOFuse.VFS.xml kiofuse_interface) +qt5_add_dbus_adaptor(dolphin_dbus_SRCS ${CMAKE_CURRENT_BINARY_DIR}/org.kde.DolphinMainWindow.xml dolphinmainwindow.h DolphinMainWindow) +qt5_add_dbus_interface(dolphin_dbus_SRCS ${CMAKE_CURRENT_BINARY_DIR}/org.kde.DolphinMainWindow.xml dolphinmainwindowinterface) +qt5_add_dbus_interface(dolphin_dbus_SRCS panels/terminal/org.kde.KIOFuse.VFS.xml kiofuse_interface) -add_library(dolphinstatic STATIC ${dolphinstatic_SRCS}) +target_sources(dolphinstatic PRIVATE + ${dolphin_dbus_SRCS} +) target_include_directories(dolphinstatic SYSTEM PRIVATE ${PHONON_INCLUDES}) target_link_libraries(dolphinstatic @@ -324,21 +334,24 @@ if (HAVE_KUSERFEEDBACK) ) endif() -set(dolphin_SRCS +add_executable(dolphin) + +target_sources(dolphin PRIVATE dbusinterface.cpp main.cpp ) # Sets the icon on Windows and OSX file(GLOB ICONS_SRCS "${CMAKE_CURRENT_SOURCE_DIR}/icons/*system-file-manager.png") -ecm_add_app_icon(dolphin_SRCS ICONS ${ICONS_SRCS}) - -kf5_add_kdeinit_executable(dolphin ${dolphin_SRCS}) - +ecm_add_app_icon(dolphin_APPICON_SRCS ICONS ${ICONS_SRCS}) +# ecm_add_app_icon 5.83 will take target as arg, use that once it is min req. +target_sources(dolphin PRIVATE + ${dolphin_APPICON_SRCS} +) -target_link_libraries(kdeinit_dolphin PUBLIC - dolphinprivate +target_link_libraries(dolphin PRIVATE + dolphinprivate dolphinstatic KF5::Crash ) @@ -346,60 +359,58 @@ target_link_libraries(kdeinit_dolphin PUBLIC include(DbusInterfaceMacros) generate_and_install_dbus_interface( - kdeinit_dolphin + dolphin dbusinterface.h org.freedesktop.FileManager1.xml OPTIONS -a ) -install(TARGETS kdeinit_dolphin ${KDE_INSTALL_TARGETS_DEFAULT_ARGS}) install(TARGETS dolphin ${KDE_INSTALL_TARGETS_DEFAULT_ARGS}) ########################################## -set(kcm_dolphinviewmodes_PART_SRCS - settings/kcm/kcmdolphinviewmodes.cpp - settings/viewmodes/dolphinfontrequester.cpp - settings/viewmodes/viewmodesettings.cpp - settings/viewmodes/viewsettingstab.cpp - views/zoomlevelinfo.cpp) - -set(kcm_dolphinnavigation_PART_SRCS - settings/kcm/kcmdolphinnavigation.cpp - settings/navigation/navigationsettingspage.cpp - settings/settingspagebase.cpp) +if(NOT WIN32) + # The settings are still accessible from the hamburger menu + add_library(kcm_dolphinviewmodes MODULE) + add_library(kcm_dolphinnavigation MODULE) + add_library(kcm_dolphingeneral MODULE) -set(kcm_dolphingeneral_PART_SRCS - settings/kcm/kcmdolphingeneral.cpp - settings/general/behaviorsettingspage.cpp - settings/general/previewssettingspage.cpp - settings/general/configurepreviewplugindialog.cpp - settings/general/confirmationssettingspage.cpp - settings/settingspagebase.cpp - settings/serviceitemdelegate.cpp - settings/servicemodel.cpp) + target_sources(kcm_dolphinviewmodes PRIVATE + settings/kcm/kcmdolphinviewmodes.cpp + settings/viewmodes/dolphinfontrequester.cpp + settings/viewmodes/viewmodesettings.cpp + settings/viewmodes/viewsettingstab.cpp + views/zoomlevelinfo.cpp) -kconfig_add_kcfg_files(kcm_dolphinviewmodes_PART_SRCS - settings/dolphin_compactmodesettings.kcfgc - settings/dolphin_directoryviewpropertysettings.kcfgc - settings/dolphin_detailsmodesettings.kcfgc - settings/dolphin_iconsmodesettings.kcfgc - settings/dolphin_generalsettings.kcfgc - settings/dolphin_versioncontrolsettings.kcfgc -) + target_sources(kcm_dolphinnavigation PRIVATE + settings/kcm/kcmdolphinnavigation.cpp + settings/navigation/navigationsettingspage.cpp + settings/settingspagebase.cpp) -kconfig_add_kcfg_files(kcm_dolphinnavigation_PART_SRCS - settings/dolphin_generalsettings.kcfgc) + target_sources(kcm_dolphingeneral PRIVATE + settings/kcm/kcmdolphingeneral.cpp + settings/general/behaviorsettingspage.cpp + settings/general/previewssettingspage.cpp + settings/general/configurepreviewplugindialog.cpp + settings/general/confirmationssettingspage.cpp + settings/settingspagebase.cpp + settings/serviceitemdelegate.cpp + settings/servicemodel.cpp) -kconfig_add_kcfg_files(kcm_dolphingeneral_PART_SRCS - settings/dolphin_generalsettings.kcfgc) + kconfig_add_kcfg_files(kcm_dolphinviewmodes + settings/dolphin_compactmodesettings.kcfgc + settings/dolphin_directoryviewpropertysettings.kcfgc + settings/dolphin_detailsmodesettings.kcfgc + settings/dolphin_iconsmodesettings.kcfgc + settings/dolphin_generalsettings.kcfgc + settings/dolphin_versioncontrolsettings.kcfgc + ) + kconfig_add_kcfg_files(kcm_dolphinnavigation + settings/dolphin_generalsettings.kcfgc) -if(NOT WIN32) - # The settings are still accessible from the hamburger menu - add_library(kcm_dolphinviewmodes MODULE ${kcm_dolphinviewmodes_PART_SRCS}) - add_library(kcm_dolphinnavigation MODULE ${kcm_dolphinnavigation_PART_SRCS}) - add_library(kcm_dolphingeneral MODULE ${kcm_dolphingeneral_PART_SRCS}) + kconfig_add_kcfg_files(kcm_dolphingeneral + settings/dolphin_generalsettings.kcfgc) target_link_libraries(kcm_dolphinviewmodes dolphinprivate) target_link_libraries(kcm_dolphinnavigation dolphinprivate) diff --git a/src/dbusinterface.cpp b/src/dbusinterface.cpp index cf1ad53ad..7e453f72a 100644 --- a/src/dbusinterface.cpp +++ b/src/dbusinterface.cpp @@ -59,6 +59,18 @@ void DBusInterface::ShowItemProperties(const QStringList& uriList, const QString } } +void DBusInterface::SortOrderForUrl(const QString &url, QString &role, QString &order) +{ + QUrl qurl(url); + auto sort = Dolphin::sortOrderForUrl(qurl); + role = sort.first; + if (sort.second == Qt::AscendingOrder) { + order = QStringLiteral("ascending"); + } else { + order = QStringLiteral("descending"); + } +} + void DBusInterface::setAsDaemon() { m_isDaemon = true; diff --git a/src/dbusinterface.h b/src/dbusinterface.h index 9b183384d..66659e976 100644 --- a/src/dbusinterface.h +++ b/src/dbusinterface.h @@ -20,6 +20,8 @@ public: Q_SCRIPTABLE void ShowItems(const QStringList& uriList, const QString& startUpId); Q_SCRIPTABLE void ShowItemProperties(const QStringList& uriList, const QString& startUpId); + Q_SCRIPTABLE void SortOrderForUrl(const QString &url, QString &role, QString &order); + /** * Set whether this interface has been created by dolphin --daemon. */ diff --git a/src/dolphinbookmarkhandler.h b/src/dolphinbookmarkhandler.h index ac86f950c..a75090500 100644 --- a/src/dolphinbookmarkhandler.h +++ b/src/dolphinbookmarkhandler.h @@ -14,7 +14,6 @@ class DolphinMainWindow; class DolphinViewContainer; class KActionCollection; -class KBookmarkManager; class KBookmarkMenu; class QMenu; diff --git a/src/dolphincontextmenu.cpp b/src/dolphincontextmenu.cpp index 2b216ce03..47f0cdd40 100644 --- a/src/dolphincontextmenu.cpp +++ b/src/dolphincontextmenu.cpp @@ -22,6 +22,7 @@ #include <KActionCollection> #include <KFileItemActions> #include <KFileItemListProperties> +#include <KHamburgerMenu> #include <KIO/EmptyTrashJob> #include <KIO/JobUiDelegate> #include <KIO/Paste> @@ -63,7 +64,10 @@ DolphinContextMenu::DolphinContextMenu(DolphinMainWindow* parent, const DolphinView* view = m_mainWindow->activeViewContainer()->view(); m_selectedItems = view->selectedItems(); - QApplication::instance()->installEventFilter(this); + installEventFilter(this); + + static_cast<KHamburgerMenu *>(m_mainWindow->actionCollection()-> + action(QStringLiteral("hamburger_menu")))->addToMenu(this); } DolphinContextMenu::~DolphinContextMenu() @@ -144,8 +148,6 @@ void DolphinContextMenu::openTrashContextMenu() QAction* propertiesAction = m_mainWindow->actionCollection()->action(QStringLiteral("properties")); addAction(propertiesAction); - addShowMenuBarAction(); - if (exec(m_pos) == emptyTrashAction) { Trash::empty(m_mainWindow); } @@ -204,7 +206,7 @@ void DolphinContextMenu::addDirectoryItemContextMenu(KFileItemActions &fileItemA QMenu* menu = newFileMenu->menu(); menu->setTitle(i18nc("@title:menu Create new folder, file, link, etc.", "Create New")); - menu->setIcon(QIcon::fromTheme(QStringLiteral("document-new"))); + menu->setIcon(QIcon::fromTheme(QStringLiteral("list-add"))); addMenu(menu); addSeparator(); @@ -356,8 +358,6 @@ void DolphinContextMenu::openViewportContextMenu() QAction* propertiesAction = m_mainWindow->actionCollection()->action(QStringLiteral("properties")); addAction(propertiesAction); - addShowMenuBarAction(); - exec(m_pos); } @@ -418,16 +418,6 @@ void DolphinContextMenu::insertDefaultItemActions(const KFileItemListProperties& } } -void DolphinContextMenu::addShowMenuBarAction() -{ - const KActionCollection* ac = m_mainWindow->actionCollection(); - QAction* showMenuBar = ac->action(KStandardAction::name(KStandardAction::ShowMenubar)); - if (!m_mainWindow->menuBar()->isVisible() && !m_mainWindow->toolBar()->isVisible()) { - addSeparator(); - addAction(showMenuBar); - } -} - bool DolphinContextMenu::placeExists(const QUrl& url) const { const KFilePlacesModel* placesModel = DolphinPlacesModelSingleton::instance().placesModel(); @@ -503,7 +493,7 @@ void DolphinContextMenu::addAdditionalActions(KFileItemActions &fileItemActions, addSeparator(); QList<QAction *> additionalActions; - if (props.isDirectory() && props.isLocal()) { + if (props.isDirectory() && props.isLocal() && ContextMenuSettings::showOpenTerminal()) { additionalActions << m_mainWindow->actionCollection()->action(QStringLiteral("open_terminal")); } fileItemActions.addActionsTo(this, KFileItemActions::MenuActionSource::All, additionalActions); diff --git a/src/dolphinmainwindow.cpp b/src/dolphinmainwindow.cpp index 4297321fc..737856b23 100644 --- a/src/dolphinmainwindow.cpp +++ b/src/dolphinmainwindow.cpp @@ -24,7 +24,6 @@ #include "panels/folders/folderspanel.h" #include "panels/places/placesitemmodel.h" #include "panels/places/placespanel.h" -#include "panels/information/informationpanel.h" #include "panels/terminal/terminalpanel.h" #include "settings/dolphinsettingsdialog.h" #include "statusbar/dolphinstatusbar.h" @@ -64,12 +63,14 @@ #include <KUrlComboBox> #include <KUrlNavigator> #include <KWindowSystem> +#include <KXMLGUIFactory> #include <QApplication> #include <QClipboard> #include <QCloseEvent> #include <QDesktopServices> #include <QDialog> +#include <QDomDocument> #include <QFileInfo> #include <QLineEdit> #include <QMenuBar> @@ -83,7 +84,7 @@ namespace { // Used for GeneralSettings::version() to determine whether // an updated version of Dolphin is running. - const int CurrentDolphinVersion = 200; + const int CurrentDolphinVersion = 201; // The maximum number of entries in the back/forward popup menu const int MaxNumberOfNavigationentries = 12; // The maximum number of "Activate Tab" shortcuts @@ -177,15 +178,21 @@ DolphinMainWindow::DolphinMainWindow() : if (firstRun) { menuBar()->setVisible(false); - // Assure a proper default size if Dolphin runs the first time - resize(750, 500); } const bool showMenu = !menuBar()->isHidden(); QAction* showMenuBarAction = actionCollection()->action(KStandardAction::name(KStandardAction::ShowMenubar)); showMenuBarAction->setChecked(showMenu); // workaround for bug #171080 - if (!showMenu) { - createControlButton(); + + auto hamburgerMenu = static_cast<KHamburgerMenu *>(actionCollection()->action( + KStandardAction::name(KStandardAction::HamburgerMenu))); + hamburgerMenu->setMenuBar(menuBar()); + hamburgerMenu->setShowMenuBarAction(showMenuBarAction); + connect(hamburgerMenu, &KHamburgerMenu::aboutToShowMenu, + this, &DolphinMainWindow::updateHamburgerMenu); + hamburgerMenu->hideActionsOf(toolBar()); + if (GeneralSettings::version() < 201 && !toolBar()->actions().contains(hamburgerMenu)) { + addHamburgerMenuToToolbar(); } updateAllowedToolbarAreas(); @@ -982,11 +989,6 @@ void DolphinMainWindow::toggleShowMenuBar() { const bool visible = menuBar()->isVisible(); menuBar()->setVisible(!visible); - if (visible) { - createControlButton(); - } else { - deleteControlButton(); - } } QPointer<QAction> DolphinMainWindow::preferredSearchTool() @@ -1153,87 +1155,91 @@ void DolphinMainWindow::openContextMenu(const QPoint& pos, } } -void DolphinMainWindow::updateControlMenu() +void DolphinMainWindow::updateHamburgerMenu() { - QMenu* menu = qobject_cast<QMenu*>(sender()); - Q_ASSERT(menu); - - // All actions get cleared by QMenu::clear(). This includes the sub-menus - // because 'menu' is their parent. - menu->clear(); - KActionCollection* ac = actionCollection(); - - menu->addMenu(m_newFileMenu->menu()); - addActionToMenu(ac->action(QStringLiteral("file_new")), menu); - addActionToMenu(ac->action(QStringLiteral("new_tab")), menu); - addActionToMenu(ac->action(QStringLiteral("closed_tabs")), menu); - - menu->addSeparator(); - - // Add "Edit" actions - bool added = addActionToMenu(ac->action(KStandardAction::name(KStandardAction::Undo)), menu) | - addActionToMenu(ac->action(QString("copy_location")), menu) | - addActionToMenu(ac->action(QStringLiteral("copy_to_inactive_split_view")), menu) | - addActionToMenu(ac->action(QStringLiteral("move_to_inactive_split_view")), menu) | - addActionToMenu(ac->action(KStandardAction::name(KStandardAction::SelectAll)), menu) | - addActionToMenu(ac->action(QStringLiteral("invert_selection")), menu); - - if (added) { - menu->addSeparator(); + auto hamburgerMenu = static_cast<KHamburgerMenu *>( + ac->action(KStandardAction::name(KStandardAction::HamburgerMenu))); + auto menu = hamburgerMenu->menu(); + if (!menu) { + menu = new QMenu(this); + hamburgerMenu->setMenu(menu); + hamburgerMenu->hideActionsOf(ac->action(QStringLiteral("basic_actions"))->menu()); + hamburgerMenu->hideActionsOf(ac->action(QStringLiteral("zoom"))->menu()); + } else { + menu->clear(); } + const QList<QAction *> toolbarActions = toolBar()->actions(); - // Add "View" actions - if (!GeneralSettings::showZoomSlider()) { - addActionToMenu(ac->action(KStandardAction::name(KStandardAction::ZoomIn)), menu); - addActionToMenu(ac->action(QStringLiteral("view_zoom_reset")), menu); - addActionToMenu(ac->action(KStandardAction::name(KStandardAction::ZoomOut)), menu); + if (!toolBar()->isVisible()) { + // If neither the menu bar nor the toolbar are visible, these actions should be available. + menu->addAction(ac->action(KStandardAction::name(KStandardAction::ShowMenubar))); + menu->addAction(toolBarMenuAction()); menu->addSeparator(); } - added = addActionToMenu(ac->action(QStringLiteral("show_preview")), menu) | - addActionToMenu(ac->action(QStringLiteral("show_in_groups")), menu) | - addActionToMenu(ac->action(QStringLiteral("show_hidden_files")), menu) | - addActionToMenu(ac->action(QStringLiteral("additional_info")), menu) | - addActionToMenu(ac->action(QStringLiteral("view_properties")), menu); + // This group of actions (until the next separator) contains all the most basic actions + // necessary to use Dolphin effectively. + menu->addAction(ac->action(QStringLiteral("go_back"))); + menu->addAction(ac->action(QStringLiteral("go_forward"))); - if (added) { - menu->addSeparator(); + menu->addMenu(m_newFileMenu->menu()); + menu->addAction(ac->action(QStringLiteral("basic_actions"))); + menu->addAction(ac->action(KStandardAction::name(KStandardAction::Undo))); + if (!toolBar()->isVisible() + || (!toolbarActions.contains(ac->action(QStringLiteral("toggle_search"))) + && !toolbarActions.contains(ac->action(QStringLiteral("open_preferred_search_tool")))) + ) { + menu->addAction(ac->action(KStandardAction::name(KStandardAction::Find))); + // This way a search action will only be added if none of the three available + // search actions is present on the toolbar. + } + if (!toolBar()->isVisible() + || !toolbarActions.contains(ac->action(QStringLiteral("toggle_filter"))) + ) { + menu->addAction(ac->action(QStringLiteral("show_filter_bar"))); + // This way a filter action will only be added if none of the two available + // filter actions is present on the toolbar. } - - // Add a curated assortment of items from the "Tools" menu - addActionToMenu(ac->action(QStringLiteral("show_filter_bar")), menu); - addActionToMenu(ac->action(QStringLiteral("open_preferred_search_tool")), menu); - addActionToMenu(ac->action(QStringLiteral("open_terminal")), menu); - menu->addSeparator(); - // Add "Show Panels" menu - addActionToMenu(ac->action(QStringLiteral("panels")), menu); - - // Add "Settings" menu entries - addActionToMenu(ac->action(KStandardAction::name(KStandardAction::KeyBindings)), menu); - addActionToMenu(ac->action(KStandardAction::name(KStandardAction::ConfigureToolbars)), menu); - addActionToMenu(ac->action(KStandardAction::name(KStandardAction::Preferences)), menu); - addActionToMenu(ac->action(KStandardAction::name(KStandardAction::ShowMenubar)), menu); - - // Add "Help" menu - auto helpMenu = m_helpMenu->menu(); - helpMenu->setIcon(QIcon::fromTheme(QStringLiteral("system-help"))); - menu->addMenu(helpMenu); -} + // The second group of actions (up until the next separator) contains actions for opening + // additional views to interact with the file system. + menu->addAction(ac->action(QStringLiteral("file_new"))); + menu->addAction(ac->action(QStringLiteral("new_tab"))); + if (ac->action(QStringLiteral("undo_close_tab"))->isEnabled()) { + menu->addAction(ac->action(QStringLiteral("closed_tabs"))); + } + menu->addAction(ac->action(QStringLiteral("open_terminal"))); + menu->addSeparator(); -void DolphinMainWindow::updateToolBar() -{ - if (!menuBar()->isVisible()) { - createControlButton(); + // The third group contains actions to change what one sees in the view + // and to change the more general UI. + if (!toolBar()->isVisible() + || (!toolbarActions.contains(ac->action(QStringLiteral("icons"))) + && !toolbarActions.contains(ac->action(QStringLiteral("compact"))) + && !toolbarActions.contains(ac->action(QStringLiteral("details"))) + && !toolbarActions.contains(ac->action(QStringLiteral("view_mode")))) + ) { + menu->addAction(ac->action(QStringLiteral("view_mode"))); } -} + menu->addAction(ac->action(QStringLiteral("show_hidden_files"))); + menu->addAction(ac->action(QStringLiteral("sort"))); + menu->addAction(ac->action(QStringLiteral("additional_info"))); + if (!GeneralSettings::showStatusBar() || !GeneralSettings::showZoomSlider()) { + menu->addAction(ac->action(QStringLiteral("zoom"))); + } + menu->addAction(ac->action(QStringLiteral("panels"))); -void DolphinMainWindow::slotControlButtonDeleted() -{ - m_controlButton = nullptr; - m_updateToolBarTimer->start(); + // The "Configure" menu is not added to the actionCollection() because there is hardly + // a good reason for users to put it on their toolbar. + auto configureMenu = menu->addMenu(QIcon::fromTheme(QStringLiteral("configure")), + i18nc("@action:inmenu menu for configure actions", "Configure")); + configureMenu->addAction(ac->action(KStandardAction::name(KStandardAction::SwitchApplicationLanguage))); + configureMenu->addAction(ac->action(KStandardAction::name(KStandardAction::KeyBindings))); + configureMenu->addAction(ac->action(KStandardAction::name(KStandardAction::ConfigureToolbars))); + configureMenu->addAction(ac->action(KStandardAction::name(KStandardAction::Preferences))); + hamburgerMenu->hideActionsOf(configureMenu); } void DolphinMainWindow::slotPlaceActivated(const QUrl& url) @@ -1245,7 +1251,9 @@ void DolphinMainWindow::slotPlaceActivated(const QUrl& url) // which had been unmounted earlier, see https://bugs.kde.org/show_bug.cgi?id=161385. reloadView(); } else { + view->disableUrlNavigatorSelectionRequests(); changeUrl(url); + view->enableUrlNavigatorSelectionRequests(); } } @@ -1269,6 +1277,7 @@ void DolphinMainWindow::activeViewChanged(DolphinViewContainer* viewContainer) // view and url navigator) and main window. oldViewContainer->disconnect(this); oldViewContainer->view()->disconnect(this); + oldViewContainer->urlNavigatorInternalWithHistory()->disconnect(this); auto navigators = static_cast<DolphinNavigatorsWidgetAction *> (actionCollection()->action(QStringLiteral("url_navigators"))); navigators->primaryUrlNavigator()->disconnect(this); @@ -1355,11 +1364,13 @@ void DolphinMainWindow::setViewsToHomeIfMountPathOpen(const QString& mountPath) void DolphinMainWindow::setupActions() { + KStandardAction::hamburgerMenu(nullptr, nullptr, actionCollection()); + // setup 'File' menu m_newFileMenu = new DolphinNewFileMenu(actionCollection(), this); QMenu* menu = m_newFileMenu->menu(); menu->setTitle(i18nc("@title:menu Create new folder, file, link, etc.", "Create New")); - menu->setIcon(QIcon::fromTheme(QStringLiteral("document-new"))); + menu->setIcon(QIcon::fromTheme(QStringLiteral("list-add"))); m_newFileMenu->setDelayed(false); connect(menu, &QMenu::aboutToShow, this, &DolphinMainWindow::updateNewMenu); @@ -1788,6 +1799,8 @@ void DolphinMainWindow::setupDockWidgets() infoPanel, &InformationPanel::setSelection); connect(this, &DolphinMainWindow::requestItemInfo, infoPanel, &InformationPanel::requestDelayedItemInfo); + connect(this, &DolphinMainWindow::fileItemsChanged, + infoPanel, &InformationPanel::slotFilesItemChanged); #endif // i18n: This is the last paragraph for the "What's This"-texts of all four panels. @@ -2076,65 +2089,6 @@ void DolphinMainWindow::updateGoActions() goUpAction->setEnabled(KIO::upUrl(currentUrl) != currentUrl); } -void DolphinMainWindow::createControlButton() -{ - if (m_controlButton) { - return; - } - Q_ASSERT(!m_controlButton); - - m_controlButton = new QToolButton(this); - m_controlButton->setAccessibleName(i18nc("@action:intoolbar", "Control")); - m_controlButton->setIcon(QIcon::fromTheme(QStringLiteral("application-menu"))); - m_controlButton->setToolTip(i18nc("@action", "Show menu")); - m_controlButton->setAttribute(Qt::WidgetAttribute::WA_CustomWhatsThis); - m_controlButton->setPopupMode(QToolButton::InstantPopup); - - QMenu* controlMenu = new QMenu(m_controlButton); - connect(controlMenu, &QMenu::aboutToShow, this, &DolphinMainWindow::updateControlMenu); - controlMenu->installEventFilter(this); - - m_controlButton->setMenu(controlMenu); - - toolBar()->addWidget(m_controlButton); - connect(toolBar(), &KToolBar::iconSizeChanged, - m_controlButton, &QToolButton::setIconSize); - - // The added widgets are owned by the toolbar and may get deleted when e.g. the toolbar - // gets edited. In this case we must add them again. The adding is done asynchronously by - // m_updateToolBarTimer. - connect(m_controlButton, &QToolButton::destroyed, this, &DolphinMainWindow::slotControlButtonDeleted); - m_updateToolBarTimer = new QTimer(this); - m_updateToolBarTimer->setInterval(500); - connect(m_updateToolBarTimer, &QTimer::timeout, this, &DolphinMainWindow::updateToolBar); -} - -void DolphinMainWindow::deleteControlButton() -{ - delete m_controlButton; - m_controlButton = nullptr; - - delete m_updateToolBarTimer; - m_updateToolBarTimer = nullptr; -} - -bool DolphinMainWindow::addActionToMenu(QAction* action, QMenu* menu) -{ - Q_ASSERT(action); - Q_ASSERT(menu); - - const KToolBar* toolBarWidget = toolBar(); - const auto associatedWidgets = action->associatedWidgets(); - for (const QWidget* widget : associatedWidgets) { - if (widget == toolBarWidget) { - return false; - } - } - - menu->addAction(action); - return true; -} - void DolphinMainWindow::refreshViews() { m_tabWidget->refreshViews(); @@ -2173,6 +2127,8 @@ void DolphinMainWindow::connectViewSignals(DolphinViewContainer* container) this, &DolphinMainWindow::slotSelectionChanged); connect(view, &DolphinView::requestItemInfo, this, &DolphinMainWindow::requestItemInfo); + connect(view, &DolphinView::fileItemsChanged, + this, &DolphinMainWindow::fileItemsChanged); connect(view, &DolphinView::tabRequested, this, &DolphinMainWindow::openNewTab); connect(view, &DolphinView::requestContextMenu, @@ -2192,15 +2148,17 @@ void DolphinMainWindow::connectViewSignals(DolphinViewContainer* container) connect(view, &DolphinView::goUpRequested, this, &DolphinMainWindow::goUp); + connect(container->urlNavigatorInternalWithHistory(), &KUrlNavigator::urlChanged, + this, &DolphinMainWindow::changeUrl); + connect(container->urlNavigatorInternalWithHistory(), &KUrlNavigator::historyChanged, + this, &DolphinMainWindow::updateHistory); + auto navigators = static_cast<DolphinNavigatorsWidgetAction *> (actionCollection()->action(QStringLiteral("url_navigators"))); - const KUrlNavigator *navigator = m_tabWidget->currentTabPage()->primaryViewActive() ? navigators->primaryUrlNavigator() : navigators->secondaryUrlNavigator(); - connect(navigator, &KUrlNavigator::urlChanged, - this, &DolphinMainWindow::changeUrl); QAction *editableLocactionAction = actionCollection()->action(QStringLiteral("editable_location")); editableLocactionAction->setChecked(navigator->isUrlEditable()); connect(navigator, &KUrlNavigator::editableStateChanged, @@ -2208,10 +2166,6 @@ void DolphinMainWindow::connectViewSignals(DolphinViewContainer* container) connect(navigator, &KUrlNavigator::tabRequested, this, &DolphinMainWindow::openNewTab); - disconnect(m_updateHistoryConnection); - m_updateHistoryConnection = connect( - container->urlNavigatorInternalWithHistory(), &KUrlNavigator::historyChanged, - this, &DolphinMainWindow::updateHistory); } void DolphinMainWindow::updateSplitAction() @@ -2434,6 +2388,29 @@ void DolphinMainWindow::setupWhatsThis() m_helpMenu->action(KHelpMenu::menuAboutKDE)->setWhatsThis(whatsThisAboutKDE); } +bool DolphinMainWindow::addHamburgerMenuToToolbar() +{ + QDomDocument domDocument = KXMLGUIClient::domDocument(); + if (domDocument.isNull()) { + return false; + } + QDomNode toolbar = domDocument.elementsByTagName(QStringLiteral("ToolBar")).at(0); + if (toolbar.isNull()) { + return false; + } + + QDomElement hamburgerMenuElement = domDocument.createElement(QStringLiteral("Action")); + hamburgerMenuElement.setAttribute(QStringLiteral("name"), QStringLiteral("hamburger_menu")); + toolbar.appendChild(hamburgerMenuElement); + + KXMLGUIFactory::saveConfigFile(domDocument, xmlFile()); + reloadXML(); + createGUI(); + return true; + // Make sure to also remove the <KXMLGUIFactory> and <QDomDocument> include + // whenever this method is removed (maybe in the year ~2026). +} + bool DolphinMainWindow::event(QEvent *event) { if (event->type() == QEvent::WhatsThisClicked) { @@ -2457,6 +2434,12 @@ bool DolphinMainWindow::eventFilter(QObject* obj, QEvent* event) return false; } +// Set a sane initial window size +QSize DolphinMainWindow::sizeHint() const +{ + return KXmlGuiWindow::sizeHint().expandedTo(QSize(760, 550)); +} + void DolphinMainWindow::saveNewToolbarConfig() { KXmlGuiWindow::saveNewToolbarConfig(); // Applies the new config. This has to be called first @@ -2468,6 +2451,8 @@ void DolphinMainWindow::saveNewToolbarConfig() m_tabWidget->currentTabPage()->insertNavigatorsWidget(navigators); } updateAllowedToolbarAreas(); + (static_cast<KHamburgerMenu *>(actionCollection()->action(KStandardAction::name( + KStandardAction::HamburgerMenu))))->hideActionsOf(toolBar()); } void DolphinMainWindow::focusTerminalPanel() diff --git a/src/dolphinmainwindow.h b/src/dolphinmainwindow.h index 921f5a4c9..95e8bb564 100644 --- a/src/dolphinmainwindow.h +++ b/src/dolphinmainwindow.h @@ -15,6 +15,10 @@ #include <KSortableList> #include <kxmlguiwindow.h> +#ifdef HAVE_BALOO + #include "panels/information/informationpanel.h" +#endif + #include <QIcon> #include <QList> #include <QMenu> @@ -37,7 +41,6 @@ class KNewFileMenu; class KHelpMenu; class KToolBarPopupAction; class QToolButton; -class QIcon; class PlacesPanel; class TerminalPanel; @@ -194,6 +197,12 @@ Q_SIGNALS: void requestItemInfo(const KFileItem& item); /** + * It is emitted when in the current view, files are changed, + * or dirs have files/removed from them. + */ + void fileItemsChanged(const KFileItemList &changedFileItems); + + /** * Is emitted if the settings have been changed. */ void settingsChanged(); @@ -216,6 +225,9 @@ protected: /** Handles QWhatsThisClickedEvent and passes all others on. */ bool eventFilter(QObject*, QEvent*) override; + /** Sets a sane initial window size **/ + QSize sizeHint() const override; + protected Q_SLOTS: /** * Calls the base method KXmlGuiWindow::saveNewToolbarConfig(). @@ -459,9 +471,15 @@ private Q_SLOTS: const QUrl& url, const QList<QAction*>& customActions); - void updateControlMenu(); - void updateToolBar(); - void slotControlButtonDeleted(); + /** + * Updates the menu that is by default at the right end of the toolbar. + * + * In true "simple by default" fashion, the menu only contains the most important + * and necessary actions to be able to use Dolphin. This is supposed to hold true even + * if the user does not know how to open a context menu. More advanced actions can be + * discovered through a sub-menu (@see KConfigWidgets::KHamburgerMenu::setMenuBarAdvertised()). + */ + void updateHamburgerMenu(); /** * Is called if the user clicked an item in the Places Panel. @@ -566,16 +584,6 @@ private: void updateViewActions(); void updateGoActions(); - void createControlButton(); - void deleteControlButton(); - - /** - * Adds the action \p action to the menu \p menu in - * case if it has not added already to the toolbar. - * @return True if the action has been added to the menu. - */ - bool addActionToMenu(QAction* action, QMenu* menu); - /** * Connects the signals from the created DolphinView with * the DolphinViewContainer \a container with the corresponding slots of @@ -616,6 +624,16 @@ private: /** Returns preferred search tool as configured in "More Search Tools" menu. */ QPointer<QAction> preferredSearchTool(); + /** + * Adds this action to the mainWindow's toolbar and saves the change + * in the users ui configuration file. + * This method is only needed for migration and should be removed once we can expect + * that pretty much all users have been migrated. Remove in 2026 because that's when + * even the most risk-averse distros will already have been forced to upgrade. + * @return true if successful. Otherwise false. + */ + bool addHamburgerMenuToToolbar(); + private: /** * Implements a custom error handling for the undo manager. This @@ -653,11 +671,7 @@ private: KToolBarPopupAction* m_backAction; KToolBarPopupAction* m_forwardAction; - /** Makes sure that only one object is ever connected to the history. */ - QMetaObject::Connection m_updateHistoryConnection; - QMenu m_searchTools; - }; inline DolphinViewContainer* DolphinMainWindow::activeViewContainer() const diff --git a/src/dolphinnavigatorswidgetaction.cpp b/src/dolphinnavigatorswidgetaction.cpp index be88b61af..d66125af6 100644 --- a/src/dolphinnavigatorswidgetaction.cpp +++ b/src/dolphinnavigatorswidgetaction.cpp @@ -233,6 +233,8 @@ QPushButton *DolphinNavigatorsWidgetAction::newEmptyTrashButton(const DolphinUrl { auto emptyTrashButton = new QPushButton(QIcon::fromTheme(QStringLiteral("user-trash")), i18nc("@action:button", "Empty Trash"), parent); + emptyTrashButton->setToolTip(QLatin1String("Empties Trash to create free space")); + emptyTrashButton->setFlat(true); connect(emptyTrashButton, &QPushButton::clicked, this, [parent]() { Trash::empty(parent); }); diff --git a/src/dolphinpart.desktop.in b/src/dolphinpart.desktop.in index 71690ead9..848f847d5 100644 --- a/src/dolphinpart.desktop.in +++ b/src/dolphinpart.desktop.in @@ -43,6 +43,7 @@ Name[sr@ijekavian]=Делфинов приказ Name[sr@ijekavianlatin]=Dolphinov prikaz Name[sr@latin]=Dolphinov prikaz Name[sv]=Vy i Dolphin +Name[ta]=டால்பின் காட்சிமுறை Name[tr]=Dolphin Görünümü Name[uk]=Перегляд Dolphin Name[vi]=Khung xem Dolphin @@ -112,6 +113,7 @@ Name[sr@ijekavian]=Иконице Name[sr@ijekavianlatin]=Ikonice Name[sr@latin]=Ikonice Name[sv]=Ikoner +Name[ta]=சின்னங்கள் Name[tr]=Simgeler Name[uk]=Піктограми Name[vi]=Biểu tượng @@ -166,6 +168,7 @@ Name[sr@ijekavian]=Сажето Name[sr@ijekavianlatin]=Sažeto Name[sr@latin]=Sažeto Name[sv]=Kompakt +Name[ta]=சுருக்கமானது Name[tr]=Sıkışık Name[uk]=Компактний Name[vi]=Gọn @@ -220,6 +223,7 @@ Name[sr@ijekavian]=Детаљи Name[sr@ijekavianlatin]=Detalji Name[sr@latin]=Detalji Name[sv]=Detaljinformation +Name[ta]=விவரங்கள் Name[tr]=Ayrıntılar Name[uk]=Подробиці Name[vi]=Chi tiết diff --git a/src/dolphintabpage.cpp b/src/dolphintabpage.cpp index 36049fa97..33c77c42a 100644 --- a/src/dolphintabpage.cpp +++ b/src/dolphintabpage.cpp @@ -328,48 +328,6 @@ void DolphinTabPage::restoreState(const QByteArray& state) m_splitter->restoreState(splitterState); } -void DolphinTabPage::restoreStateV1(const QByteArray& state) -{ - if (state.isEmpty()) { - return; - } - - QByteArray sd = state; - QDataStream stream(&sd, QIODevice::ReadOnly); - - bool isSplitViewEnabled = false; - stream >> isSplitViewEnabled; - setSplitViewEnabled(isSplitViewEnabled, WithoutAnimation); - - QUrl primaryUrl; - stream >> primaryUrl; - m_primaryViewContainer->setUrl(primaryUrl); - bool primaryUrlEditable; - stream >> primaryUrlEditable; - m_primaryViewContainer->urlNavigatorInternalWithHistory()->setUrlEditable(primaryUrlEditable); - - if (isSplitViewEnabled) { - QUrl secondaryUrl; - stream >> secondaryUrl; - m_secondaryViewContainer->setUrl(secondaryUrl); - bool secondaryUrlEditable; - stream >> secondaryUrlEditable; - m_secondaryViewContainer->urlNavigatorInternalWithHistory()->setUrlEditable(secondaryUrlEditable); - } - - stream >> m_primaryViewActive; - if (m_primaryViewActive) { - m_primaryViewContainer->setActive(true); - } else { - Q_ASSERT(m_splitViewEnabled); - m_secondaryViewContainer->setActive(true); - } - - QByteArray splitterState; - stream >> splitterState; - m_splitter->restoreState(splitterState); -} - void DolphinTabPage::setActive(bool active) { if (active) { diff --git a/src/dolphintabpage.h b/src/dolphintabpage.h index a9b7f8133..57a0c3344 100644 --- a/src/dolphintabpage.h +++ b/src/dolphintabpage.h @@ -129,15 +129,6 @@ public: void restoreState(const QByteArray& state); /** - * Restores all tab related properties (urls, splitter layout, ...) from - * the given \a state. - * - * @deprecated The first tab state version has no version number, we keep - * this method to restore old states (<= Dolphin 4.14.x). - */ - Q_DECL_DEPRECATED void restoreStateV1(const QByteArray& state); - - /** * Set whether the tab page is active * */ diff --git a/src/dolphintabwidget.cpp b/src/dolphintabwidget.cpp index 0a024235b..cfb695e7d 100644 --- a/src/dolphintabwidget.cpp +++ b/src/dolphintabwidget.cpp @@ -87,15 +87,8 @@ void DolphinTabWidget::readProperties(const KConfigGroup& group) if (i >= count()) { openNewActivatedTab(); } - if (group.hasKey("Tab Data " % QString::number(i))) { - // Tab state created with Dolphin > 4.14.x - const QByteArray state = group.readEntry("Tab Data " % QString::number(i), QByteArray()); - tabPageAt(i)->restoreState(state); - } else { - // Tab state created with Dolphin <= 4.14.x - const QByteArray state = group.readEntry("Tab " % QString::number(i), QByteArray()); - tabPageAt(i)->restoreStateV1(state); - } + const QByteArray state = group.readEntry("Tab Data " % QString::number(i), QByteArray()); + tabPageAt(i)->restoreState(state); } const int index = group.readEntry("Active Tab Index", 0); diff --git a/src/dolphinui.rc b/src/dolphinui.rc index e749abae0..1b7f2e8b1 100644 --- a/src/dolphinui.rc +++ b/src/dolphinui.rc @@ -1,6 +1,6 @@ <?xml version="1.0"?> <!DOCTYPE gui SYSTEM "kpartgui.dtd"> -<gui name="dolphin" version="33"> +<gui name="dolphin" version="35"> <MenuBar> <Menu name="file"> <Action name="new_menu" /> @@ -124,7 +124,7 @@ <Action name="split_view" /> <Action name="split_stash" /> <Action name="toggle_search" /> - <Action name="toggle_filter" /> + <Action name="hamburger_menu" /> </ToolBar> <ActionProperties scheme="Default"> <Action priority="0" name="go_back"/> diff --git a/src/dolphinviewcontainer.cpp b/src/dolphinviewcontainer.cpp index 549b62b03..1a608669f 100644 --- a/src/dolphinviewcontainer.cpp +++ b/src/dolphinviewcontainer.cpp @@ -727,6 +727,18 @@ void DolphinViewContainer::slotUrlSelectionRequested(const QUrl& url) m_view->markUrlAsCurrent(url); // makes the item scroll into view } +void DolphinViewContainer::disableUrlNavigatorSelectionRequests() +{ + disconnect(m_urlNavigator.get(), &KUrlNavigator::urlSelectionRequested, + this, &DolphinViewContainer::slotUrlSelectionRequested); +} + +void DolphinViewContainer::enableUrlNavigatorSelectionRequests() +{ + connect(m_urlNavigator.get(), &KUrlNavigator::urlSelectionRequested, + this, &DolphinViewContainer::slotUrlSelectionRequested); +} + void DolphinViewContainer::redirect(const QUrl& oldUrl, const QUrl& newUrl) { Q_UNUSED(oldUrl) diff --git a/src/dolphinviewcontainer.h b/src/dolphinviewcontainer.h index eeb9204c1..1a92e1fa6 100644 --- a/src/dolphinviewcontainer.h +++ b/src/dolphinviewcontainer.h @@ -28,7 +28,6 @@ namespace KActivities { class FilterBar; class KMessageWidget; class QUrl; -class KUrlNavigator; class DolphinSearchBox; class DolphinStatusBar; @@ -175,6 +174,15 @@ public: */ QString caption() const; + /** + * Disable/enable the behavior of "select child when moving to parent folder" + * offered by KUrlNavigator. + * + * See KUrlNavigator::urlSelectionRequested + */ + void disableUrlNavigatorSelectionRequests(); + void enableUrlNavigatorSelectionRequests(); + public Q_SLOTS: /** * Sets the current active URL, where all actions are applied. The diff --git a/src/global.cpp b/src/global.cpp index 3d17a733b..197d6ec28 100644 --- a/src/global.cpp +++ b/src/global.cpp @@ -9,6 +9,7 @@ #include "dolphin_generalsettings.h" #include "dolphindebug.h" #include "dolphinmainwindowinterface.h" +#include "views/viewproperties.h" #include <KConfigWatcher> #include <KDialogJobUiDelegate> @@ -140,6 +141,12 @@ QVector<QPair<QSharedPointer<OrgKdeDolphinMainWindowInterface>, QStringList>> Do return dolphinInterfaces; } +QPair<QString, Qt::SortOrder> Dolphin::sortOrderForUrl(QUrl &url) +{ + ViewProperties globalProps(url); + return QPair<QString, Qt::SortOrder>(globalProps.sortRole(), globalProps.sortOrder()); +} + double GlobalConfig::animationDurationFactor() { if (s_animationDurationFactor >= 0.0) { diff --git a/src/global.h b/src/global.h index 088e9c5b6..4f4eb890c 100644 --- a/src/global.h +++ b/src/global.h @@ -46,6 +46,8 @@ namespace Dolphin { */ QVector<QPair<QSharedPointer<OrgKdeDolphinMainWindowInterface>, QStringList>> dolphinGuiInstances(const QString& preferredService); + QPair<QString, Qt::SortOrder> sortOrderForUrl(QUrl &url); + /** * TODO: Move this somewhere global to all KDE apps, not just Dolphin */ diff --git a/src/kitemviews/kfileitemmodel.cpp b/src/kitemviews/kfileitemmodel.cpp index da15ccbdd..a6c5e48ec 100644 --- a/src/kitemviews/kfileitemmodel.cpp +++ b/src/kitemviews/kfileitemmodel.cpp @@ -1015,6 +1015,8 @@ void KFileItemModel::slotItemsAdded(const QUrl &directoryUrl, const KFileItemLis // emitted during the maximum update interval. m_maximumUpdateIntervalTimer->start(); } + + Q_EMIT fileItemsChanged({KFileItem(directoryUrl)}); } void KFileItemModel::slotItemsDeleted(const KFileItemList& items) @@ -1023,6 +1025,7 @@ void KFileItemModel::slotItemsDeleted(const KFileItemList& items) QVector<int> indexesToRemove; indexesToRemove.reserve(items.count()); + KFileItemList dirsChanged; for (const KFileItem& item : items) { const int indexForItem = index(item); @@ -1036,6 +1039,11 @@ void KFileItemModel::slotItemsDeleted(const KFileItemList& items) m_filteredItems.erase(it); } } + + QUrl parentUrl = item.url().adjusted(QUrl::RemoveFilename | QUrl::StripTrailingSlash); + if (dirsChanged.findByUrl(parentUrl).isNull()) { + dirsChanged << KFileItem(parentUrl); + } } std::sort(indexesToRemove.begin(), indexesToRemove.end()); @@ -1063,6 +1071,8 @@ void KFileItemModel::slotItemsDeleted(const KFileItemList& items) const KItemRangeList itemRanges = KItemRangeList::fromSortedContainer(indexesToRemove); removeFilteredChildren(itemRanges); removeItems(itemRanges, DeleteItemData); + + Q_EMIT fileItemsChanged(dirsChanged); } void KFileItemModel::slotRefreshItems(const QList<QPair<KFileItem, KFileItem> >& items) @@ -1077,6 +1087,7 @@ void KFileItemModel::slotRefreshItems(const QList<QPair<KFileItem, KFileItem> >& indexes.reserve(items.count()); QSet<QByteArray> changedRoles; + KFileItemList changedFiles; QListIterator<QPair<KFileItem, KFileItem> > it(items); while (it.hasNext()) { @@ -1102,6 +1113,7 @@ void KFileItemModel::slotRefreshItems(const QList<QPair<KFileItem, KFileItem> >& m_items.remove(oldItem.url()); m_items.insert(newItem.url(), indexForItem); + changedFiles.append(newItem); indexes.append(indexForItem); } else { // Check if 'oldItem' is one of the filtered items. @@ -1130,6 +1142,8 @@ void KFileItemModel::slotRefreshItems(const QList<QPair<KFileItem, KFileItem> >& std::sort(indexes.begin(), indexes.end()); const KItemRangeList itemRangeList = KItemRangeList::fromSortedContainer(indexes); emitItemsChangedAndTriggerResorting(itemRangeList, changedRoles); + + Q_EMIT fileItemsChanged(changedFiles); } void KFileItemModel::slotClear() @@ -1719,6 +1733,15 @@ bool KFileItemModel::lessThan(const ItemData* a, const ItemData* b, const QColla } } + // Show hidden files and folders last + const bool isHiddenA = a->item.isHidden(); + const bool isHiddenB = b->item.isHidden(); + if (isHiddenA && !isHiddenB) { + return false; + } else if (!isHiddenA && isHiddenB) { + return true; + } + if (m_sortDirsFirst || (DetailsModeSettings::directorySizeCount() && m_sortRole == SizeRole)) { const bool isDirA = a->item.isDir(); const bool isDirB = b->item.isDir(); @@ -2090,7 +2113,7 @@ QList<QPair<int, QVariant> > KFileItemModel::timeRoleGroups(const std::function< if (daysDistance == 1) { const KLocalizedString format = ki18nc("@title:group Date: " "MMMM is full month name in current locale, and yyyy is " - "full year number", "'Yesterday' (MMMM, yyyy)"); + "full year number. You must keep the ' don't use any fancy \" or « or similar. The ' is not shown to the user, it's there to mark a part of the text that should not be formatted as a date", "'Yesterday' (MMMM, yyyy)"); const QString translatedFormat = format.toString(); if (translatedFormat.count(QLatin1Char('\'')) == 2) { newGroupValue = fileTime.toString(translatedFormat); @@ -2105,7 +2128,7 @@ QList<QPair<int, QVariant> > KFileItemModel::timeRoleGroups(const std::function< } else if (daysDistance <= 7) { newGroupValue = fileTime.toString(i18nc("@title:group Date: " "The week day name: dddd, MMMM is full month name " - "in current locale, and yyyy is full year number", + "in current locale, and yyyy is full year number.", "dddd (MMMM, yyyy)")); newGroupValue = i18nc("Can be used to script translation of " "\"dddd (MMMM, yyyy)\" with context @title:group Date", @@ -2113,7 +2136,7 @@ QList<QPair<int, QVariant> > KFileItemModel::timeRoleGroups(const std::function< } else if (daysDistance <= 7 * 2) { const KLocalizedString format = ki18nc("@title:group Date: " "MMMM is full month name in current locale, and yyyy is " - "full year number", "'One Week Ago' (MMMM, yyyy)"); + "full year number. You must keep the ' don't use any fancy \" or « or similar. The ' is not shown to the user, it's there to mark a part of the text that should not be formatted as a date", "'One Week Ago' (MMMM, yyyy)"); const QString translatedFormat = format.toString(); if (translatedFormat.count(QLatin1Char('\'')) == 2) { newGroupValue = fileTime.toString(translatedFormat); @@ -2128,7 +2151,7 @@ QList<QPair<int, QVariant> > KFileItemModel::timeRoleGroups(const std::function< } else if (daysDistance <= 7 * 3) { const KLocalizedString format = ki18nc("@title:group Date: " "MMMM is full month name in current locale, and yyyy is " - "full year number", "'Two Weeks Ago' (MMMM, yyyy)"); + "full year number. You must keep the ' don't use any fancy \" or « or similar. The ' is not shown to the user, it's there to mark a part of the text that should not be formatted as a date", "'Two Weeks Ago' (MMMM, yyyy)"); const QString translatedFormat = format.toString(); if (translatedFormat.count(QLatin1Char('\'')) == 2) { newGroupValue = fileTime.toString(translatedFormat); @@ -2143,7 +2166,7 @@ QList<QPair<int, QVariant> > KFileItemModel::timeRoleGroups(const std::function< } else if (daysDistance <= 7 * 4) { const KLocalizedString format = ki18nc("@title:group Date: " "MMMM is full month name in current locale, and yyyy is " - "full year number", "'Three Weeks Ago' (MMMM, yyyy)"); + "full year number. You must keep the ' don't use any fancy \" or « or similar. The ' is not shown to the user, it's there to mark a part of the text that should not be formatted as a date", "'Three Weeks Ago' (MMMM, yyyy)"); const QString translatedFormat = format.toString(); if (translatedFormat.count(QLatin1Char('\'')) == 2) { newGroupValue = fileTime.toString(translatedFormat); @@ -2158,7 +2181,7 @@ QList<QPair<int, QVariant> > KFileItemModel::timeRoleGroups(const std::function< } else { const KLocalizedString format = ki18nc("@title:group Date: " "MMMM is full month name in current locale, and yyyy is " - "full year number", "'Earlier on' MMMM, yyyy"); + "full year number. You must keep the ' don't use any fancy \" or « or similar. The ' is not shown to the user, it's there to mark a part of the text that should not be formatted as a date", "'Earlier on' MMMM, yyyy"); const QString translatedFormat = format.toString(); if (translatedFormat.count(QLatin1Char('\'')) == 2) { newGroupValue = fileTime.toString(translatedFormat); diff --git a/src/kitemviews/kfileitemmodel.h b/src/kitemviews/kfileitemmodel.h index 886a1c6de..acf4b761c 100644 --- a/src/kitemviews/kfileitemmodel.h +++ b/src/kitemviews/kfileitemmodel.h @@ -245,6 +245,12 @@ Q_SIGNALS: */ void urlIsFileError(const QUrl& url); + /** + * It is emitted for files when they change and + * for dirs when files are added or removed. + */ + void fileItemsChanged(const KFileItemList &changedFileItems); + protected: void onGroupedSortingChanged(bool current) override; void onSortRoleChanged(const QByteArray& current, const QByteArray& previous, bool resortItems = true) override; diff --git a/src/kitemviews/kitemlistcontainer.cpp b/src/kitemviews/kitemlistcontainer.cpp index f253cda53..10b9f1415 100644 --- a/src/kitemviews/kitemlistcontainer.cpp +++ b/src/kitemviews/kitemlistcontainer.cpp @@ -208,6 +208,8 @@ void KItemListContainer::slotViewChanged(KItemListView* current, KItemListView* disconnect(previous, &KItemListView::maximumItemOffsetChanged, this, &KItemListContainer::updateItemOffsetScrollBar); disconnect(previous, &KItemListView::scrollTo, this, &KItemListContainer::scrollTo); + disconnect(m_horizontalSmoothScroller, &KItemListSmoothScroller::scrollingStopped, previous, &KItemListView::scrollingStopped); + disconnect(m_verticalSmoothScroller, &KItemListSmoothScroller::scrollingStopped, previous, &KItemListView::scrollingStopped); m_horizontalSmoothScroller->setTargetObject(nullptr); m_verticalSmoothScroller->setTargetObject(nullptr); } @@ -224,6 +226,9 @@ void KItemListContainer::slotViewChanged(KItemListView* current, KItemListView* connect(current, &KItemListView::maximumItemOffsetChanged, this, &KItemListContainer::updateItemOffsetScrollBar); connect(current, &KItemListView::scrollTo, this, &KItemListContainer::scrollTo); + connect(m_horizontalSmoothScroller, &KItemListSmoothScroller::scrollingStopped, current, &KItemListView::scrollingStopped); + connect(m_verticalSmoothScroller, &KItemListSmoothScroller::scrollingStopped, current, &KItemListView::scrollingStopped); + m_horizontalSmoothScroller->setTargetObject(current); m_verticalSmoothScroller->setTargetObject(current); updateSmoothScrollers(current->scrollOrientation()); diff --git a/src/kitemviews/kitemlistview.cpp b/src/kitemviews/kitemlistview.cpp index 56cede2fd..5c8c712e8 100644 --- a/src/kitemviews/kitemlistview.cpp +++ b/src/kitemviews/kitemlistview.cpp @@ -526,8 +526,11 @@ void KItemListView::scrollToItem(int index) if (newOffset != scrollOffset()) { Q_EMIT scrollTo(newOffset); + return; } } + + Q_EMIT scrollingStopped(); } void KItemListView::beginTransaction() @@ -1602,16 +1605,16 @@ void KItemListView::slotRoleEditingCanceled(int index, const QByteArray& role, c { disconnectRoleEditingSignals(index); - Q_EMIT roleEditingCanceled(index, role, value); m_editingRole = false; + Q_EMIT roleEditingCanceled(index, role, value); } void KItemListView::slotRoleEditingFinished(int index, const QByteArray& role, const QVariant& value) { disconnectRoleEditingSignals(index); - Q_EMIT roleEditingFinished(index, role, value); m_editingRole = false; + Q_EMIT roleEditingFinished(index, role, value); } void KItemListView::setController(KItemListController* controller) @@ -1750,13 +1753,11 @@ void KItemListView::doLayout(LayoutAnimationHint hint, int changedIndex, int cha const bool animate = (hint == Animation); for (int i = firstVisibleIndex; i <= lastVisibleIndex; ++i) { bool applyNewPos = true; - bool wasHidden = false; const QRectF itemBounds = m_layouter->itemRect(i); const QPointF newPos = itemBounds.topLeft(); KItemListWidget* widget = m_visibleItems.value(i); if (!widget) { - wasHidden = true; if (!reusableItems.isEmpty()) { // Reuse a KItemListWidget instance from an invisible item const int oldIndex = reusableItems.takeLast(); @@ -2551,7 +2552,7 @@ void KItemListView::updateGroupHeaderHeight() groupHeaderHeight += 2 * m_styleOption.horizontalMargin; groupHeaderMargin = m_styleOption.horizontalMargin; } else if (m_itemSize.isEmpty()){ - groupHeaderHeight += 2 * m_styleOption.padding; + groupHeaderHeight += 4 * m_styleOption.padding; groupHeaderMargin = m_styleOption.iconSize / 2; } else { groupHeaderHeight += 2 * m_styleOption.padding + m_styleOption.verticalMargin; diff --git a/src/kitemviews/kitemlistview.h b/src/kitemviews/kitemlistview.h index a84794335..5453d851f 100644 --- a/src/kitemviews/kitemlistview.h +++ b/src/kitemviews/kitemlistview.h @@ -307,6 +307,12 @@ Q_SIGNALS: void roleEditingCanceled(int index, const QByteArray& role, const QVariant& value); void roleEditingFinished(int index, const QByteArray& role, const QVariant& value); + /** + * Emitted once scrolling has finished, or immediately if no scrolling was necessary + * to get item in view in scrollToItem. + */ + void scrollingStopped(); + protected: QVariant itemChange(GraphicsItemChange change, const QVariant &value) override; void setItemSize(const QSizeF& size); diff --git a/src/kitemviews/kstandarditemlistwidget.cpp b/src/kitemviews/kstandarditemlistwidget.cpp index 73744b385..e58340fb8 100644 --- a/src/kitemviews/kstandarditemlistwidget.cpp +++ b/src/kitemviews/kstandarditemlistwidget.cpp @@ -764,6 +764,7 @@ void KStandardItemListWidget::editedRoleChanged(const QByteArray& current, const m_roleEditor = new KItemListRoleEditor(parent); m_roleEditor->setRole(current); + m_roleEditor->setAllowUpDownKeyChainEdit(m_layout != IconsLayout); m_roleEditor->setFont(styleOption().font); const QString text = data().value(current).toString(); diff --git a/src/kitemviews/private/kfileitemmodeldirlister.cpp b/src/kitemviews/private/kfileitemmodeldirlister.cpp index 90c970874..eb860a2b9 100644 --- a/src/kitemviews/private/kfileitemmodeldirlister.cpp +++ b/src/kitemviews/private/kfileitemmodeldirlister.cpp @@ -8,11 +8,16 @@ #include <KLocalizedString> #include <KIO/Job> +#include <kio_version.h> KFileItemModelDirLister::KFileItemModelDirLister(QObject* parent) : KDirLister(parent) { +#if KIO_VERSION < QT_VERSION_CHECK(5, 82, 0) setAutoErrorHandlingEnabled(false, nullptr); +#else + setAutoErrorHandlingEnabled(false); +#endif } KFileItemModelDirLister::~KFileItemModelDirLister() diff --git a/src/kitemviews/private/kitemlistroleeditor.cpp b/src/kitemviews/private/kitemlistroleeditor.cpp index df142a456..cc10bd58a 100644 --- a/src/kitemviews/private/kitemlistroleeditor.cpp +++ b/src/kitemviews/private/kitemlistroleeditor.cpp @@ -40,6 +40,11 @@ QByteArray KItemListRoleEditor::role() const return m_role; } +void KItemListRoleEditor::setAllowUpDownKeyChainEdit(bool allowChainEdit) +{ + m_allowUpDownKeyChainEdit = allowChainEdit; +} + bool KItemListRoleEditor::eventFilter(QObject* watched, QEvent* event) { if (watched == parentWidget() && event->type() == QEvent::Resize) { @@ -78,6 +83,20 @@ void KItemListRoleEditor::keyPressEvent(QKeyEvent* event) emitRoleEditingFinished(); event->accept(); return; + case Qt::Key_Tab: + case Qt::Key_Down: + if (m_allowUpDownKeyChainEdit || event->key() == Qt::Key_Tab) { + emitRoleEditingFinished(EditNext); + event->accept(); + return; + } + case Qt::Key_Backtab: + case Qt::Key_Up: + if (m_allowUpDownKeyChainEdit || event->key() == Qt::Key_Backtab) { + emitRoleEditingFinished(EditPrevious); + event->accept(); + return; + } case Qt::Key_Left: case Qt::Key_Right: { QTextCursor cursor = textCursor(); @@ -143,10 +162,13 @@ void KItemListRoleEditor::autoAdjustSize() } } -void KItemListRoleEditor::emitRoleEditingFinished() +void KItemListRoleEditor::emitRoleEditingFinished(EditResultDirection direction) { + QVariant ret; + ret.setValue(EditResult {KIO::encodeFileName(toPlainText()), direction}); + if (!m_blockFinishedSignal) { - Q_EMIT roleEditingFinished(m_role, KIO::encodeFileName(toPlainText())); + Q_EMIT roleEditingFinished(m_role, ret); } } diff --git a/src/kitemviews/private/kitemlistroleeditor.h b/src/kitemviews/private/kitemlistroleeditor.h index 070cf5ce9..a0f55df51 100644 --- a/src/kitemviews/private/kitemlistroleeditor.h +++ b/src/kitemviews/private/kitemlistroleeditor.h @@ -11,12 +11,26 @@ #include <KTextEdit> +enum EditResultDirection{ + EditDone, + EditNext, + EditPrevious, +}; +Q_DECLARE_METATYPE(EditResultDirection) + +struct EditResult +{ + QString newName; + EditResultDirection direction; +}; +Q_DECLARE_METATYPE(EditResult) + /** * @brief Editor for renaming roles of a KItemListWidget. * * Provides signals when the editing got cancelled (e.g. by * pressing Escape or when losing the focus) or when the editing - * got finished (e.g. by pressing Enter or Return). + * got finished (e.g. by pressing Enter, Tab or Return). * * The size automatically gets increased if the text does not fit. */ @@ -31,6 +45,7 @@ public: void setRole(const QByteArray& role); QByteArray role() const; + void setAllowUpDownKeyChainEdit(bool allowChainEdit); bool eventFilter(QObject* watched, QEvent* event) override; Q_SIGNALS: @@ -53,11 +68,12 @@ private: * Emits the signal roleEditingFinished if m_blockFinishedSignal * is false. */ - void emitRoleEditingFinished(); + void emitRoleEditingFinished(EditResultDirection direction = EditDone); private: QByteArray m_role; bool m_blockFinishedSignal; + bool m_allowUpDownKeyChainEdit; }; #endif diff --git a/src/kitemviews/private/kitemlistsmoothscroller.cpp b/src/kitemviews/private/kitemlistsmoothscroller.cpp index 1465361ed..f77d3df58 100644 --- a/src/kitemviews/private/kitemlistsmoothscroller.cpp +++ b/src/kitemviews/private/kitemlistsmoothscroller.cpp @@ -175,6 +175,9 @@ void KItemListSmoothScroller::slotAnimationStateChanged(QAbstractAnimation::Stat if (newState == QAbstractAnimation::Stopped && m_smoothScrolling && !m_scrollBarPressed) { m_smoothScrolling = false; } + if (newState == QAbstractAnimation::Stopped) { + Q_EMIT scrollingStopped(); + } } void KItemListSmoothScroller::handleWheelEvent(QWheelEvent* event) diff --git a/src/kitemviews/private/kitemlistsmoothscroller.h b/src/kitemviews/private/kitemlistsmoothscroller.h index 55548219e..7b2839884 100644 --- a/src/kitemviews/private/kitemlistsmoothscroller.h +++ b/src/kitemviews/private/kitemlistsmoothscroller.h @@ -69,6 +69,11 @@ public: */ void handleWheelEvent(QWheelEvent* event); +Q_SIGNALS: + /** + * Emitted when the scrolling animation has finished + */ + void scrollingStopped(); protected: bool eventFilter(QObject* obj, QEvent* event) override; diff --git a/src/main.cpp b/src/main.cpp index ef2905d77..fba45f43c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -37,7 +37,7 @@ #endif #include <iostream> -extern "C" Q_DECL_EXPORT int kdemain(int argc, char **argv) +int main(int argc, char **argv) { #ifndef Q_OS_WIN // Prohibit using sudo or kdesu (but allow using the root user directly) diff --git a/src/org.kde.dolphin.appdata.xml b/src/org.kde.dolphin.appdata.xml index b1943fce6..2bb479cdd 100644 --- a/src/org.kde.dolphin.appdata.xml +++ b/src/org.kde.dolphin.appdata.xml @@ -46,6 +46,7 @@ <name xml:lang="sr-ijekavian">Делфин</name> <name xml:lang="sr-ijekavianlatin">Dolphin</name> <name xml:lang="sv">Dolphin</name> + <name xml:lang="ta">டால்பின்</name> <name xml:lang="tr">Dolphin</name> <name xml:lang="uk">Dolphin</name> <name xml:lang="vi">Dolphin</name> @@ -95,6 +96,7 @@ <summary xml:lang="sr-ijekavian">Менаџер фајлова</summary> <summary xml:lang="sr-ijekavianlatin">Menadžer fajlova</summary> <summary xml:lang="sv">Filhanterare</summary> + <summary xml:lang="ta">கோப்பு உலாவி</summary> <summary xml:lang="tr">Dosya Yöneticisi</summary> <summary xml:lang="uk">Програма для керування файлами</summary> <summary xml:lang="vi">Trình quản lí tệp</summary> @@ -126,6 +128,7 @@ <p xml:lang="sk">Dolphin je správca súborov KDE, ktorý vám umožní prechádzať a prehľadávať obsah vašich pevných diskov, USB kľúčov, SD kariet a ďalších. Vytváranie, presúvanie alebo mazanie súborov a priečinkov je jednoduché a rýchle.</p> <p xml:lang="sl">Dolphin je upravitelj datotek KDE, ki vam omogoča krmarjenje in brskanje po vsebini trdih diskov, USB ključkov, SD kartic in še več. Ustvarjanje, premikanje ali brisanje datotek in map je preprosto in hitro.</p> <p xml:lang="sv">Dolphin är KDE:s filhanterare som låter dig navigera och bläddra i innehållet på hårddiskar, USB-minnen, SD-kort, med mera. Skapa, flytta eller ta bort filer och kataloger är enkelt och går snabbt.</p> + <p xml:lang="ta">டால்பின் என்பது, உங்கள் வட்டுகள், USB சாதனங்கள், மற்றும் SD அட்டைகள் போன்றவற்றின் உள்ளடக்கத்தை பார்க்க உதவும் கே.டீ.யீ.யின் கோப்பு உலாவியாகும். கோப்புகள் மற்றும் அடைவுகளை எளிதாகவும் வேகமாகவும் உருவாக்க, நகர்த்த, மற்றும் நீக்க முடியும்.</p> <p xml:lang="tr">Dolphin, KDE'nin sabit disklerinizin, USB belleklerinizin, SD kartlarınızın ve daha fazlasının içeriğinde gezinmenizi ve bunlara göz atmanızı sağlayan dosya yöneticisidir. Dosya ve klasörlerin oluşturulması, taşınması veya silinmesi basit ve hızlıdır.</p> <p xml:lang="uk">Dolphin — програма для керування файлами KDE, за допомогою якої ви можете пересуватися та переглядати вміст дисків, флешок USB, SD-карток тощо. Створення, пересування або вилучення файлів та тек є простим і швидким завданням.</p> <p xml:lang="vi">Dolphin là trình quản lí tệp của KDE, nó cho phép bạn điều hướng và duyệt nội dung các ổ cứng, các thẻ USB, thẻ SD và các thiết bị khác của bạn. Việc tạo, chuyển, hay xoá tệp và thư mục đều đơn giản và nhanh chóng.</p> @@ -155,6 +158,7 @@ <p xml:lang="sk">Dolphin obsahuje množstvo funkcií produktivity, ktoré vám ušetria čas. Viaceré karty a funkcie rozdeleného zobrazenia umožňujú navigáciu vo viacerých priečinkoch súčasne. Medzi jednotlivými zobrazeniami môžete súbory jednoducho presúvať a presúvať alebo kopírovať. Ponuka pravým tlačidlom myši Dolphin ponúka mnoho rýchlych akcií, ktoré vám okrem iného umožňujú kompresiu, zdieľanie a duplikovanie súborov. Môžete tiež pridať svoje vlastné vlastné akcie.</p> <p xml:lang="sl">Dolphin vsebuje veliko produktivnih funkcij, s katerimi boste prihranili čas. Več zavihkov in funkcij razdeljenega pogleda omogočajo sočasno krmarjenje po več mapah, tako da lahko datoteke enostavno vlečete in spustite med pogledi, da jih premaknete ali kopirate. Dolphinov meni z desnim klikom nudi veliko hitrih dejanj, ki vam med drugim omogočajo stiskanje, skupno rabo in podvajanje datotek. Dodate lahko tudi svoja dejanja po meri.</p> <p xml:lang="sv">Dolphin innehåller mängder av produktivitetsfunktioner som sparar tid. Funktionerna för flera flikar och delad vy tillåter att flera kataloger navigeras samtidigt, och du kan enkelt dra och släppa filer mellan vyer för att flytta eller kopiera dem. Dolphins högerklicksmeny tillhandahåller många snabbåtgärder som låter dig bland annat komprimera, dela och duplicera filer. Du kan också lägga till egna åtgärder.</p> + <p xml:lang="ta">உங்கள் நேரத்தைச் சேமிக்கும் பல அமசங்களை டால்பின் கொண்டுள்ளது. பல கீற்றுகளையோ துண்டாக்கப்பட்ட காட்சிமுறையையோ கொண்டு ஒரே நேரத்தில் பல அடைவுகளில் உலாவலாம். மேலும், காட்சிகளுக்கிடையே கோப்புகளை இழுத்துப் போடலாம். டால்பினின் வலது-க்ளிக் பட்டியில் சுருக்குதல், பகிர்தல், மற்றும் நகலெடுத்தல் போன்ற பல செயல்கள் உள்ளன. மேலும், உங்களுக்கு விருப்பமான செயல்களை நீங்கள் வலது-க்ளிக் பட்டியில் சேர்க்கலாம்.</p> <p xml:lang="tr">Dolphin size zaman kazandıracak birçok üretkenlik özelliği içerir. Birden çok sekme ve bölünmüş görünüm özellikleri, aynı anda birden çok klasörde gezinmeye izin verir ve dosyaları taşımak veya kopyalamak için görünümler arasında kolayca sürükleyip bırakabilirsiniz. Dolphin'in sağ tıklama menüsü, diğer birçok şeyin yanı sıra dosyaları sıkıştırmanıza, paylaşmanıza ve çoğaltmanıza olanak tanıyan birçok hızlı işlem sağlar. Ayrıca kendi özel eylemlerinizi de ekleyebilirsiniz.</p> <p xml:lang="uk">У Dolphin передбачено багато можливостей, які роблять вашу роботу продуктивнішою та заощаджують час. За допомогою можливостей використання декількох вкладок та поділу панелей перегляду ви можете переглядати вміст декількох тек одночасно і без проблем перетягувати і скидати пункти файлів і тек між різними панелями з метою копіювання або пересування. У контекстному меню Dolphin, яке можна викликати клацанням правою кнопкою миші, серед іншого, передбачено багато пунктів для швидкого доступу до стискання, оприлюднення та дублювання файлів. Крім того, ви можете додавати туди власні нетипові пункти дій.</p> <p xml:lang="vi">Dolphin bao gồm nhiều tính năng năng suất sẽ giúp bạn tiết kiệm thời gian. Các tính năng đa thẻ và khung xem chia đôi cho phép điều hướng nhiều thư mục cùng lúc, và bạn có thể dễ dàng kéo thả tệp giữa các khung xem để chuyển hay chép chúng. Trình đơn bấm phải của Dolphin cung cấp nhiều hành động nhanh gọn cho phép bạn nén, chia sẻ, và tạo bản sao cho các tệp, cùng nhiều việc khác nữa. Bạn cũng có thể thêm các hành động tự chọn của mình.</p> @@ -184,6 +188,7 @@ <p xml:lang="sk">Delfín je veľmi ľahký, ale zároveň ho môžete prispôsobiť svojim konkrétnym potrebám. To znamená, že správu súborov môžete vykonávať presne tak, ako chcete. Dolphin podporuje tri rôzne režimy zobrazenia: klasické zobrazenie všetkých súborov v mriežke, podrobnejšie zobrazenie a stromové zobrazenie. Môžete tiež nakonfigurovať väčšinu správania Dolphin.</p> <p xml:lang="sl">Dolphin je zelo lahek, hkrati pa ga lahko prilagodite svojim posebnim potrebam. To pomeni, da lahko izvajate upravljanje datotek natanko tako, kot želite. Dolphin podpira tri različne načine pogleda: klasičen mrežni pogled vseh datotek, podrobnejši pogled in drevesni pogled. Večino vedenja Dolphina lahko tudi nastavljate.</p> <p xml:lang="sv">Dolphin är mycket lättviktigt, men samtidigt kan du anpassa det för dina specifika behov. Det betyder att du kan utföra filhantering precis på det sätt du vill. Dolphin stöder tre olika visningsmetoder: en klassisk rutnätsvy av alla filer, en mer detaljerad vy och en trädvy. Du kan också anpassa det mesta av Dolphins beteende.</p> + <p xml:lang="ta">டால்பின் மிகவும் சிக்கனமானது, ஆனால் அதே நேரத்தில், உங்கள் தேவைகளுக்கேற்ப அதை மாற்றி அமைக்கலாம். அதாவது, நீங்கள் விரும்பும் விதத்திலெயே உங்கள் கோப்புகளை நீங்கள் நிர்வகிக்கலாம். டால்பின் மூன்று காட்சிமுறைகளை ஆதரிக்கும்: சாதாரணமான காட்சிமுறை, அதைவிட விவரமான காட்சிமுறை, மற்றும் கிளைப்பட (tree) காட்சிமுறை. டால்பினின் நடத்தையின் பெரும்பாலான அம்சங்களை நீங்கள் மாற்றலாம்.</p> <p xml:lang="tr">Dolphin çok hafiftir, ancak aynı zamanda onu özel ihtiyaçlarınıza göre uyarlayabilirsiniz. Bu, dosya yönetiminizi tam olarak istediğiniz şekilde gerçekleştirebileceğiniz anlamına gelir. Dolphin üç farklı görünüm kipini destekler: tüm dosyaların klasik bir ızgara görünümü, daha ayrıntılı bir görünüm ve bir ağaç görünümü. Ayrıca, Dolphin'in davranışlarının çoğunu yapılandırabilirsiniz.</p> <p xml:lang="uk">Dolphin є дуже невибагливим до ресурсів. Втім, ви можете адаптувати програму до ваших потреб. Це означає, що ви можете здійснювати керування файлами саме так, як вам того хочеться. У Dolphin передбачено три різних режими перегляду: класичний перегляд таблицею усіх файлів, режим докладного перегляду та ієрархічний перегляд. Більшу частину характеристик роботи програми можна налаштувати Dolphin.</p> <p xml:lang="vi">Dolphin rất nhẹ, nhưng đồng thời bạn có thể điều chỉnh nó theo các nhu cầu cụ thể của mình. Điều này nghĩa là bạn có thể thực hiện việc quản lí tệp đúng như cách bạn muốn. Dolphin hỗ trợ ba chế độ xem khác nhau: một khung xem tất cả các tệp ở dạng lưới cổ điển, một khung xem chi tiết hơn, và một khung xem dạng cây. Bạn cũng có thể cấu hình hầu hết tất cả các ứng xử của Dolphin.</p> @@ -213,6 +218,7 @@ <p xml:lang="sk">Dolphin dokáže zobraziť súbory a priečinky z mnohých internetových cloudových služieb a iných vzdialených počítačov, akoby sa nachádzali priamo na vašej pracovnej ploche.</p> <p xml:lang="sl">Dolphin lahko prikazuje datoteke in mape iz številnih internetnih storitev v oblaku in druge oddaljene računalnike, kot da bi bili na namizju.</p> <p xml:lang="sv">Dolphin kan visa filer och kataloger från många molntjänster på Internet och från andra datorer, som om de fanns direkt på ditt eget skrivbord.</p> + <p xml:lang="ta">இணையத் தேக்கக (cloud storage) சேவைகளிலோ தொலைக் கணினிகளிலோ உள்ள கோப்புகளை, உங்கள் கணினியில் இருப்பது போல டால்பினால் காட்ட முடியும்.</p> <p xml:lang="tr">Dolphin, birçok İnternet bulut hizmetinden ve diğer uzak makinelerden dosya ve klasörleri sanki masaüstünüzdeymiş gibi görüntüleyebilir.</p> <p xml:lang="uk">Dolphin здатен показувати файли і теки із багатьох «хмарних» служб інтернету та віддалених комп'ютерів так, наче усі ці дані зберігаються на вашому робочому комп'ютері.</p> <p xml:lang="vi">Dolphin có thể hiển thị tệp và thư mục từ nhiều dịch vụ đám mây Liên Mạng và các máy ở xa khác như thể chúng ở ngay trên máy tính của bạn vậy.</p> @@ -242,6 +248,7 @@ <p xml:lang="sk">Dolphin tiež prichádza s integrovaným terminálom, ktorý umožňuje spúšťať príkazy v aktuálnom priečinku. Možnosti Dolphinu môžete ešte rozšíriť pomocou výkonných doplnkov, ktoré ho prispôsobia vášmu pracovnému toku. Integračný doplnok git môžete použiť na interakciu s úložiskami git, alebo doplnok Nextcloud na synchronizáciu súborov online a oveľa viac.</p> <p xml:lang="sl">Dolphin ima tudi integriran terminal, ki vam omogoča zagon ukazov v trenutni mapi. Zmogljivosti Dolphina lahko razširite še močnimi vtičniki, ki ga prilagodijo vašemu delovnemu toku. Lahko uporabite git integracijski vtičnik za interakcijo s skladišči git ali vtičnik Nextcloud za sinhronizacijo datotek v spletu in še veliko več.</p> <p xml:lang="sv">Dolphin levereras också med en integrerad terminal som låter dig köra kommandon i den aktuella katalogen. Du kan utöka Dolphins funktioner ytterligare med kraftfulla insticksprogram för att anpassa programmet till ditt arbetsflöde. Du kan använda insticksprogrammet git-integrering för att komma åt git-arkiv, eller insticksprogrammet Nextcloud för att synkronisera filer på nätet, med mera.</p> + <p xml:lang="ta">தற்போதைய அடைவில் நீங்கள் விரும்பும் கட்டளைகளை இயக்க உதவும் உள்ளமைந்த முனையத்தை டால்பின் கொண்டுள்ளது. பல ஆற்றல்மிக்க செருகுநிரல்களைக் கொண்டு நீங்கள் டால்பினின் இயலுமைகளை உங்கள் தேவைக்கேற்ப மேம்படுத்தலாம். உதாரணத்துக்கு git ஒருங்கிணைப்பு செருகுநிரலைக் கொண்டு git repo-களை நீங்கள் கையாளலாம், அல்லது Nextcloud செருகுநிரலைக் கொண்டு உங்கள் கோப்புகளை இணையத்தில் ஒத்திசைக்கலாம்.</p> <p xml:lang="tr">Dolphin ayrıca mevcut klasörde komutları çalıştırmanıza izin veren tümleşik bir uçbirim ile birlikte gelir. İş akışınıza uyarlamak için güçlü eklentilerle Dolphin'in yeteneklerini daha da genişletebilirsiniz. Git bütünleştirme eklentisini git depolarıyla etkileşime girmek veya Nextcloud eklentisini dosyalarınızı çevrimiçi olarak eşitlemek ve çok daha fazlasını kullanabilirsiniz.</p> <p xml:lang="uk">Також до Dolphin вбудовано термінал, за допомогою якого ви можете виконувати команди у поточній теці. Ви можете розширити можливості Dolphin за допомогою потужних додатків з метою пристосування програми до ваших робочих процедур. Ви можете скористатися додатком інтеграції із git для роботи зі сховищами git або додатком Nextcloud для синхронізації ваших файлів зі сховищами даних в інтернеті тощо.</p> <p xml:lang="vi">Dolphin còn đi kèm với một dòng lệnh tích hợp, cho phép bạn chạy lệnh ở thư mục hiện tại. Bạn thậm chí có thể mở rộng khả năng của Dolphin thêm nữa bằng các phần cài cắm mạnh mẽ để đáp ứng với cách làm việc của bạn. Bạn có thể dùng phần cài cắm tích hợp git để tương tác với các kho git, hay phần cài cắm Nextcloud để đồng bộ trực tuyến các tệp của bạn, và còn nhiều nữa.</p> @@ -289,13 +296,71 @@ <caption xml:lang="sk">Správa súborov v Dolphin</caption> <caption xml:lang="sl">Upravljanje datotek v Dolphinu</caption> <caption xml:lang="sv">Filhantering i Dolphin</caption> + <caption xml:lang="ta">டால்பினால் கோப்புகளை கையாளுதல்</caption> <caption xml:lang="tr">Dolphin'de dosya yönetimi</caption> <caption xml:lang="uk">Керування файлами у Dolphin</caption> <caption xml:lang="vi">Quản lí tệp trong Dolphin</caption> <caption xml:lang="x-test">xxFile management in Dolphinxx</caption> <caption xml:lang="zh-CN">用 Dolphin 进行文件管理</caption> <caption xml:lang="zh-TW">在 Dolphin 管理檔案</caption> - <image>https://kde.org/images/screenshots/dolphin.png</image> + <image>https://cdn.kde.org/screenshots/dolphin/dolphin.png</image> + </screenshot> + <screenshot type="default"> + <caption>Embedded Terminal in Dolphin</caption> + <caption xml:lang="az">Dolphin daxilinə yerləşdirilmiş Terminal</caption> + <caption xml:lang="ca">Terminal incrustat en el Dolphin</caption> + <caption xml:lang="cs">Zabudovaný terminál v Dolphinu</caption> + <caption xml:lang="de">Eingebettetes Terminal in Dolphin</caption> + <caption xml:lang="el">Ενσωματωμένο τερματικό στο Dolphin</caption> + <caption xml:lang="en-GB">Embedded Terminal in Dolphin</caption> + <caption xml:lang="es">Terminal integrado en Dolphin</caption> + <caption xml:lang="eu">Dolphinen txertatutako terminala</caption> + <caption xml:lang="fi">Upotettu pääte Dolphinissa</caption> + <caption xml:lang="fr">Terminal intégré dans Dolphin</caption> + <caption xml:lang="ia">Terminal incorporate in Dolphin</caption> + <caption xml:lang="it">Terminale integrato in Dolphin</caption> + <caption xml:lang="ko">Dolphin에 내장된 터미널</caption> + <caption xml:lang="nl">Ingebedde terminal in Dolphin</caption> + <caption xml:lang="pl">Osadzony terminal w Dolphinie</caption> + <caption xml:lang="pt">Terminal Incorporado no Dolphin</caption> + <caption xml:lang="pt-BR">Terminal incorporado no Dolphin</caption> + <caption xml:lang="ru">Встроенный терминал</caption> + <caption xml:lang="sk">Zabudovaný terminál v Dolphin</caption> + <caption xml:lang="sl">Vdelani teminal v Dolphinu</caption> + <caption xml:lang="sv">Inbäddad terminal i Dolphin</caption> + <caption xml:lang="uk">Вбудований термінал у Dolphin</caption> + <caption xml:lang="vi">Dòng lệnh nhúng trong Dolphin</caption> + <caption xml:lang="x-test">xxEmbedded Terminal in Dolphinxx</caption> + <caption xml:lang="zh-CN">Dolphin 的内嵌命令行终端</caption> + <image>https://cdn.kde.org/screenshots/dolphin/dolphin-terminal.png</image> + </screenshot> + <screenshot> + <caption>Dolphin lets you configure your file manager exactly how you want</caption> + <caption xml:lang="az">Dolphin, fayl bələdçisini tam istədiyiniz kimi tənzimləməyə imkan verir</caption> + <caption xml:lang="ca">El Dolphin permet configurar el gestor de fitxers exactament com es vol</caption> + <caption xml:lang="de">Mit Dolphin können Sie Ihre Dateiverwaltung genau so einrichten, wie Sie es wünschen</caption> + <caption xml:lang="el">Με το Dolphin διαμορφώνετε τον διαχειριστή αρχείων ακριβώς όπως τον θέλετε</caption> + <caption xml:lang="en-GB">Dolphin lets you configure your file manager exactly how you want</caption> + <caption xml:lang="es">Dolphin le permite configurar el gestor de archivos exactamente como lo desee</caption> + <caption xml:lang="eu">Dolphinek zure fitxategi-kudeatzailea nahi duzun eran konfiguratzen uzten dizu</caption> + <caption xml:lang="fi">Dolphinilla voit tehdä tiedostonhallintaa juuri kuten haluat</caption> + <caption xml:lang="fr">Dolphin vous permet de configurer votre gestionnaire de fichiers, exactement comme vous le souhaitez.</caption> + <caption xml:lang="ia">Dolphin te permitte configurar tu gerente de file exactemente como tu lo vole</caption> + <caption xml:lang="it">Dolphin ti consente di configurare il tuo gestore file esattamente come desideri</caption> + <caption xml:lang="ko">Dolphin은 사용하고 싶은 대로 설정할 수 있습니다</caption> + <caption xml:lang="nl">Dolphin laat u uw bestandsbeheerder exact configureren zoals u dat wilt</caption> + <caption xml:lang="pl">Dolphin umożliwia ustawienie zarządzania plikami dokładnie tak, jak tego chcesz</caption> + <caption xml:lang="pt">O Dolphin permite-lhe configurar o seu gestor de ficheiros exactamente como pretende</caption> + <caption xml:lang="pt-BR">O Dolphin permite a você configurar seu gerenciador de arquivos exatamente como você quer</caption> + <caption xml:lang="ru">Диспетчер файлов Dolphin позволяет настроить тонко настроить своё поведение</caption> + <caption xml:lang="sk">Dolphin vám umožňuje konfigurovať správcu súborov presne podľa vašich predstáv</caption> + <caption xml:lang="sl">Dolphin vam omogoča sestaviti upravljalnik datotek natančno tako kot želite</caption> + <caption xml:lang="sv">Dolphin låter dig anpassa din filhanterare exakt som du vill</caption> + <caption xml:lang="uk">Ви можете налаштувати вашу програму для керування файлами Dolphin так, щоб вона працювала саме так, як ви цього хочете</caption> + <caption xml:lang="vi">Dolphin cho phép bạn cấu hình trình quản lí tệp đúng như bạn muốn</caption> + <caption xml:lang="x-test">xxDolphin lets you configure your file manager exactly how you wantxx</caption> + <caption xml:lang="zh-CN">Dolphin 让您可以随心所欲地对文件管理器进行配置</caption> + <image>https://cdn.kde.org/screenshots/dolphin/dolphin-settings.png</image> </screenshot> </screenshots> <project_group>KDE</project_group> diff --git a/src/org.kde.dolphin.desktop b/src/org.kde.dolphin.desktop index 7020ef70a..63509b476 100755 --- a/src/org.kde.dolphin.desktop +++ b/src/org.kde.dolphin.desktop @@ -43,6 +43,7 @@ Name[sr@ijekavian]=Делфин Name[sr@ijekavianlatin]=Dolphin Name[sr@latin]=Dolphin Name[sv]=Dolphin +Name[ta]=டால்பின் Name[tr]=Dolphin Name[uk]=Dolphin Name[vi]=Dolphin @@ -98,6 +99,7 @@ GenericName[sr@ijekavian]=Менаџер фајлова GenericName[sr@ijekavianlatin]=Menadžer fajlova GenericName[sr@latin]=Menadžer fajlova GenericName[sv]=Filhanterare +GenericName[ta]=கோப்பு உலாவி GenericName[tr]=Dosya Yöneticisi GenericName[uk]=Менеджер файлів GenericName[vi]=Trình quản lí tệp diff --git a/src/panels/information/informationpanel.cpp b/src/panels/information/informationpanel.cpp index f843e7f46..9a6fc3708 100644 --- a/src/panels/information/informationpanel.cpp +++ b/src/panels/information/informationpanel.cpp @@ -242,6 +242,7 @@ void InformationPanel::showItemInfo() connect(m_folderStatJob, &KIO::Job::result, this, &InformationPanel::slotFolderStatFinished); } else { + m_shownUrl = item.url(); m_content->showItem(item); } } @@ -303,6 +304,15 @@ void InformationPanel::slotFilesAdded(const QString& directory) } } +void InformationPanel::slotFilesItemChanged(const KFileItemList &changedFileItems) +{ + const auto item = changedFileItems.findByUrl(m_shownUrl); + if (!item.isNull()) { + m_fileItem = item; + showItemInfo(); + } +} + void InformationPanel::slotFilesChanged(const QStringList& files) { for (const QString& fileName : files) { diff --git a/src/panels/information/informationpanel.h b/src/panels/information/informationpanel.h index debd88e46..d7f89bc9c 100644 --- a/src/panels/information/informationpanel.h +++ b/src/panels/information/informationpanel.h @@ -46,6 +46,8 @@ public Q_SLOTS: */ void requestDelayedItemInfo(const KFileItem& item); + void slotFilesItemChanged(const KFileItemList &changedFileItems); + protected: /** @see Panel::urlChanged() */ bool urlChanged() override; diff --git a/src/panels/places/dolphin_placespanelsettings.kcfg b/src/panels/places/dolphin_placespanelsettings.kcfg index b2ef8e574..db0ac9495 100644 --- a/src/panels/places/dolphin_placespanelsettings.kcfg +++ b/src/panels/places/dolphin_placespanelsettings.kcfg @@ -4,11 +4,12 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0 http://www.kde.org/standards/kcfg/1.0/kcfg.xsd"> + <include>kiconloader.h</include> <kcfgfile name="dolphinrc"/> <group name="PlacesPanel"> <entry name="IconSize" type="Int"> <label>Size of icons in the Places Panel (-1 means "use the style's small size")</label> - <default>-1</default> + <default code="true">KIconLoader::SizeSmallMedium</default> </entry> </group> </kcfg> diff --git a/src/panels/places/placespanel.cpp b/src/panels/places/placespanel.cpp index d49ad39ec..1f5f0260f 100644 --- a/src/panels/places/placespanel.cpp +++ b/src/panels/places/placespanel.cpp @@ -23,6 +23,7 @@ #include "placesview.h" #include "trash/dolphintrash.h" #include "views/draganddrophelper.h" +#include "settings/dolphinsettingsdialog.h" #include <KFilePlaceEditDialog> #include <KFilePlacesModel> @@ -181,6 +182,7 @@ void PlacesPanel::slotItemContextMenuRequested(int index, const QPointF& pos) QMenu menu(this); QAction* emptyTrashAction = nullptr; + QAction* configureTrashAction = nullptr; QAction* editAction = nullptr; QAction* teardownAction = nullptr; QAction* ejectAction = nullptr; @@ -200,7 +202,7 @@ void PlacesPanel::slotItemContextMenuRequested(int index, const QPointF& pos) if (item->url().isLocalFile()) { propertiesAction = menu.addAction(QIcon::fromTheme(QStringLiteral("document-properties")), i18nc("@action:inmenu", "Properties")); } - if (!isDevice && !isTrash) { + if (!isDevice) { menu.addSeparator(); } @@ -236,6 +238,10 @@ void PlacesPanel::slotItemContextMenuRequested(int index, const QPointF& pos) } } + if (isTrash) { + configureTrashAction = menu.addAction(QIcon::fromTheme(QStringLiteral("configure")), i18nc("@action:inmenu", "Configure Trash...")); + } + if (!isDevice) { editAction = menu.addAction(QIcon::fromTheme(QStringLiteral("edit-entry")), i18nc("@item:inmenu", "Edit...")); } @@ -255,6 +261,11 @@ void PlacesPanel::slotItemContextMenuRequested(int index, const QPointF& pos) if (action) { if (action == emptyTrashAction) { Trash::empty(this); + } else if (action == configureTrashAction) { + DolphinSettingsDialog* settingsDialog = new DolphinSettingsDialog(item->url(), this); + settingsDialog->setCurrentPage(settingsDialog->trashSettings); + settingsDialog->setAttribute(Qt::WA_DeleteOnClose); + settingsDialog->show(); } else { // The index might have changed if devices were added/removed while // the context menu was open. diff --git a/src/panels/places/placesview.cpp b/src/panels/places/placesview.cpp index 5214f47dc..50446d44d 100644 --- a/src/panels/places/placesview.cpp +++ b/src/panels/places/placesview.cpp @@ -1,6 +1,5 @@ /* * SPDX-FileCopyrightText: 2012 Frank Reininghaus <[email protected]> - * SPDX-FileCopyrightText: 2021 Harald Sitter <[email protected]> * * SPDX-License-Identifier: GPL-2.0-or-later */ @@ -12,10 +11,6 @@ PlacesView::PlacesView(QGraphicsWidget* parent) : KStandardItemListView(parent) { - KItemListStyleOption option = styleOption(); - option.padding = 4; - setStyleOption(option); - const int iconSize = PlacesPanelSettings::iconSize(); if (iconSize >= 0) { setIconSize(iconSize); diff --git a/src/search/dolphinfacetswidget.cpp b/src/search/dolphinfacetswidget.cpp index e8a43101f..db53d595f 100644 --- a/src/search/dolphinfacetswidget.cpp +++ b/src/search/dolphinfacetswidget.cpp @@ -54,6 +54,12 @@ DolphinFacetsWidget::DolphinFacetsWidget(QWidget* parent) : m_ratingSelector->addItem(QIcon::fromTheme(QStringLiteral("starred-symbolic")), i18nc("@item:inlistbox", "Highest Rating"), 5); initComboBox(m_ratingSelector); + m_clearTagsAction = new QAction(QIcon::fromTheme(QStringLiteral("edit-clear-all")), i18nc("@action:inmenu", "Clear Selection"), this); + connect(m_clearTagsAction, &QAction::triggered, this, [this]() { + resetSearchTags(); + Q_EMIT facetChanged(); + }); + m_tagsSelector = new QToolButton(this); m_tagsSelector->setIcon(QIcon::fromTheme(QStringLiteral("tag"))); m_tagsSelector->setMenu(new QMenu(this)); @@ -98,9 +104,7 @@ void DolphinFacetsWidget::resetSearchTerms() m_dateSelector->setCurrentIndex(0); m_ratingSelector->setCurrentIndex(0); - m_searchTags = QStringList(); - updateTagsSelector(); - updateTagsMenu(); + resetSearchTags(); } QStringList DolphinFacetsWidget::searchTerms() const @@ -219,6 +223,13 @@ void DolphinFacetsWidget::removeSearchTag(const QString& tag) updateTagsSelector(); } +void DolphinFacetsWidget::resetSearchTags() +{ + m_searchTags = QStringList(); + updateTagsSelector(); + updateTagsMenu(); +} + void DolphinFacetsWidget::initComboBox(QComboBox* combo) { combo->setFrame(false); @@ -241,6 +252,7 @@ void DolphinFacetsWidget::updateTagsSelector() } m_tagsSelector->setEnabled(isEnabled() && (hasListedTags || hasSelectedTags)); + m_clearTagsAction->setEnabled(hasSelectedTags); } void DolphinFacetsWidget::updateTagsMenu() @@ -253,7 +265,8 @@ void DolphinFacetsWidget::updateTagsMenu() void DolphinFacetsWidget::updateTagsMenuItems(const QUrl&, const KFileItemList& items) { - m_tagsSelector->menu()->clear(); + QMenu *tagsMenu = m_tagsSelector->menu(); + tagsMenu->clear(); QStringList allTags = QStringList(m_searchTags); for (const KFileItem &item: items) { @@ -265,7 +278,7 @@ void DolphinFacetsWidget::updateTagsMenuItems(const QUrl&, const KFileItemList& const bool onlyOneTag = allTags.count() == 1; for (const QString& tagName : qAsConst(allTags)) { - QAction* action = m_tagsSelector->menu()->addAction(QIcon::fromTheme(QStringLiteral("tag")), tagName); + QAction *action = tagsMenu->addAction(QIcon::fromTheme(QStringLiteral("tag")), tagName); action->setCheckable(true); action->setChecked(m_searchTags.contains(tagName)); @@ -283,5 +296,10 @@ void DolphinFacetsWidget::updateTagsMenuItems(const QUrl&, const KFileItemList& }); } + if (allTags.count() > 1) { + tagsMenu->addSeparator(); + tagsMenu->addAction(m_clearTagsAction); + } + updateTagsSelector(); } diff --git a/src/search/dolphinfacetswidget.h b/src/search/dolphinfacetswidget.h index 83345b344..3e3b0f264 100644 --- a/src/search/dolphinfacetswidget.h +++ b/src/search/dolphinfacetswidget.h @@ -63,6 +63,7 @@ private: void setTimespan(const QDate& date); void addSearchTag(const QString& tag); void removeSearchTag(const QString& tag); + void resetSearchTags(); void initComboBox(QComboBox* combo); void updateTagsSelector(); @@ -75,6 +76,7 @@ private: QStringList m_searchTags; KCoreDirLister m_tagsLister; + QAction *m_clearTagsAction; }; #endif diff --git a/src/settings/contextmenu/contextmenusettingspage.cpp b/src/settings/contextmenu/contextmenusettingspage.cpp index e04a7c65f..c92bad43e 100644 --- a/src/settings/contextmenu/contextmenusettingspage.cpp +++ b/src/settings/contextmenu/contextmenusettingspage.cpp @@ -21,6 +21,8 @@ #include <KServiceTypeTrader> #include <KDesktopFileActions> +#include <kio_version.h> + #include <QGridLayout> #include <QLabel> #include <QListWidget> @@ -120,6 +122,8 @@ bool ContextMenuSettingsPage::entryVisible(const QString& id) return ContextMenuSettings::showCopyLocation(); } else if (id == "duplicate") { return ContextMenuSettings::showDuplicateHere(); + } else if (id == "open_terminal") { + return ContextMenuSettings::showOpenTerminal(); } return false; } @@ -140,6 +144,8 @@ void ContextMenuSettingsPage::setEntryVisible(const QString& id, bool visible) ContextMenuSettings::setShowCopyLocation(visible); } else if (id == "duplicate") { ContextMenuSettings::setShowDuplicateHere(visible); + } else if (id == "open_terminal") { + ContextMenuSettings::setShowOpenTerminal(visible); } } @@ -274,7 +280,8 @@ void ContextMenuSettingsPage::loadServices() } } - // Load service plugins that implement the KFileItemActionPlugin interface + // Load service plugins, this is deprecated in KIO 5.82 +#if KIO_VERSION < QT_VERSION_CHECK(6, 0, 0) const KService::List pluginServices = KServiceTypeTrader::self()->query(QStringLiteral("KFileItemAction/Plugin")); for (const KService::Ptr &service : pluginServices) { const QString desktopEntryName = service->desktopEntryName(); @@ -283,11 +290,10 @@ void ContextMenuSettingsPage::loadServices() addRow(service->icon(), service->name(), desktopEntryName, checked); } } +#endif // Load JSON-based plugins that implement the KFileItemActionPlugin interface - const auto jsonPlugins = KPluginLoader::findPlugins(QStringLiteral("kf5/kfileitemaction"), [](const KPluginMetaData& metaData) { - return metaData.serviceTypes().contains(QLatin1String("KFileItemAction/Plugin")); - }); + const auto jsonPlugins = KPluginLoader::findPlugins(QStringLiteral("kf5/kfileitemaction")); for (const auto &jsonMetadata : jsonPlugins) { const QString desktopEntryName = jsonMetadata.pluginId(); @@ -306,9 +312,24 @@ void ContextMenuSettingsPage::loadVersionControlSystems() const QStringList enabledPlugins = VersionControlSettings::enabledPlugins(); // Create a checkbox for each available version control plugin + QSet<QString> loadedPlugins; + + const QVector<KPluginMetaData> plugins = KPluginLoader::findPlugins(QStringLiteral("dolphin/vcs")); + for (const auto &plugin : plugins) { + const QString pluginName = plugin.name(); + addRow(QStringLiteral("code-class"), + pluginName, + VersionControlServicePrefix + pluginName, + enabledPlugins.contains(pluginName)); + loadedPlugins += pluginName; + } + const KService::List pluginServices = KServiceTypeTrader::self()->query(QStringLiteral("FileViewVersionControlPlugin")); for (const auto &plugin : pluginServices) { const QString pluginName = plugin->name(); + if (loadedPlugins.contains(pluginName)) { + continue; + } addRow(QStringLiteral("code-class"), pluginName, VersionControlServicePrefix + pluginName, diff --git a/src/settings/dolphin_contextmenusettings.kcfg b/src/settings/dolphin_contextmenusettings.kcfg index 9e7056551..44fd83513 100644 --- a/src/settings/dolphin_contextmenusettings.kcfg +++ b/src/settings/dolphin_contextmenusettings.kcfg @@ -38,5 +38,9 @@ <label>Show 'Duplicate Here' in context menu.</label> <default>true</default> </entry> + <entry name="ShowOpenTerminal" type="Bool"> + <label>Show 'Open Terminal' in context menu.</label> + <default>true</default> + </entry> </group> </kcfg> diff --git a/src/settings/dolphin_generalsettings.kcfg b/src/settings/dolphin_generalsettings.kcfg index bc1cf72aa..728d11634 100644 --- a/src/settings/dolphin_generalsettings.kcfg +++ b/src/settings/dolphin_generalsettings.kcfg @@ -101,6 +101,10 @@ <label>Use auto-expanding folders for all view types</label> <default>false</default> </entry> + <entry name="ShowStatusBar" type="Bool"> + <label>Show the statusbar</label> + <default>true</default> + </entry> <entry name="ShowZoomSlider" type="Bool"> <label>Show zoom slider in the statusbar</label> <default>true</default> diff --git a/src/settings/dolphinsettingsdialog.cpp b/src/settings/dolphinsettingsdialog.cpp index 4d759c911..281cb7ba5 100644 --- a/src/settings/dolphinsettingsdialog.cpp +++ b/src/settings/dolphinsettingsdialog.cpp @@ -85,7 +85,8 @@ DolphinSettingsDialog::DolphinSettingsDialog(const QUrl& url, QWidget* parent, K QStringLiteral("open_in_new_tab"), QStringLiteral("open_in_new_window"), QStringLiteral("copy_location"), - QStringLiteral("duplicate") + QStringLiteral("duplicate"), + QStringLiteral("open_terminal"), }); KPageWidgetItem* contextMenuSettingsFrame = addPage(contextMenuSettingsPage, i18nc("@title:group", "Context Menu")); @@ -98,9 +99,9 @@ DolphinSettingsDialog::DolphinSettingsDialog(const QUrl& url, QWidget* parent, K trashSettingsPage = createTrashSettingsPage(this); #endif if (trashSettingsPage) { - KPageWidgetItem* trashSettingsFrame = addPage(trashSettingsPage, + trashSettings = addPage(trashSettingsPage, i18nc("@title:group", "Trash")); - trashSettingsFrame->setIcon(QIcon::fromTheme(QStringLiteral("user-trash"))); + trashSettings->setIcon(QIcon::fromTheme(QStringLiteral("user-trash"))); connect(trashSettingsPage, &TrashSettingsPage::changed, this, &DolphinSettingsDialog::enableApply); } diff --git a/src/settings/dolphinsettingsdialog.h b/src/settings/dolphinsettingsdialog.h index 65ce95274..f9a5652ea 100644 --- a/src/settings/dolphinsettingsdialog.h +++ b/src/settings/dolphinsettingsdialog.h @@ -26,6 +26,8 @@ public: explicit DolphinSettingsDialog(const QUrl& url, QWidget* parent = nullptr, KActionCollection* actions = {}); ~DolphinSettingsDialog() override; + KPageWidgetItem* trashSettings; + Q_SIGNALS: void settingsChanged(); diff --git a/src/settings/general/statusbarsettingspage.cpp b/src/settings/general/statusbarsettingspage.cpp index ddefa1a40..9d90a64fd 100644 --- a/src/settings/general/statusbarsettingspage.cpp +++ b/src/settings/general/statusbarsettingspage.cpp @@ -15,19 +15,24 @@ StatusBarSettingsPage::StatusBarSettingsPage(QWidget* parent) : SettingsPageBase(parent), + m_showStatusBar(nullptr), m_showZoomSlider(nullptr), m_showSpaceInfo(nullptr) { + m_showStatusBar = new QCheckBox(i18nc("@option:check", "Show status bar"), this); m_showZoomSlider = new QCheckBox(i18nc("@option:check", "Show zoom slider"), this); m_showSpaceInfo = new QCheckBox(i18nc("@option:check", "Show space information"), this); QVBoxLayout* topLayout = new QVBoxLayout(this); + topLayout->addWidget(m_showStatusBar); topLayout->addWidget(m_showZoomSlider); topLayout->addWidget(m_showSpaceInfo); topLayout->addStretch(); loadSettings(); + connect(m_showStatusBar, &QCheckBox::toggled, this, &StatusBarSettingsPage::changed); + connect(m_showStatusBar, &QCheckBox::toggled, this, &StatusBarSettingsPage::onShowStatusBarToggled); connect(m_showZoomSlider, &QCheckBox::toggled, this, &StatusBarSettingsPage::changed); connect(m_showSpaceInfo, &QCheckBox::toggled, this, &StatusBarSettingsPage::changed); } @@ -36,9 +41,17 @@ StatusBarSettingsPage::~StatusBarSettingsPage() { } +void StatusBarSettingsPage::onShowStatusBarToggled() +{ + const bool checked = m_showStatusBar->isChecked(); + m_showZoomSlider->setEnabled(checked); + m_showSpaceInfo->setEnabled(checked); +} + void StatusBarSettingsPage::applySettings() { GeneralSettings* settings = GeneralSettings::self(); + settings->setShowStatusBar(m_showStatusBar->isChecked()); settings->setShowZoomSlider(m_showZoomSlider->isChecked()); settings->setShowSpaceInfo(m_showSpaceInfo->isChecked()); settings->save(); @@ -54,7 +67,10 @@ void StatusBarSettingsPage::restoreDefaults() void StatusBarSettingsPage::loadSettings() { + m_showStatusBar->setChecked(GeneralSettings::showStatusBar()); m_showZoomSlider->setChecked(GeneralSettings::showZoomSlider()); m_showSpaceInfo->setChecked(GeneralSettings::showSpaceInfo()); + + onShowStatusBarToggled(); } diff --git a/src/settings/general/statusbarsettingspage.h b/src/settings/general/statusbarsettingspage.h index 3c5e7c2ad..af8e06164 100644 --- a/src/settings/general/statusbarsettingspage.h +++ b/src/settings/general/statusbarsettingspage.h @@ -29,8 +29,10 @@ public: private: void loadSettings(); + void onShowStatusBarToggled(); private: + QCheckBox* m_showStatusBar; QCheckBox* m_showZoomSlider; QCheckBox* m_showSpaceInfo; }; diff --git a/src/settings/kcm/kcmdolphingeneral.desktop b/src/settings/kcm/kcmdolphingeneral.desktop index 172cdcab2..9753285fa 100644 --- a/src/settings/kcm/kcmdolphingeneral.desktop +++ b/src/settings/kcm/kcmdolphingeneral.desktop @@ -42,6 +42,7 @@ Name[sr@ijekavian]=Делфиново опште Name[sr@ijekavianlatin]=Dolphinovo opšte Name[sr@latin]=Dolphinovo opšte Name[sv]=Dolphin allmänt +Name[ta]=டால்பின் பொது அமைப்புகள் Name[tr]=Dolphin Genel Name[uk]=«Загальне» Dolphin Name[vi]=Chung cho Dolphin @@ -91,6 +92,7 @@ Comment[sr@ijekavian]=Овај сервис омогућава подешава� Comment[sr@ijekavianlatin]=Ovaj servis omogućava podešavanje opštih Dolphinovih postavki. Comment[sr@latin]=Ovaj servis omogućava podešavanje opštih Dolphinovih postavki. Comment[sv]=Den här tjänsten låter dig anpassa allmänna inställningar i Dolphin. +Comment[ta]=டால்பினின் பொது அமைப்புகளை அமைக்க இந்த சேவை உதவும். Comment[tr]=Bu servis genel Dolphin ayarlarını yapılandırmanızı sağlar. Comment[uk]=Ця служба надасть змогу налаштувати загальні параметри Dolphin. Comment[vi]=Dịch vụ này cho phép cấu hình các thiết lập chung của Dolphin. @@ -150,6 +152,7 @@ Name[sr@ijekavian]=Опште Name[sr@ijekavianlatin]=Opšte Name[sr@latin]=Opšte Name[sv]=Allmänt +Name[ta]=பொது Name[tr]=Genel Name[uk]=Загальне Name[vi]=Chung @@ -199,6 +202,7 @@ Comment[sr@ijekavian]=Подешавање општих поставки мен� Comment[sr@ijekavianlatin]=Podešavanje opštih postavki menadžera fajlova Comment[sr@latin]=Podešavanje opštih postavki menadžera fajlova Comment[sv]=Anpassa filhanterarens allmänna inställningar +Comment[ta]=பொதுவான கோப்பு மேலாளி அமைப்புகளை அமையுங்கள் Comment[tr]=Genel dosya yöneticisi ayarlarını yapılandır Comment[uk]=Налаштувати загальні параметри менеджера файлів Comment[vi]=Cấu hình các thiết lập chung cho trình quản lí tệp @@ -248,6 +252,7 @@ X-KDE-Keywords[sr@ijekavian]=file manager,менаџер фајлова X-KDE-Keywords[sr@ijekavianlatin]=file manager,menadžer fajlova X-KDE-Keywords[sr@latin]=file manager,menadžer fajlova X-KDE-Keywords[sv]=filhanterare +X-KDE-Keywords[ta]=file manager,கோப்பு மேலாளர், கோப்பு நிர்வாகி, கோப்பு உலாவி X-KDE-Keywords[tr]=dosya yöneticisi X-KDE-Keywords[uk]=менеджер,керування,файл,файли X-KDE-Keywords[vi]=file manager,trình quản lí tệp diff --git a/src/settings/kcm/kcmdolphinnavigation.desktop b/src/settings/kcm/kcmdolphinnavigation.desktop index ca9d5a799..0ff189a47 100644 --- a/src/settings/kcm/kcmdolphinnavigation.desktop +++ b/src/settings/kcm/kcmdolphinnavigation.desktop @@ -42,6 +42,7 @@ Name[sr@ijekavian]=Делфинова навигација Name[sr@ijekavianlatin]=Dolphinova navigacija Name[sr@latin]=Dolphinova navigacija Name[sv]=Dolphin navigering +Name[ta]=டால்பின் உலாவல் Name[tr]=Dolphin Gezintisi Name[uk]=«Навігація» Dolphin Name[vi]=Điều hướng Dolphin @@ -91,6 +92,7 @@ Comment[sr@ijekavian]=Овај сервис омогућава подешава� Comment[sr@ijekavianlatin]=Ovaj servis omogućava podešavanje navigacije u Dolphinu. Comment[sr@latin]=Ovaj servis omogućava podešavanje navigacije u Dolphinu. Comment[sv]=Den här tjänsten låter dig anpassa navigering i Dolphin. +Comment[ta]=டால்பினின் உலாவல் அமைப்புகளை அமைக்க இந்த சேவை உதவும். Comment[tr]=Bu servis Dolphin gezintisini yapılandırmanızı sağlar. Comment[uk]=Ця служба надасть змогу налаштувати навігацію у Dolphin. Comment[vi]=Dịch vụ này cho phép cấu hình điều hướng Dolphin. @@ -150,6 +152,7 @@ Name[sr@ijekavian]=Навигација Name[sr@ijekavianlatin]=Navigacija Name[sr@latin]=Navigacija Name[sv]=Navigering +Name[ta]=உலாவல் Name[tr]=Gezinti Name[uk]=Навігація Name[vi]=Điều hướng @@ -200,6 +203,7 @@ Comment[sr@ijekavian]=Подешавање навигације у менаџе� Comment[sr@ijekavianlatin]=Podešavanje navigacije u menadžeru fajlova Comment[sr@latin]=Podešavanje navigacije u menadžeru fajlova Comment[sv]=Anpassa filhanterarens navigering +Comment[ta]=கோப்பு உலாவியில் உலாவலை அமையுங்கள் Comment[tr]=Dosya yöneticisi gezintisini yapılandır Comment[uk]=Налаштувати навігацію у менеджері файлів Comment[vi]=Cấu hình điều hướng trình quản lí tệp @@ -249,6 +253,7 @@ X-KDE-Keywords[sr@ijekavian]=file manager,менаџер фајлова X-KDE-Keywords[sr@ijekavianlatin]=file manager,menadžer fajlova X-KDE-Keywords[sr@latin]=file manager,menadžer fajlova X-KDE-Keywords[sv]=filhanterare +X-KDE-Keywords[ta]=file manager,கோப்பு மேலாளர், கோப்பு நிர்வாகி, கோப்பு உலாவி X-KDE-Keywords[tr]=dosya yöneticisi X-KDE-Keywords[uk]=менеджер,керування,файл,файли X-KDE-Keywords[vi]=file manager,trình quản lí tệp diff --git a/src/settings/kcm/kcmdolphinviewmodes.desktop b/src/settings/kcm/kcmdolphinviewmodes.desktop index d035d6b30..f6b0a0a6c 100644 --- a/src/settings/kcm/kcmdolphinviewmodes.desktop +++ b/src/settings/kcm/kcmdolphinviewmodes.desktop @@ -41,6 +41,7 @@ Name[sr@ijekavian]=Делфинови режими приказа Name[sr@ijekavianlatin]=Dolphinovi režimi prikaza Name[sr@latin]=Dolphinovi režimi prikaza Name[sv]=Dolphin visningslägen +Name[ta]=டால்பின் காட்சிமுறைகள் Name[tr]=Dolphin Görünüm Kipleri Name[uk]=Режими перегляду Dolphin Name[vi]=Các chế độ xem Dolphin @@ -89,6 +90,7 @@ Comment[sr@ijekavian]=Овај сервис омогућава подешава� Comment[sr@ijekavianlatin]=Ovaj servis omogućava podešavanje Dolphinovih režima prikaza. Comment[sr@latin]=Ovaj servis omogućava podešavanje Dolphinovih režima prikaza. Comment[sv]=Den här tjänsten låter dig anpassa visningslägen i Dolphin. +Comment[ta]=டால்பினின் காட்சிமுறைகளை அமைக்க இந்த சேவை உதவும். Comment[tr]=Bu servis Dolphin görünüm kiplerini yapılandırmanızı sağlar. Comment[uk]=Ця служба надасть змогу налаштувати режими перегляду Dolphin. Comment[vi]=Dịch vụ này cho phép cấu hình các chế độ xem Dolphin. @@ -147,6 +149,7 @@ Name[sr@ijekavian]=Режими приказа Name[sr@ijekavianlatin]=Režimi prikaza Name[sr@latin]=Režimi prikaza Name[sv]=Visningslägen +Name[ta]=காட்சிமுறைகள் Name[tr]=Görünüm Kipleri Name[uk]=Режими перегляду Name[vi]=Các chế độ xem @@ -196,6 +199,7 @@ Comment[sr@ijekavian]=Подешавање режима приказа у мен Comment[sr@ijekavianlatin]=Podešavanje režima prikaza u menadžeru fajlova Comment[sr@latin]=Podešavanje režima prikaza u menadžeru fajlova Comment[sv]=Anpassa filhanterarens visningslägen +Comment[ta]=கோப்பு உலாவியின் காட்சிமுறைகளை அமையுங்கள் Comment[tr]=Dosya yöneticisi görünüm ayarlarını yapılandır Comment[uk]=Налаштувати режими перегляду менеджера файлів Comment[vi]=Cấu hình các chế độ xem trình quản lí tệp @@ -245,6 +249,7 @@ X-KDE-Keywords[sr@ijekavian]=file manager,менаџер фајлова X-KDE-Keywords[sr@ijekavianlatin]=file manager,menadžer fajlova X-KDE-Keywords[sr@latin]=file manager,menadžer fajlova X-KDE-Keywords[sv]=filhanterare +X-KDE-Keywords[ta]=file manager,கோப்பு மேலாளர், கோப்பு நிர்வாகி, கோப்பு உலாவி X-KDE-Keywords[tr]=dosya yöneticisi X-KDE-Keywords[uk]=менеджер,керування,файл,файли X-KDE-Keywords[vi]=file manager,trình quản lí tệp diff --git a/src/statusbar/dolphinstatusbar.cpp b/src/statusbar/dolphinstatusbar.cpp index 91c843366..8ac74e71f 100644 --- a/src/statusbar/dolphinstatusbar.cpp +++ b/src/statusbar/dolphinstatusbar.cpp @@ -321,12 +321,15 @@ void DolphinStatusBar::updateZoomSliderToolTip(int zoomLevel) void DolphinStatusBar::setExtensionsVisible(bool visible) { + bool showStatusBar = visible; bool showSpaceInfo = visible; bool showZoomSlider = visible; if (visible) { + showStatusBar = GeneralSettings::showStatusBar(); showSpaceInfo = GeneralSettings::showSpaceInfo(); showZoomSlider = GeneralSettings::showZoomSlider(); } + setVisible(showStatusBar); m_spaceInfo->setShown(showSpaceInfo); m_spaceInfo->setVisible(showSpaceInfo); m_zoomSlider->setVisible(showZoomSlider); diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt index 692b7756f..e9a0e2dce 100644 --- a/src/tests/CMakeLists.txt +++ b/src/tests/CMakeLists.txt @@ -62,10 +62,7 @@ TEST_NAME viewpropertiestest LINK_LIBRARIES dolphinprivate dolphinstatic Qt5::Test) # DolphinMainWindowTest -set(dolphinmainwindowtest_SRCS dolphinmainwindowtest.cpp) -qt5_add_resources(dolphinmainwindowtest_SRCS ${CMAKE_SOURCE_DIR}/src/dolphin.qrc) - -ecm_add_test(${dolphinmainwindowtest_SRCS} +ecm_add_test(dolphinmainwindowtest.cpp ${CMAKE_SOURCE_DIR}/src/dolphin.qrc TEST_NAME dolphinmainwindowtest LINK_LIBRARIES dolphinprivate dolphinstatic Qt5::Test) diff --git a/src/tests/kfileitemmodeltest.cpp b/src/tests/kfileitemmodeltest.cpp index 558a00ab5..f527fbc61 100644 --- a/src/tests/kfileitemmodeltest.cpp +++ b/src/tests/kfileitemmodeltest.cpp @@ -812,6 +812,19 @@ void KFileItemModelTest::testRemoveFilteredExpandedItems() void KFileItemModelTest::testSorting() { + // testDir structure is as follows + // ./ + // ├─ a + // ├─ b + // ├─ c/ + // │ ├─ c-2/ + // │ │ ├─ c-3 + // │ ├─ c-1 + // ├─ d + // ├─ e + // ├─ .f + // ├─ .g/ + QSignalSpy itemsInsertedSpy(m_model, &KFileItemModel::itemsInserted); QSignalSpy itemsMovedSpy(m_model, &KFileItemModel::itemsMoved); QVERIFY(itemsMovedSpy.isValid()); @@ -836,17 +849,27 @@ void KFileItemModelTest::testSorting() m_testDir->createFile("d", "The largest file in this directory", now.addDays(-1)); m_testDir->createFile("e", "An even larger file", now.addDays(-4)); m_testDir->createFile(".f"); + m_testDir->createDir(".g"); m_model->loadDirectory(m_testDir->url()); QVERIFY(itemsInsertedSpy.wait()); + QCOMPARE(itemsInsertedSpy.count(), 1); + KItemRangeList itemRangeList = itemsInsertedSpy.takeFirst().at(0).value<KItemRangeList>(); + QCOMPARE(itemRangeList, KItemRangeList() << KItemRange(0, 5)); int index = m_model->index(QUrl(m_testDir->url().url() + "/c")); m_model->setExpanded(index, true); QVERIFY(itemsInsertedSpy.wait()); + QCOMPARE(itemsInsertedSpy.count(), 1); + itemRangeList = itemsInsertedSpy.takeFirst().at(0).value<KItemRangeList>(); + QCOMPARE(itemRangeList, KItemRangeList() << KItemRange(1, 2)); index = m_model->index(QUrl(m_testDir->url().url() + "/c/c-2")); m_model->setExpanded(index, true); QVERIFY(itemsInsertedSpy.wait()); + QCOMPARE(itemsInsertedSpy.count(), 1); + itemRangeList = itemsInsertedSpy.takeFirst().at(0).value<KItemRangeList>(); + QCOMPARE(itemRangeList, KItemRangeList() << KItemRange(2, 1)); // Default: Sort by Name, ascending QCOMPARE(m_model->sortRole(), QByteArray("text")); @@ -942,7 +965,36 @@ void KFileItemModelTest::testSorting() QCOMPARE(itemsMovedSpy.first().at(0).value<KItemRange>(), KItemRange(4, 4)); QCOMPARE(itemsMovedSpy.takeFirst().at(1).value<QList<int> >(), QList<int>() << 7 << 6 << 5 << 4); - // TODO: Sort by other roles; show/hide hidden files + // 'Show Hidden Files' enabled + m_model->setShowHiddenFiles(true); + QVERIFY(m_model->showHiddenFiles()); + QCOMPARE(itemsInModel(), QStringList() << "c" << "c-2" << "c-3" << "c-1" << "d" << "e" << "b" << "a" << ".g" << ".f"); + QCOMPARE(itemsMovedSpy.count(), 0); + QCOMPARE(itemsInsertedSpy.count(), 1); + QCOMPARE(itemsInsertedSpy.takeFirst().at(0).value<KItemRangeList>(), KItemRangeList() << KItemRange(8, 2)); + + // Sort by Name + m_model->setSortRole("text"); + QCOMPARE(itemsInModel(), QStringList() << "c" << "c-2" << "c-3" << "c-1" << "e" << "d" << "b" << "a" << ".g" << ".f"); + QCOMPARE(itemsMovedSpy.count(), 1); + QCOMPARE(itemsMovedSpy.first().at(0).value<KItemRange>(), KItemRange(4, 2)); + QCOMPARE(itemsMovedSpy.takeFirst().at(1).value<QList<int> >(), QList<int>() << 5 << 4); + + // Sort ascending + m_model->setSortOrder(Qt::AscendingOrder); + QCOMPARE(itemsInModel(), QStringList() << "c" << "c-2" << "c-3" << "c-1" << "a" << "b" << "d" << "e" << ".g" << ".f"); + QCOMPARE(itemsMovedSpy.count(), 1); + QCOMPARE(itemsMovedSpy.first().at(0).value<KItemRange>(), KItemRange(4, 4)); + QCOMPARE(itemsMovedSpy.takeFirst().at(1).value<QList<int> >(), QList<int>() << 7 << 6 << 5 << 4); + + // 'Sort Folders First' disabled + m_model->setSortDirectoriesFirst(false); + QVERIFY(!m_model->sortDirectoriesFirst()); + QCOMPARE(itemsInModel(), QStringList() << "a" << "b" << "c" << "c-1" << "c-2" << "c-3" << "d" << "e" << ".f" << ".g"); + QCOMPARE(itemsMovedSpy.count(), 1); + QCOMPARE(itemsMovedSpy.first().at(0).value<KItemRange>(), KItemRange(0, 10)); + QCOMPARE(itemsMovedSpy.takeFirst().at(1).value<QList<int> >(), QList<int>() << 2 << 4 << 5 << 3 << 0 << 1 << 6 << 7 << 9 << 8); + } void KFileItemModelTest::testIndexForKeyboardSearch() @@ -1099,7 +1151,7 @@ void KFileItemModelTest::testRemoveHiddenItems() m_model->setShowHiddenFiles(true); m_model->loadDirectory(m_testDir->url()); QVERIFY(itemsInsertedSpy.wait()); - QCOMPARE(itemsInModel(), QStringList() << ".a" << ".b" << "c" << "d" <<".f" << ".g" << "h" << "i"); + QCOMPARE(itemsInModel(), QStringList() << "c" << "d" << "h" << "i" << ".a" << ".b" <<".f" << ".g"); QCOMPARE(itemsInsertedSpy.count(), 1); QCOMPARE(itemsRemovedSpy.count(), 0); KItemRangeList itemRangeList = itemsInsertedSpy.takeFirst().at(0).value<KItemRangeList>(); @@ -1110,14 +1162,14 @@ void KFileItemModelTest::testRemoveHiddenItems() QCOMPARE(itemsInsertedSpy.count(), 0); QCOMPARE(itemsRemovedSpy.count(), 1); itemRangeList = itemsRemovedSpy.takeFirst().at(0).value<KItemRangeList>(); - QCOMPARE(itemRangeList, KItemRangeList() << KItemRange(0, 2) << KItemRange(4, 2)); + QCOMPARE(itemRangeList, KItemRangeList() << KItemRange(4, 4)); m_model->setShowHiddenFiles(true); - QCOMPARE(itemsInModel(), QStringList() << ".a" << ".b" << "c" << "d" <<".f" << ".g" << "h" << "i"); + QCOMPARE(itemsInModel(), QStringList() << "c" << "d" << "h" << "i" << ".a" << ".b" <<".f" << ".g"); QCOMPARE(itemsInsertedSpy.count(), 1); QCOMPARE(itemsRemovedSpy.count(), 0); itemRangeList = itemsInsertedSpy.takeFirst().at(0).value<KItemRangeList>(); - QCOMPARE(itemRangeList, KItemRangeList() << KItemRange(0, 2) << KItemRange(2, 2)); + QCOMPARE(itemRangeList, KItemRangeList() << KItemRange(4, 4)); m_model->clear(); QCOMPARE(itemsInModel(), QStringList()); diff --git a/src/trash/dolphintrash.cpp b/src/trash/dolphintrash.cpp index bec266c3b..8684cda06 100644 --- a/src/trash/dolphintrash.cpp +++ b/src/trash/dolphintrash.cpp @@ -8,6 +8,7 @@ #include "dolphintrash.h" #include <KIO/JobUiDelegate> +#include <kio_version.h> #include <KJobWidgets> #include <QList> #include <KNotification> @@ -21,7 +22,11 @@ Trash::Trash() // The trash icon must always be updated dependent on whether // the trash is empty or not. We use a KDirLister that automatically // watches for changes if the number of items has been changed. +#if KIO_VERSION < QT_VERSION_CHECK(5, 82, 0) m_trashDirLister->setAutoErrorHandlingEnabled(false, nullptr); +#else + m_trashDirLister->setAutoErrorHandlingEnabled(false); +#endif m_trashDirLister->setDelayedMimeTypes(true); auto trashDirContentChanged = [this]() { bool isTrashEmpty = m_trashDirLister->items().isEmpty(); diff --git a/src/views/dolphinview.cpp b/src/views/dolphinview.cpp index f0f67c9d0..ce77dd325 100644 --- a/src/views/dolphinview.cpp +++ b/src/views/dolphinview.cpp @@ -18,6 +18,7 @@ #include "kitemviews/kitemlistcontroller.h" #include "kitemviews/kitemlistheader.h" #include "kitemviews/kitemlistselectionmanager.h" +#include "kitemviews/private/kitemlistroleeditor.h" #include "versioncontrol/versioncontrolobserver.h" #include "viewproperties.h" #include "views/tooltips/tooltipmanager.h" @@ -178,6 +179,7 @@ DolphinView::DolphinView(const QUrl& url, QWidget* parent) : connect(m_model, &KFileItemModel::errorMessage, this, &DolphinView::errorMessage); connect(m_model, &KFileItemModel::directoryRedirection, this, &DolphinView::slotDirectoryRedirection); connect(m_model, &KFileItemModel::urlIsFileError, this, &DolphinView::urlIsFileError); + connect(m_model, &KFileItemModel::fileItemsChanged, this, &DolphinView::fileItemsChanged); connect(this, &DolphinView::itemCountChanged, this, &DolphinView::updatePlaceholderLabel); @@ -674,12 +676,21 @@ void DolphinView::renameSelectedItems() if (items.count() == 1 && GeneralSettings::renameInline()) { const int index = m_model->index(items.first()); - m_view->editRole(index, "text"); - hideToolTip(); + QMetaObject::Connection * const connection = new QMetaObject::Connection; + *connection = connect(m_view, &KItemListView::scrollingStopped, this, [=](){ + QObject::disconnect(*connection); + delete connection; + + m_view->editRole(index, "text"); + + hideToolTip(); + + connect(m_view, &DolphinItemListView::roleEditingFinished, + this, &DolphinView::slotRoleEditingFinished); + }); + m_view->scrollToItem(index); - connect(m_view, &DolphinItemListView::roleEditingFinished, - this, &DolphinView::slotRoleEditingFinished); } else { KIO::RenameFileDialog* dialog = new KIO::RenameFileDialog(items, this); connect(dialog, &KIO::RenameFileDialog::renamingFinished, @@ -1736,13 +1747,15 @@ void DolphinView::slotRoleEditingFinished(int index, const QByteArray& role, con disconnect(m_view, &DolphinItemListView::roleEditingFinished, this, &DolphinView::slotRoleEditingFinished); - if (index < 0 || index >= m_model->count()) { + const KFileItemList items = selectedItems(); + if (items.count() != 1) { return; } if (role == "text") { - const KFileItem oldItem = m_model->fileItem(index); - const QString newName = value.toString(); + const KFileItem oldItem = items.first(); + const EditResult retVal = value.value<EditResult>(); + const QString newName = retVal.newName; if (!newName.isEmpty() && newName != oldItem.text() && newName != QLatin1Char('.') && newName != QLatin1String("..")) { const QUrl oldUrl = oldItem.url(); @@ -1773,14 +1786,14 @@ void DolphinView::slotRoleEditingFinished(int index, const QByteArray& role, con #endif const bool newNameExistsAlready = (m_model->index(newUrl) >= 0); - if (!newNameExistsAlready) { + if (!newNameExistsAlready && m_model->index(oldUrl) == index) { // Only change the data in the model if no item with the new name // is in the model yet. If there is an item with the new name // already, calling KIO::CopyJob will open a dialog // asking for a new name, and KFileItemModel will update the // data when the dir lister signals that the file name has changed. QHash<QByteArray, QVariant> data; - data.insert(role, value); + data.insert(role, retVal.newName); m_model->setData(index, data); } @@ -1797,6 +1810,13 @@ void DolphinView::slotRoleEditingFinished(int index, const QByteArray& role, con connect(job, &KJob::result, this, &DolphinView::slotRenamingResult); } } + if (retVal.direction != EditDone) { + const short indexShift = retVal.direction == EditNext ? 1 : -1; + m_container->controller()->selectionManager()->setSelected(index, 1, KItemListSelectionManager::Deselect); + m_container->controller()->selectionManager()->setSelected(index + indexShift, 1, + KItemListSelectionManager::Select); + renameSelectedItems(); + } } } diff --git a/src/views/dolphinview.h b/src/views/dolphinview.h index be8263917..bb093774f 100644 --- a/src/views/dolphinview.h +++ b/src/views/dolphinview.h @@ -593,6 +593,8 @@ Q_SIGNALS: void goUpRequested(); + void fileItemsChanged(const KFileItemList &changedFileItems); + protected: /** Changes the zoom level if Control is pressed during a wheel event. */ void wheelEvent(QWheelEvent* event) override; diff --git a/src/views/dolphinviewactionhandler.cpp b/src/views/dolphinviewactionhandler.cpp index 236daed5f..4acc420b0 100644 --- a/src/views/dolphinviewactionhandler.cpp +++ b/src/views/dolphinviewactionhandler.cpp @@ -18,6 +18,7 @@ #endif #include <KActionCollection> #include <KActionMenu> +#include <KFileItemListProperties> #include <KLocalizedString> #include <KNewFileMenu> #include <KPropertiesDialog> @@ -68,6 +69,9 @@ void DolphinViewActionHandler::setCurrentView(DolphinView* view) this, &DolphinViewActionHandler::slotZoomLevelChanged); connect(view, &DolphinView::writeStateChanged, this, &DolphinViewActionHandler::slotWriteStateChanged); + connect(view, &DolphinView::selectionChanged, + this, &DolphinViewActionHandler::slotSelectionChanged); + slotSelectionChanged(m_currentView->selectedItems()); } DolphinView* DolphinViewActionHandler::currentView() @@ -155,6 +159,25 @@ void DolphinViewActionHandler::createActions() m_actionCollection->setDefaultShortcuts(copyPathAction, {Qt::CTRL | Qt::ALT | Qt::Key_C}); connect(copyPathAction, &QAction::triggered, this, &DolphinViewActionHandler::slotCopyPath); + // This menu makes sure that users who don't know how to open a context menu and haven't + // figured out how to enable the menu bar can still perform basic file manipulation. + // This only works if they know how to select a file. + // The text when nothing is selected at least implies that a selection can /somehow/ be made. + // This menu is by default only used in the hamburger menu but created here so users can put + // it on their toolbar. + KActionMenu *basicActionsMenu = m_actionCollection->add<KActionMenu>(QStringLiteral("basic_actions"), this); + // The text is set later depending on the selection in the currently active view. + basicActionsMenu->setPopupMode(QToolButton::InstantPopup); + basicActionsMenu->addAction(m_actionCollection->action(KStandardAction::name(KStandardAction::Cut))); + basicActionsMenu->addAction(m_actionCollection->action(KStandardAction::name(KStandardAction::Copy))); + basicActionsMenu->addAction(m_actionCollection->action(KStandardAction::name(KStandardAction::Paste))); + basicActionsMenu->addSeparator(); + basicActionsMenu->addAction(m_actionCollection->action(KStandardAction::name(KStandardAction::RenameFile))); + basicActionsMenu->addAction(m_actionCollection->action(KStandardAction::name(KStandardAction::MoveToTrash))); + basicActionsMenu->addSeparator(); + basicActionsMenu->addAction(m_actionCollection->action(QStringLiteral("properties"))); + basicActionsMenu->addSeparator(); // We add one more separator because we sometimes add contextual + // actions in slotSelectionChanged() after the static ones above. // View menu KToggleAction* iconsAction = iconsModeAction(); @@ -208,6 +231,14 @@ void DolphinViewActionHandler::createActions() m_actionCollection); zoomOutAction->setWhatsThis(i18nc("@info:whatsthis zoom out", "This reduces the icon size.")); + KActionMenu* zoomMenu = m_actionCollection->add<KActionMenu>(QStringLiteral("zoom")); + zoomMenu->setText(i18nc("@action:inmenu menu of zoom actions", "Zoom")); + zoomMenu->setIcon(QIcon::fromTheme(QStringLiteral("zoom"))); + zoomMenu->setPopupMode(QToolButton::InstantPopup); + zoomMenu->addAction(zoomInAction); + zoomMenu->addAction(zoomResetAction); + zoomMenu->addAction(zoomOutAction); + KToggleAction* showPreview = m_actionCollection->add<KToggleAction>(QStringLiteral("show_preview")); showPreview->setText(i18nc("@action:intoolbar", "Show Previews")); showPreview->setToolTip(i18nc("@info", "Show preview of files and folders")); @@ -709,3 +740,69 @@ void DolphinViewActionHandler::slotCopyPath() { m_currentView->copyPathToClipboard(); } + +void DolphinViewActionHandler::slotSelectionChanged(const KFileItemList& selection) +{ + QString basicActionsMenuText; + switch (selection.count()) { + case 0: + basicActionsMenuText = + i18nc("@action:inmenu menu with actions like copy, paste, rename. The user's selection is empty when this text is shown.", + "Actions for Current View"); + break; + case 1: + basicActionsMenuText = + i18nc("@action:inmenu menu with actions like copy, paste, rename. %1 is the name of the singular selected file/folder.", + "Actions for \"%1\"", selection.first().name()); + break; + case 2: + basicActionsMenuText = + i18nc("@action:inmenu menu with actions like copy, paste, rename. %1 and %2 are names of files/folders.", + "Actions for \"%1\" and \"%2\"", selection.first().name(), selection.last().name()); + break; + case 3: + basicActionsMenuText = + i18nc("@action:inmenu menu with actions like copy, paste, rename. %1, %2 and %3 are names of files/folders.", + "Actions for \"%1\", \"%2\" and \"%3\"", + selection.first().name(), selection.at(1).name(), selection.last().name()); + break; + default: + basicActionsMenuText = QString(); + break; + } + + // At some point the added clarity from the text starts being less important than the menu width. + if (basicActionsMenuText.isEmpty() || basicActionsMenuText.length() > 40) { + const KFileItemListProperties properties(selection); + if (properties.isFile()) { + basicActionsMenuText = + i18ncp("@action:inmenu menu with actions like copy, paste, rename. %1 is the amount of selected files/folders.", + "Actions for One Selected File", "Actions for %1 Selected Files", selection.count()); + } else if (properties.isDirectory()) { + basicActionsMenuText = + i18ncp("@action:inmenu menu with actions like copy, paste, rename. %1 is the amount of selected files/folders.", + "Actions for One Selected Folder", "Actions for %1 Selected Folders", selection.count()); + } else { + basicActionsMenuText = + i18ncp("@action:inmenu menu with actions like copy, paste, rename. %1 is the amount of selected files/folders.", + "Actions for One Selected Item", "Actions for %1 Selected Items", selection.count()); + } + } + + QAction *basicActionsMenu = m_actionCollection->action(QStringLiteral("basic_actions")); + basicActionsMenu->setText(basicActionsMenuText); + + // Add or remove contextual actions + auto basicActionsMenuActions = basicActionsMenu->menu()->actions(); + while (!basicActionsMenu->menu()->actions().constLast()->isSeparator()) { + basicActionsMenu->menu()->removeAction(basicActionsMenu->menu()->actions().last()); + } + if (selection.count() == 1) { + if (selection.first().isLink()) { + basicActionsMenu->menu()->addAction(m_actionCollection->action(QStringLiteral("show_target"))); + } + if (selection.first().isDir()) { + basicActionsMenu->menu()->addAction(m_actionCollection->action(QStringLiteral("add_to_places"))); + } + } +} diff --git a/src/views/dolphinviewactionhandler.h b/src/views/dolphinviewactionhandler.h index 23b4e5f1a..3f73153ea 100644 --- a/src/views/dolphinviewactionhandler.h +++ b/src/views/dolphinviewactionhandler.h @@ -19,6 +19,7 @@ class QAction; class QActionGroup; class DolphinView; class KActionCollection; +class KFileItemList; /** * @short Handles all actions for DolphinView @@ -211,6 +212,13 @@ private Q_SLOTS: */ void slotCopyPath(); + /** + * Changes the name of the menu that contains basic actions like "Copy", "Rename", ... + * The name is changed to something like "Actions for 3 Selected Items" to be extra + * explicit of how these basic actions are used. + */ + void slotSelectionChanged(const KFileItemList& selection); + private: /** * Create all the actions. diff --git a/src/views/versioncontrol/fileviewversioncontrolplugin.desktop b/src/views/versioncontrol/fileviewversioncontrolplugin.desktop index 4c33b3b2c..5cffe9aac 100644 --- a/src/views/versioncontrol/fileviewversioncontrolplugin.desktop +++ b/src/views/versioncontrol/fileviewversioncontrolplugin.desktop @@ -43,6 +43,7 @@ Comment[sr@ijekavian]=Прикључак управљања верзијама � Comment[sr@ijekavianlatin]=Priključak upravljanja verzijama za fajl prikaze Comment[sr@latin]=Priključak upravljanja verzijama za fajl prikaze Comment[sv]=Insticksprogram för versionskontroll i filvyer +Comment[ta]=கோப்புக் காட்சிகளுக்கான பதிப்புக் கட்டுப்பாட்டு (version control) செருகுநிரல் Comment[tr]=Dosya Görünümleri için Sürüm Kontrol Eklentisi Comment[uk]=Додаток керування версіями для панелей перегляду файлів Comment[vi]=Phần cài cắm "Quản lí phiên bản" cho khung xem tệp diff --git a/src/views/versioncontrol/kversioncontrolplugin.h b/src/views/versioncontrol/kversioncontrolplugin.h index aeac5ad29..c908be247 100644 --- a/src/views/versioncontrol/kversioncontrolplugin.h +++ b/src/views/versioncontrol/kversioncontrolplugin.h @@ -23,14 +23,15 @@ class KFileItem; * steps are required (in the example below it is assumed that a plugin for * Subversion will be written): * - * - Create a fileviewsvnplugin.desktop file with the following content: + * - Create a fileviewsvnplugin.json file with the following content: * <code> - * [Desktop Entry] - * Type=Service - * Name=Subversion - * X-KDE-ServiceTypes=FileViewVersionControlPlugin - * MimeType=text/plain; - * X-KDE-Library=fileviewsvnplugin + * { + * "KPlugin": { + * "Description": "The svn plugin", + * "Name": "Svn" + * } + * } + * </code> * * - Create a class FileViewSvnPlugin derived from KVersionControlPlugin and @@ -45,15 +46,13 @@ class KFileItem; * <code> * #include <KPluginFactory> * #include <KPluginLoader> - * K_PLUGIN_FACTORY(FileViewSvnPluginFactory, registerPlugin<FileViewSvnPlugin>();) - * K_EXPORT_PLUGIN(FileViewSvnPluginFactory("fileviewsvnplugin")) + * K_PLUGIN_CLASS_WITH_JSON(FileViewSvnPlugin, "fileviewsvnplugin.json") * </code> * * - Add the following lines to your CMakeLists.txt file: * <code> - * kde4_add_plugin(fileviewsvnplugin fileviewsvnplugin.cpp) - * target_link_libraries(fileviewsvnplugin konq) - * install(FILES fileviewsvnplugin.desktop DESTINATION ${SERVICES_INSTALL_DIR}) + * kcoreaddons_add_plugin(fileviewsvnplugin SOURCES fileviewsvnplugin.cpp INSTALL_NAMESPACE "dolphin/vcs") + * target_link_libraries(fileviewsvnplugin DolphinVcs) * </code> * * General implementation notes: diff --git a/src/views/versioncontrol/versioncontrolobserver.cpp b/src/views/versioncontrol/versioncontrolobserver.cpp index cf5be3c91..9c18c6794 100644 --- a/src/views/versioncontrol/versioncontrolobserver.cpp +++ b/src/views/versioncontrol/versioncontrolobserver.cpp @@ -15,6 +15,8 @@ #include <KLocalizedString> #include <KService> #include <KServiceTypeTrader> +#include <KPluginLoader> +#include <KPluginMetaData> #include <QTimer> @@ -279,24 +281,33 @@ void VersionControlObserver::initPlugins() // all fileview version control plugins and remember them in 'plugins'. const QStringList enabledPlugins = VersionControlSettings::enabledPlugins(); - const KService::List pluginServices = KServiceTypeTrader::self()->query(QStringLiteral("FileViewVersionControlPlugin")); - for (KService::List::ConstIterator it = pluginServices.constBegin(); it != pluginServices.constEnd(); ++it) { - if (enabledPlugins.contains((*it)->name())) { - KVersionControlPlugin* plugin = (*it)->createInstance<KVersionControlPlugin>(this); - if (plugin) { - connect(plugin, &KVersionControlPlugin::itemVersionsChanged, - this, &VersionControlObserver::silentDirectoryVerification); - connect(plugin, &KVersionControlPlugin::infoMessage, - this, &VersionControlObserver::infoMessage); - connect(plugin, &KVersionControlPlugin::errorMessage, - this, &VersionControlObserver::errorMessage); - connect(plugin, &KVersionControlPlugin::operationCompletedMessage, - this, &VersionControlObserver::operationCompletedMessage); + const QVector<KPluginMetaData> plugins = KPluginLoader::findPlugins(QStringLiteral("dolphin/vcs")); + + QSet<QString> loadedPlugins; + for (const auto &p : plugins) { + if (enabledPlugins.contains(p.name())) { + KPluginLoader loader(p.fileName()); + KPluginFactory *factory = loader.factory(); + KVersionControlPlugin *plugin = factory->create<KVersionControlPlugin>(); + if (plugin) { m_plugins.append(plugin); + loadedPlugins += p.name(); } } } + + for (auto &plugin : qAsConst(m_plugins)) { + connect(plugin, &KVersionControlPlugin::itemVersionsChanged, + this, &VersionControlObserver::silentDirectoryVerification); + connect(plugin, &KVersionControlPlugin::infoMessage, + this, &VersionControlObserver::infoMessage); + connect(plugin, &KVersionControlPlugin::errorMessage, + this, &VersionControlObserver::errorMessage); + connect(plugin, &KVersionControlPlugin::operationCompletedMessage, + this, &VersionControlObserver::operationCompletedMessage); + } + m_pluginsInitialized = true; } } |
