diff options
177 files changed, 30131 insertions, 0 deletions
diff --git a/tier1/kconfig/CMakeLists.txt b/tier1/kconfig/CMakeLists.txt new file mode 100644 index 00000000..c7a7c934 --- /dev/null +++ b/tier1/kconfig/CMakeLists.txt @@ -0,0 +1,60 @@ +cmake_minimum_required(VERSION 2.8.12) + +project(KConfig) + +find_package(ECM 0.0.9 REQUIRED NO_MODULE) +set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH} ${ECM_KDE_MODULE_DIR}) + +set(QT_REQUIRED_VERSION 5.2.0) + +find_package(Qt5 ${QT_REQUIRED_VERSION} CONFIG REQUIRED Widgets Xml Test Concurrent) +include(KDEInstallDirs) +include(KDEFrameworkCompilerSettings) +include(KDECMakeSettings) + +include(FeatureSummary) +include(ECMSetupVersion) + +set(KF5_VERSION "5.0.0") + +ecm_setup_version(${KF5_VERSION} VARIABLE_PREFIX KCONFIG + VERSION_HEADER "${CMAKE_CURRENT_BINARY_DIR}/kconfig_version.h" + PACKAGE_VERSION_FILE "${CMAKE_CURRENT_BINARY_DIR}/KF5ConfigConfigVersion.cmake") + + +# Needed for the tests or examples to build correctly +set(KConfig_KCFGC_EXECUTABLE kconfig_compiler) +include(KF5ConfigMacros.cmake) + +add_subdirectory(src) +add_subdirectory(autotests) + + +# create a Config.cmake and a ConfigVersion.cmake file and install them +set(CMAKECONFIG_INSTALL_DIR "${CMAKECONFIG_INSTALL_PREFIX}/KF5Config") + +include(CMakePackageConfigHelpers) + +configure_package_config_file("${CMAKE_CURRENT_SOURCE_DIR}/KF5ConfigConfig.cmake.in" + "${CMAKE_CURRENT_BINARY_DIR}/KF5ConfigConfig.cmake" + INSTALL_DESTINATION ${CMAKECONFIG_INSTALL_DIR} + ) + +install(FILES "${CMAKE_CURRENT_BINARY_DIR}/KF5ConfigConfig.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/KF5ConfigConfigVersion.cmake" + "${CMAKE_CURRENT_SOURCE_DIR}/KF5ConfigMacros.cmake" + DESTINATION "${CMAKECONFIG_INSTALL_DIR}" + COMPONENT Devel ) + + +install(EXPORT KF5ConfigTargets DESTINATION "${CMAKECONFIG_INSTALL_DIR}" + FILE KF5ConfigTargets.cmake NAMESPACE KF5:: COMPONENT Devel) + + +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/kconfig_version.h + DESTINATION ${INCLUDE_INSTALL_DIR} COMPONENT Devel ) + + +if ("${CMAKE_BINARY_DIR}" STREQUAL "${CMAKE_CURRENT_BINARY_DIR}") + feature_summary(WHAT ALL FATAL_ON_MISSING_REQUIRED_PACKAGES) +endif() diff --git a/tier1/kconfig/COPYING.LIB b/tier1/kconfig/COPYING.LIB new file mode 100644 index 00000000..2d2d780e --- /dev/null +++ b/tier1/kconfig/COPYING.LIB @@ -0,0 +1,510 @@ + + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations +below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it +becomes a de-facto standard. To achieve this, non-free programs must +be allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control +compilation and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at least + three years, to give the same user the materials specified in + Subsection 6a, above, for a charge no more than the cost of + performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply, and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License +may add an explicit geographical distribution limitation excluding those +countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms +of the ordinary General Public License). + + To apply these terms, attach the following notices to the library. +It is safest to attach them to the start of each source file to most +effectively convey the exclusion of warranty; and each file should +have at least the "copyright" line and a pointer to where the full +notice is found. + + + <one line to give the library's name and a brief 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 St, 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/tier1/kconfig/DESIGN b/tier1/kconfig/DESIGN new file mode 100644 index 00000000..3cccc1ca --- /dev/null +++ b/tier1/kconfig/DESIGN @@ -0,0 +1,106 @@ +If you add a major new feature, suggest using it in +http://techbase.kde.org/Development/Tutorials/KConfig + +kconfigdata.h contains definitions of the data formats used by kconfig. + +Configuration entries are stored as "KEntry". They are indexed with "KEntryKey". +The primary store is a "KEntryMap" which is defined as a QMap from "KEntryKey" +to "KEntry" + +KEntry's are stored in order in the KEntryMap. The most significant sort +criteria is mGroup. This means that all entries who belong in the same group, +are grouped in the QMap as well. + +The start of a group is indicated with a KEntryKey with an empty mKey and a +dummy KEntry. This allows us to search for the start of the group and then to +iterate until we end up in another group. That way we will find all entries +of a certain group. + +Entries that are localised with the _current_ locale are stored with bLocal +set to true. Entries that are localised with another locale are either not +stored at all (default), or with the localization as part of the key and bRaw +set to true (when reading a file in order to merge it). + +Entries that are being read from a location other than the location to +which is written back are marked as "default" and will be added both as +normal entry as well as an entry with the key marked as default. + +When the configuration is synced to disk, the current on-disk state is re-read +into a temporary map, updated with dirty (modified) entries from the +current config object's entry map and then written back. + + +Note that there is a subtle difference between revertToDefault() and deleteEntry(). +revertToDefault() will change the entry to the default value set by the system +administrator (Via e.g. $KDEDIR/share/config) or, if no such default was set, +non-existant. +deleteEntry() will make the entry non-existant. If if the system administrator +has specified a default value, the local entry is marked with [$d]. + +Entries are marked "immutable" if the key is followed by [$i]. This means +that a user can not override these entries. + + +------------------------------------------------------------------------------ + +KConfig XT +========== + +My buzzword picker offered KConfig XT ("eXtended Technology") and KConfig NG +("Next Generation"). Since the planned changes are ment to be evolutionary +rather than revolutionary, KConfig NG was dropped. + +Goals +===== + +* Have the default value for config entries defined in 1 place. Currently it is +not uncommon to have them defined in three places: + 1) In the application that reads the setting in order to use it + 2) In the settings dialog when reading the setting + 3) In the settings dialog when selecting "Use defaults". + +* Provide type-information about config entries to facilate "KConfEdit" like +tools. Ideally type-information also includes range-information; this is even +mandatory if enums become an explicit type. + +* Facilitate the documentation of config entries. + +KCoreConfigSkeleton + | + v + KConfigSkeleton /--< myapp.kcfg + | / + |*---------------< + |kconfig_compiler \ + | \--< myconfig.kcfgc + v + MyConfig <-----KConfigDialogManager----> MyConfigWidget *---< myconfigwidget.ui + uic + +KCoreConfigSkeleton/ base class for deriving classes that store application +KConfigSkeleton: specific options providing type-safety and single-point + defaults. + +MyConfig: An application specific class that offers configuration options + to the applications via variables or accessor functions and that + handles type-safety and defaults. MyConfig is just an example + name, the application developer choses the actual name. + +myapp.kcfg: File describing the configuration options used by a specific + application. myapp.kcfg is just an example name, the application + developer choses the actual name. + +myconfig.kcfgc: Implementation specific code generation instructions + for the MyConfig class. myconfig.kcfgc is + just an example name, the application developer + choses the actual name. + +KConfigDialogManager: Class that links widgets in a dialog up with their + corresponding confguration options in a configuration + object derived from KConfigSkeleton. + +MyConfigWidget: Dialog generated from a .ui description file. Widget names + in the dialog that start with "kcfg_" refer to configuration + options. + +See http://techbase.kde.org/Development/Tutorials/Using_KConfig_XT diff --git a/tier1/kconfig/KF5ConfigConfig.cmake.in b/tier1/kconfig/KF5ConfigConfig.cmake.in new file mode 100644 index 00000000..12ff7c63 --- /dev/null +++ b/tier1/kconfig/KF5ConfigConfig.cmake.in @@ -0,0 +1,11 @@ +@PACKAGE_INIT@ + +# Any changes in this ".cmake" file will be overwritten by CMake, the source is the ".cmake.in" file. + + +include("${CMAKE_CURRENT_LIST_DIR}/KF5ConfigTargets.cmake") + +find_dependency(Qt5Xml "@REQUIRED_QT_VERSION@") + +unset( _KDE4_KCONFIG_COMPILER_DEP) +include("${CMAKE_CURRENT_LIST_DIR}/KF5ConfigMacros.cmake") diff --git a/tier1/kconfig/KF5ConfigMacros.cmake b/tier1/kconfig/KF5ConfigMacros.cmake new file mode 100644 index 00000000..bf2615b3 --- /dev/null +++ b/tier1/kconfig/KF5ConfigMacros.cmake @@ -0,0 +1,84 @@ +# KCONFIG_ADD_KCFG_FILES (SRCS_VAR [GENERATE_MOC] [USE_RELATIVE_PATH] file1.kcfgc ... fileN.kcfgc) +# Use this to add KDE config compiler files to your application/library. +# Use optional GENERATE_MOC to generate moc if you use signals in your kcfg files. +# Use optional USE_RELATIVE_PATH to generate the classes in the build following the given +# relative path to the file. +# +# Copyright (c) 2006-2009 Alexander Neundorf, <neundorf@kde.org> +# Copyright (c) 2006, 2007, Laurent Montel, <montel@kde.org> +# Copyright (c) 2007 Matthias Kretz <kretz@kde.org> +# +# Redistribution and use is allowed according to the terms of the BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. + +macro (KCONFIG_ADD_KCFG_FILES _sources ) + foreach (_current_ARG ${ARGN}) + if( ${_current_ARG} STREQUAL "GENERATE_MOC" ) + set(_kcfg_generatemoc TRUE) + endif() + + if( ${_current_ARG} STREQUAL "USE_RELATIVE_PATH" ) + set(_kcfg_relativepath TRUE) + endif() + endforeach () + + foreach (_current_FILE ${ARGN}) + + if(NOT ${_current_FILE} STREQUAL "GENERATE_MOC" AND NOT ${_current_FILE} STREQUAL "USE_RELATIVE_PATH") + get_filename_component(_tmp_FILE ${_current_FILE} ABSOLUTE) + get_filename_component(_abs_PATH ${_tmp_FILE} PATH) + + if (_kcfg_relativepath) # Process relative path only if the option was set + # Get relative path + get_filename_component(_rel_PATH ${_current_FILE} PATH) + + if (IS_ABSOLUTE ${_rel_PATH}) + # We got an absolute path + set(_rel_PATH "") + endif () + endif () + + get_filename_component(_basename ${_tmp_FILE} NAME_WE) + # If we had a relative path and we're asked to use it, then change the basename accordingly + if(NOT ${_rel_PATH} STREQUAL "") + set(_basename ${_rel_PATH}/${_basename}) + endif() + + file(READ ${_tmp_FILE} _contents) + string(REGEX REPLACE "^(.*\n)?File=([^\n]+kcfg).*\n.*$" "\\2" _kcfg_FILENAME "${_contents}") + set(_src_FILE ${CMAKE_CURRENT_BINARY_DIR}/${_basename}.cpp) + set(_header_FILE ${CMAKE_CURRENT_BINARY_DIR}/${_basename}.h) + set(_moc_FILE ${CMAKE_CURRENT_BINARY_DIR}/${_basename}.moc) + set(_kcfg_FILE ${_abs_PATH}/${_kcfg_FILENAME}) + # Maybe the .kcfg is a generated file? + if(NOT EXISTS "${_kcfg_FILE}") + set(_kcfg_FILE ${CMAKE_CURRENT_BINARY_DIR}/${_kcfg_FILENAME}) + endif() + + if(NOT EXISTS "${_kcfg_FILE}") + message(ERROR "${_kcfg_FILENAME} not found; tried in ${_abs_PATH} and ${CMAKE_CURRENT_BINARY_DIR}") + endif() + + # make sure the directory exist in the build directory + if(NOT EXISTS "${CMAKE_CURRENT_BINARY_DIR}/${_rel_PATH}") + file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${_rel_PATH}) + endif() + + # the command for creating the source file from the kcfg file + add_custom_command(OUTPUT ${_header_FILE} ${_src_FILE} + COMMAND KF5::kconfig_compiler + ARGS ${_kcfg_FILE} ${_tmp_FILE} -d ${CMAKE_CURRENT_BINARY_DIR}/${_rel_PATH} + MAIN_DEPENDENCY ${_tmp_FILE} + DEPENDS ${_kcfg_FILE} ${_KDE4_KCONFIG_COMPILER_DEP} ) + + if(_kcfg_generatemoc) + qt5_generate_moc(${_header_FILE} ${_moc_FILE} ) + set_source_files_properties(${_src_FILE} PROPERTIES SKIP_AUTOMOC TRUE) # don't run automoc on this file + list(APPEND ${_sources} ${_moc_FILE}) + endif() + + list(APPEND ${_sources} ${_src_FILE} ${_header_FILE}) + endif(NOT ${_current_FILE} STREQUAL "GENERATE_MOC" AND NOT ${_current_FILE} STREQUAL "USE_RELATIVE_PATH") + endforeach (_current_FILE) + +endmacro (KCONFIG_ADD_KCFG_FILES) diff --git a/tier1/kconfig/Mainpage.dox b/tier1/kconfig/Mainpage.dox new file mode 100644 index 00000000..7e0699f9 --- /dev/null +++ b/tier1/kconfig/Mainpage.dox @@ -0,0 +1 @@ +// DOXYGEN_SET_PROJECT_NAME = KConfig diff --git a/tier1/kconfig/TODO b/tier1/kconfig/TODO new file mode 100644 index 00000000..4346ee13 --- /dev/null +++ b/tier1/kconfig/TODO @@ -0,0 +1,175 @@ +bugs +==== + +- make expandString stuff consistent +- KConfigGroup::exists() should return true only if the group contains + any non-deleted entries (?) +- immutable groups with no entries are not written out and thus lose + their immutability. +- "C" & "en_US" should be detected early and converted to a null string + (but also save the original string, so locale() semantics don't change + at that point). + +wishes +====== + +- use lazy loading + - load as soon as the first KConfigGroup is instanciated + - lazy parsing of values is interesting, too - see kconfig_take2 branch +- add $\\VAR and $\\(cmd) escapes to list-quote expanded string +- possibly: + - preserve unchanged parts of the config literally. problem: comments + might become stale. so if a comment is already there, add an additional + comment that indicates that the value was changed (include old value?). + - api to actively add comments to files, groups and keys + - option to start these comments with ## as a sign that they should not + trigger the above change indicator logic. + - guaranteeing that write order of new keys is preserved + - detect commented out entries and put actual entries with the same key + right behind them +- possibly: selective multi-level master diversion + - this is to support roaming profiles that have machine/user/etc. specific + settings + - files, groups and keys can have [$m] and [$s] markers; these cascade + within each file only. the least significant object (farthest away from + the master) with an effective $m mode becomes the master (i.e., is + written to and not read past). + default is $m for the master file and $s for the default files. + - the CascadeConfig flag being unset doesn't make things exactly simpler + - can kdeglobals be handled by this? + - does this really make sense? promoting an object to profile wide status + is a conscious decision - which probably needs to be repeated every time + the value changes. + +internals +========= + +- clear up bDeleted vs. isNull in entrymap +- make entrymap truly hierarchical + - an entry map contains its flags, a map of keys and a map of submaps. + it does NOT contain its name and has no parent pointer. + - when creating a kconfiggroup, ask parent for the respective submap + and link it if it is present. if it is not, create one at write op, + link it and tell parent to add it to its entry map. both query and + creation are recursive, obviously. + a kconfiggroup DOES contain its name and has a parent pointer. + - 3) +- 4) + +3) +> We wouldn't have to worry about the KEntryGroup being removed out from +> under us, because the only way that should happen is if the config +> object is destroyed or reparsed, and in those cases you shouldn't be +> using a KConfigGroup from prior to that. +> +i don't think "this is stupid and will not happen" works; [...] +given that cascaded parsing includes writing to existing maps, i think +the simplest approach is clearing the existing structure from keymaps +and resetting the attributes, but leaving the subgroup maps populated, +thus keeping any group refs valid. +the question is about the type of reference held to the entry map. +originally i had thought of pointers. a map would be linked only if it +really existed, otherwise the pointer would be null (thus indicating +reads to return the default immediately and writes to ask the parent to +create a submap). however, keeping that consistent with deletions would +be a nightmare, and with the rescan changing the groups underneath +impossible without each map having a list of referring configgroups. +therefore it might make more sense to always create a corresponding tree +of empty maps when a configroup for a non-existing group is instanciated +- these groups won't be written out (they have no entries and cannot be +immutable) and access to non-existing groups (esp. without an subsequent +write that would actually create it) is rare, so the performance and +memory overhead of this "eager" approach is likely to be negligible. as +a middle way one could use a pointer and lazily populate it on first +access whithout putting semantics into the pointer being already set, +but i don't think the added complexity will pay off. + +4) +> > > > hmm, wait. maybe it would be better if the map did not do actual +> > > > permission checking. the frontent is peppered with asserts already +> > > +> > > that's the group doing permission checking, if this group is immutable +> > > then the entry can't be changed. plus, now that KEntryKey doesn't know +> > > what group it belongs to KEntryMap can't check if the group is +> > > immutable. +> > > +> > > > (need to consider how to handle release builds). in the backend, the +> > > > ugly immutableGroups hack would be unnecessary. +> > > +> > > no, immutableGroups would still be necessary unless i remove all +> > > checking from KGroupEntry and KEntryMap. but, then checks for +> > > immutable would have to be used everywhere that an entry might be +> > > changed. +> > > +> > yes - and the frontend already handles it and the backend *should* +> > handle it (issue warnings for trying to overwrite $i settings). +> +> i don't know, i think most handling of the immutability of a group +> can/should be handled by the KGroupEntry itself. this way we can keep +> all the data about a group in one place and let KGroupEntry keep +> itself in a consistent/valid state. +> +dunno, either. the use cases are: +- backend: writing immutable objects is fine, as long as the + immutability does not come from a pre-existing default. + given that there will be multiple backends, it sounds like + centralizing the check and warning reporting might make sense. otoh, + such a low-level function might not have enough context to make a + useful message. +- frontend: obviously, writing immutable objects is not permitted. this + is already checked everywhere through asserts. in non-debug builds + these asserts have no effect, but if a write gets that far it means + that the app already permitted changing the option in the first place + due to failure to check for immutability. i don't see much point in + preventing the illegitimate change from being saved, as it can be + repeated anyway (i'm not really convinced of security through + exhaustion/boredom of the attacker :). +i'm not sure whether that means that the two use cases need separate +mutators or whether the mutator should not apply any immutability +semantics at all. + + +overwriting semantics +===================== + +generally: +- localized entries cannot exist without an unlocalized "primary" entry, + so writing a localized key when no corresponding unlocalized key + exists should print a warning and copy the value to the unlocalized + key. +- a primary entry in the user config overshadows not only the immediate + default, but also any localizations of the default. applies also to a + [$d] marker, obviously. + a localized entry in the user config overshadows only that + localization from the default. + +write ops: +> > - writing an entry with the localization flag changes really only that +> > key. +> > trying to change the globality of the key prints a warning and does +> > nothing. +- key exists in local config => overwritten +- key does not exist => created +yes, that's the trivial case. + +> > - writing an entry without the localization flag deletes all +> > localizations. +> > in this case, changing the globality of the key poses no problem. +- the key itself is handled trivially +- if localizations exist in the local config, they are actively purged +- localizations in the default config don't matter, as they will be + overshadowed by the unlocalized key in the local config + +> > - deleting an entry also deletes all localizations. +- if default exists, write [$d] entry +- if no default exists, delete entry +- if localizations exist in the local config, they are actively purged +- localizations in the default config don't matter, as they will be + overshadowed by the unlocalized key in the local config (as + localizations cannot exist without a primary key, a deletion marker + key will be present). + +> > - reverting a key to default also restores all localizations. +- any local entries are actively purged + + diff --git a/tier1/kconfig/autotests/CMakeLists.txt b/tier1/kconfig/autotests/CMakeLists.txt new file mode 100644 index 00000000..e4790f69 --- /dev/null +++ b/tier1/kconfig/autotests/CMakeLists.txt @@ -0,0 +1,59 @@ + +remove_definitions(-DQT_NO_CAST_FROM_ASCII) + +include(ECMMarkAsTest) + +find_package(Qt5 5.2.0 CONFIG REQUIRED Concurrent Test Widgets) + +macro(KCONFIGCORE_UNIT_TESTS) + foreach(_testname ${ARGN}) + add_executable(${_testname} ${_testname}.cpp) # TODO NOGUI + add_test(kconfigcore-${_testname} ${_testname}) + target_link_libraries(${_testname} KF5::ConfigCore Qt5::Test Qt5::Concurrent) + ecm_mark_as_test(${_testname}) + endforeach() +endmacro() + +macro(KCONFIGGUI_UNIT_TESTS) + foreach(_testname ${ARGN}) + add_executable(${_testname} ${_testname}.cpp) + add_test(kconfiggui-${_testname} ${_testname}) + target_link_libraries(${_testname} KF5::ConfigGui Qt5::Test) + ecm_mark_as_test(${_testname}) + endforeach() +endmacro() + +kconfigcore_unit_tests( + kconfignokdehometest + kconfigtest + kdesktopfiletest + ksharedconfigtest + test_kconf_update +) + +target_include_directories(test_kconf_update PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/../src/kconf_update) + +# compile KEntryMap into the test since it's not exported +set(kentrymaptest_SRCS kentrymaptest.cpp ../src/core/kconfigdata.cpp) +add_executable(kentrymaptest ${kentrymaptest_SRCS}) +add_test(kconfigcore-kentrymaptest kentrymaptest) +target_link_libraries(kentrymaptest KF5::ConfigCore Qt5::Test) +ecm_mark_as_test(kentrymaptest) + +# compile KConfigUtils into the test since it's not exported +set(test_kconfigutils_SRCS test_kconfigutils ../src/kconf_update/kconfigutils.cpp) +add_executable(test_kconfigutils ${test_kconfigutils_SRCS}) +add_test(kconfigcore-test_kconfigutils test_kconfigutils) +target_link_libraries(test_kconfigutils KF5::ConfigCore Qt5::Test) +target_include_directories(test_kconfigutils PRIVATE ../src/kconf_update) +ecm_mark_as_test(test_kconfigutils) + +kconfiggui_unit_tests( + kconfigguitest + kconfigloadertest + kconfigskeletontest + kstandardshortcuttest +) + +add_subdirectory(kconfig_compiler) + diff --git a/tier1/kconfig/autotests/kconfig_compiler/CMakeLists.txt b/tier1/kconfig/autotests/kconfig_compiler/CMakeLists.txt new file mode 100644 index 00000000..ef2fd407 --- /dev/null +++ b/tier1/kconfig/autotests/kconfig_compiler/CMakeLists.txt @@ -0,0 +1,212 @@ + +#test5.cpp test5.h: $(srcdir)/test5.kcfg ../kconfig_compiler $(srcdir)/test5.kcfgc +# ../kconfig_compiler $(srcdir)/test5.kcfg $(srcdir)/test5.kcfgc + +macro(GEN_KCFG_TEST_SOURCE _testName _srcs) + add_custom_command( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${_testName}.cpp ${CMAKE_CURRENT_BINARY_DIR}/${_testName}.h + COMMAND ${KConfig_KCFGC_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/${_testName}.kcfg ${CMAKE_CURRENT_SOURCE_DIR}/${_testName}.kcfgc + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${_testName}.kcfg ${CMAKE_CURRENT_SOURCE_DIR}/${_testName}.kcfgc kconfig_compiler) + +# set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/${_testName}.h PROPERTIES GENERATED TRUE) + qt5_generate_moc(${CMAKE_CURRENT_BINARY_DIR}/${_testName}.h ${CMAKE_CURRENT_BINARY_DIR}/${_testName}.moc ) +# do not run automoc on the generated file + set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/${_testName}.cpp PROPERTIES SKIP_AUTOMOC TRUE) + set( ${_srcs} ${${_srcs}} ${CMAKE_CURRENT_BINARY_DIR}/${_testName}.cpp ${CMAKE_CURRENT_BINARY_DIR}/${_testName}.h ) + + set_property(SOURCE ${CMAKE_CURRENT_BINARY_DIR}/${_testName}.cpp APPEND PROPERTY OBJECT_DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${_testName}.moc ) +endmacro(GEN_KCFG_TEST_SOURCE) + +include(ECMMarkAsTest) + +########### next target ############### + +set(test1_SRCS test1main.cpp ) + + +gen_kcfg_test_source(test1 test1_SRCS) + +add_executable(test1 ${test1_SRCS}) +ecm_mark_as_test(test1) +target_link_libraries(test1 KF5::ConfigGui) + + +########### next target ############### + +set(test2_SRCS test2main.cpp ) + + +gen_kcfg_test_source(test2 test2_SRCS) + +add_executable(test2 ${test2_SRCS}) +ecm_mark_as_test(test2) +target_link_libraries(test2 KF5::ConfigGui) + + +########### next target ############### + +set(test3_SRCS test3main.cpp ) + + +gen_kcfg_test_source(test3 test3_SRCS) + +add_executable(test3 ${test3_SRCS}) +ecm_mark_as_test(test3) +target_link_libraries(test3 KF5::ConfigGui) + + +########### next target ############### + +set(test3a_SRCS test3amain.cpp ) + + +gen_kcfg_test_source(test3a test3a_SRCS) + +add_executable(test3a ${test3a_SRCS}) +ecm_mark_as_test(test3a) +target_link_libraries(test3a KF5::ConfigGui) + + +########### next target ############### + +set(test4_SRCS test4main.cpp ) + + +gen_kcfg_test_source(test4 test4_SRCS) + +add_executable(test4 ${test4_SRCS}) +ecm_mark_as_test(test4) +target_link_libraries(test4 KF5::ConfigGui) + + +########### next target ############### + +set(test5_SRCS test5main.cpp ) + + +gen_kcfg_test_source(test5 test5_SRCS) + +add_executable(test5 ${test5_SRCS}) +ecm_mark_as_test(test5) +target_link_libraries(test5 KF5::ConfigGui) + + +########### next target ############### + +set(test6_SRCS test6main.cpp ) + + +gen_kcfg_test_source(test6 test6_SRCS) + +add_executable(test6 ${test6_SRCS}) +ecm_mark_as_test(test6) +target_link_libraries(test6 KF5::ConfigGui) + + +########### next target ############### + +set(test7_SRCS test7main.cpp ) + + +gen_kcfg_test_source(test7 test7_SRCS) + +add_executable(test7 ${test7_SRCS}) +ecm_mark_as_test(test7) +target_link_libraries(test7 KF5::ConfigGui) + + +########### next target ############### + +set(test8_SRCS test8main.cpp ) + + +gen_kcfg_test_source(test8a test8_SRCS) +gen_kcfg_test_source(test8b test8_SRCS) + +add_executable(test8 ${test8_SRCS}) +ecm_mark_as_test(test8) +target_link_libraries(test8 KF5::ConfigGui) + + +########### next target ############### + +set(test9_SRCS test9main.cpp ) + + +gen_kcfg_test_source(test9 test9_SRCS) + +add_executable(test9 ${test9_SRCS}) +ecm_mark_as_test(test9) +target_link_libraries(test9 KF5::ConfigGui) + + +########### next target ############### + +set(test10_SRCS test10main.cpp ) + + +gen_kcfg_test_source(test10 test10_SRCS) + +add_executable(test10 ${test10_SRCS}) +ecm_mark_as_test(test10) +target_link_libraries(test10 KF5::ConfigGui) + + +########### next target ############### + +set(test11_SRCS test11main.cpp ) + + +gen_kcfg_test_source(test11 test11_SRCS) +gen_kcfg_test_source(test11a test11_SRCS) + +add_executable(test11 ${test11_SRCS}) +ecm_mark_as_test(test11) +target_link_libraries(test11 KF5::ConfigGui) + + +########### next target ############### + +set(test12_SRCS test12main.cpp ) + +gen_kcfg_test_source(test12 test12_SRCS) + +add_executable(test12 ${test12_SRCS}) +ecm_mark_as_test(test12) +target_link_libraries(test12 KF5::ConfigGui) + + +########### next target ############### + +set(test_dpointer_SRCS test_dpointer_main.cpp ) + +gen_kcfg_test_source(test_dpointer test_dpointer_SRCS) + +add_executable(test_dpointer ${test_dpointer_SRCS}) +ecm_mark_as_test(test_dpointer) +target_link_libraries(test_dpointer KF5::ConfigGui) + + +########### next target ############### + +set(test_signal_SRCS test_signal_main.cpp ) +gen_kcfg_test_source(test_signal test_signal_SRCS) +add_executable(test_signal ${test_signal_SRCS}) +ecm_mark_as_test(test_signal) +target_link_libraries(test_signal KF5::ConfigGui) + +########### next target ############### + +set(kconfigcompiler_test_SRCS kconfigcompiler_test.cpp ) +add_executable(kconfigcompiler_test ${kconfigcompiler_test_SRCS}) +ecm_mark_as_test(kconfigcompiler_test) +add_test(kconfig-kconfigcompiler kconfigcompiler_test) + +target_link_libraries(kconfigcompiler_test Qt5::Test ) + +########### install files ############### + + + + + diff --git a/tier1/kconfig/autotests/kconfig_compiler/kconfigcompiler_test.cpp b/tier1/kconfig/autotests/kconfig_compiler/kconfigcompiler_test.cpp new file mode 100644 index 00000000..a9bf52c8 --- /dev/null +++ b/tier1/kconfig/autotests/kconfig_compiler/kconfigcompiler_test.cpp @@ -0,0 +1,181 @@ +/* + Tests for KConfig Compiler + + Copyright (c) 2005 by Duncan Mac-Vicar <duncan@kde.org> + Copyright (c) 2009 by Pino Toscano <pino@kde.org> + + ************************************************************************* + * * + * 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 of the License, or (at your option) any later version. * + * * + ************************************************************************* +*/ + +#include <QtCore/QDir> +#include <QtCore/QFile> +#include <QtCore/QProcess> +#include <QtCore/QString> +#include <QtTest/QtTest> +#include <qstandardpaths.h> +#include "kconfigcompiler_test.h" + +// QT5 TODO QTEST_GUILESS_MAIN(KConfigCompiler_Test) +QTEST_MAIN(KConfigCompiler_Test) + +typedef const char * CompilerTestSet[]; + +static CompilerTestSet testCases = +{ + "test1.cpp", "test1.h", + "test2.cpp", "test2.h", + "test3.cpp", "test3.h", + "test3a.cpp", "test3a.h", + "test4.cpp", "test4.h", + "test5.cpp", "test5.h", + "test6.cpp", "test6.h", + "test7.cpp", "test7.h", + "test8a.cpp", "test8a.h", + "test8b.cpp", "test8b.h", + "test9.h", "test9.cpp", + "test10.h", "test10.cpp", + "test11.h", "test11.cpp", + "test11a.h", "test11a.cpp", + "test12.h", "test12.cpp", + "test_dpointer.cpp", "test_dpointer.h", + "test_signal.cpp", "test_signal.h", + NULL +}; + +static CompilerTestSet testCasesToRun = +{ + "test1", + "test2", + "test3", + "test3a", + "test4", + "test5", + "test6", + "test7", + "test8", + "test9", + "test10", + "test11", + "test12", + "test_dpointer", + "test_signal", + 0 +}; + +#if 0 +static CompilerTestSet willFailCases = +{ + // where is that QDir coming from? + //"test9.cpp", NULL + NULL +}; +#endif + +void KConfigCompiler_Test::initTestCase() +{ + m_diffExe = QStandardPaths::findExecutable("diff"); + if (!m_diffExe.isEmpty()) { + m_diff.setFileName(QDir::currentPath() + QLatin1String("/kconfigcompiler_test_differences.diff")); + if (m_diff.exists()) { + m_diff.remove(); + } + } +} + +void KConfigCompiler_Test::testBaselineComparison_data() +{ + QTest::addColumn<QString>("testName"); + + for (const char **it = testCases; *it; ++it) { + QTest::newRow(*it) << QString::fromLatin1(*it); + } +} + +void KConfigCompiler_Test::testBaselineComparison() +{ + QFETCH(QString, testName); + + QFile file(QFINDTESTDATA(testName)); + QFile fileRef(QFINDTESTDATA(testName + QLatin1String(".ref"))); + + if (!file.open(QIODevice::ReadOnly)) { + qWarning() << "Failed to open" << file.fileName(); + QFAIL("Can't open file for comparison"); + } + if (!fileRef.open(QIODevice::ReadOnly)) { + qWarning() << "Failed to open" << fileRef.fileName(); + QFAIL("Can't open file for comparison"); + } + QString content = file.readAll(); + QString contentRef = fileRef.readAll(); + + if (content != contentRef) { + appendFileDiff(fileRef.fileName(), file.fileName()); + } + // use split('\n') to avoid + // the whole output shown inline + QCOMPARE(content.split('\n'), contentRef.split('\n')); + QVERIFY(content == contentRef); +} + +void KConfigCompiler_Test::testRunning_data() +{ + QTest::addColumn<QString>("testName"); + + for (const char **it = testCasesToRun; *it; ++it) { + QTest::newRow(*it) << QString::fromLatin1(*it); + } +} + +void KConfigCompiler_Test::testRunning() +{ + QFETCH(QString, testName); + +#ifdef Q_OS_WIN + testName += QStringLiteral(".exe"); +#endif + + QString program = QFINDTESTDATA(testName); + QVERIFY2(QFile::exists(program), qPrintable(program + QLatin1String(" must exist!"))); + QProcess process; + process.start(program, QIODevice::ReadOnly); + if (process.waitForStarted()) { + QVERIFY(process.waitForFinished()); + } + QCOMPARE((int)process.error(), (int)QProcess::UnknownError); + QCOMPARE(process.exitCode(), 0); +} + + +void KConfigCompiler_Test::appendFileDiff(const QString &oldFile, const QString &newFile) +{ + if (m_diffExe.isEmpty()) { + return; + } + if (!m_diff.isOpen()) { + if (!m_diff.open(QIODevice::WriteOnly)) { + return; + } + } + + QStringList args; + args << "-u"; + args << QFileInfo(oldFile).absoluteFilePath(); + args << QFileInfo(newFile).absoluteFilePath(); + + QProcess process; + process.start(m_diffExe, args, QIODevice::ReadOnly); + process.waitForStarted(); + process.waitForFinished(); + if (process.exitCode() == 1) { + QByteArray out = process.readAllStandardOutput(); + m_diff.write(out); + } +} diff --git a/tier1/kconfig/autotests/kconfig_compiler/kconfigcompiler_test.h b/tier1/kconfig/autotests/kconfig_compiler/kconfigcompiler_test.h new file mode 100644 index 00000000..53ad18a0 --- /dev/null +++ b/tier1/kconfig/autotests/kconfig_compiler/kconfigcompiler_test.h @@ -0,0 +1,42 @@ +/* + Tests for KConfig Compiler + + Copyright (c) 2005 by Duncan Mac-Vicar <duncan@kde.org> + Copyright (c) 2009 by Pino Toscano <pino@kde.org> + + ************************************************************************* + * * + * 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 of the License, or (at your option) any later version. * + * * + ************************************************************************* +*/ + +#ifndef KCONFIGCOMPILER_TEST_H +#define KCONFIGCOMPILER_TEST_H + +#include <QtCore/QFile> +#include <QtCore/QObject> + +class QString; + +class KConfigCompiler_Test : public QObject +{ + Q_OBJECT +private Q_SLOTS: + void initTestCase(); + void testBaselineComparison_data(); + void testBaselineComparison(); + void testRunning_data(); + void testRunning(); +private: + void appendFileDiff(const QString &oldFile, const QString &newFile); + + QString m_diffExe; + QFile m_diff; +}; + +#endif + diff --git a/tier1/kconfig/autotests/kconfig_compiler/myprefs.h b/tier1/kconfig/autotests/kconfig_compiler/myprefs.h new file mode 100644 index 00000000..4d12eeb7 --- /dev/null +++ b/tier1/kconfig/autotests/kconfig_compiler/myprefs.h @@ -0,0 +1,12 @@ +#ifndef MYPREFS_H +#define MYPREFS_H + +#include <kconfigskeleton.h> + +class MyPrefs : public KConfigSkeleton +{ + public: + MyPrefs( const QString &a ) : KConfigSkeleton( a ) {} +}; + +#endif diff --git a/tier1/kconfig/autotests/kconfig_compiler/test1.cpp.ref b/tier1/kconfig/autotests/kconfig_compiler/test1.cpp.ref new file mode 100644 index 00000000..611ce5c1 --- /dev/null +++ b/tier1/kconfig/autotests/kconfig_compiler/test1.cpp.ref @@ -0,0 +1,72 @@ +// This file is generated by kconfig_compiler from test1.kcfg. +// All changes you do to this file will be lost. + +#include "test1.h" + +Test1::Test1( const QString & transport, const QString & folder ) + : KConfigSkeleton( QLatin1String( "examplerc" ) ) + , mParamtransport(transport) + , mParamfolder(folder) +{ + setCurrentGroup( QString( QLatin1String( "General-%1" ) ).arg( mParamfolder ) ); + + KConfigSkeleton::ItemBool *itemOneOption; + itemOneOption = new KConfigSkeleton::ItemBool( currentGroup(), QLatin1String( "OneOption" ), mOneOption, true ); + addItem( itemOneOption, QLatin1String( "OneOption" ) ); + KConfigSkeleton::ItemInt *itemAnotherOption; + itemAnotherOption = new KConfigSkeleton::ItemInt( currentGroup(), QLatin1String( "Another Option" ), mAnotherOption, 5 ); + addItem( itemAnotherOption, QLatin1String( "AnotherOption" ) ); + QList<KConfigSkeleton::ItemEnum::Choice> valuesListOption; + { + KConfigSkeleton::ItemEnum::Choice choice; + choice.name = QLatin1String("One"); + valuesListOption.append( choice ); + } + { + KConfigSkeleton::ItemEnum::Choice choice; + choice.name = QLatin1String("Two"); + valuesListOption.append( choice ); + } + { + KConfigSkeleton::ItemEnum::Choice choice; + choice.name = QLatin1String("Three"); + valuesListOption.append( choice ); + } + KConfigSkeleton::ItemEnum *itemListOption; + itemListOption = new KConfigSkeleton::ItemEnum( currentGroup(), QLatin1String( "ListOption" ), mListOption, valuesListOption, EnumListOption::One ); + addItem( itemListOption, QLatin1String( "ListOption" ) ); + + setCurrentGroup( QLatin1String( "MyOptions" ) ); + + KConfigSkeleton::ItemString *itemMyString; + itemMyString = new KConfigSkeleton::ItemString( currentGroup(), QLatin1String( "MyString" ), mMyString, QLatin1String( "Default String" ) ); + addItem( itemMyString, QLatin1String( "MyString" ) ); + KConfigSkeleton::ItemPath *itemMyPath; + itemMyPath = new KConfigSkeleton::ItemPath( currentGroup(), QLatin1String( "MyPath" ), mMyPath, QDir::homePath()+QString::fromLatin1(".hidden_file") ); + addItem( itemMyPath, QLatin1String( "MyPath" ) ); + KConfigSkeleton::ItemInt *itemAnotherOption2; + itemAnotherOption2 = new KConfigSkeleton::ItemInt( currentGroup(), QLatin1String( "Another Option" ), mAnotherOption2, 10 ); + addItem( itemAnotherOption2, QLatin1String( "AnotherOption2" ) ); + QStringList defaultMyStringList; + defaultMyStringList.append( QString::fromUtf8( "up" ) ); + defaultMyStringList.append( QString::fromUtf8( "down" ) ); + + KConfigSkeleton::ItemStringList *itemMyStringList; + itemMyStringList = new KConfigSkeleton::ItemStringList( currentGroup(), QLatin1String( "MyStringList" ), mMyStringList, defaultMyStringList ); + addItem( itemMyStringList, QLatin1String( "MyStringList" ) ); + QStringList defaultMyStringListHidden; + defaultMyStringListHidden.append( QString::fromUtf8( "up" ) ); + defaultMyStringListHidden.append( QString::fromUtf8( "down" ) ); + + KConfigSkeleton::ItemStringList *itemMyStringListHidden; + itemMyStringListHidden = new KConfigSkeleton::ItemStringList( currentGroup(), QLatin1String( "MyStringListHidden" ), mMyStringListHidden, defaultMyStringListHidden ); + addItem( itemMyStringListHidden, QLatin1String( "MyStringListHidden" ) ); + KConfigSkeleton::ItemInt *itemMyNumber; + itemMyNumber = new KConfigSkeleton::ItemInt( currentGroup(), QString( QLatin1String( "List-%1-%2" ) ).arg( mParamtransport ).arg( mParamfolder ), mMyNumber, 1 ); + addItem( itemMyNumber, QLatin1String( "MyNumber" ) ); +} + +Test1::~Test1() +{ +} + diff --git a/tier1/kconfig/autotests/kconfig_compiler/test1.h.ref b/tier1/kconfig/autotests/kconfig_compiler/test1.h.ref new file mode 100644 index 00000000..57fa4bf8 --- /dev/null +++ b/tier1/kconfig/autotests/kconfig_compiler/test1.h.ref @@ -0,0 +1,197 @@ +// This file is generated by kconfig_compiler from test1.kcfg. +// All changes you do to this file will be lost. +#ifndef TEST1_H +#define TEST1_H + +#include <kconfigskeleton.h> +#include <QCoreApplication> +#include <QDebug> + +#include <qdir.h> +class Test1 : public KConfigSkeleton +{ + public: + class EnumListOption + { + public: + enum type { One, Two, Three, COUNT }; + }; + + Test1( const QString & transport, const QString & folder ); + ~Test1(); + + /** + Set One option + */ + void setOneOption( bool v ) + { + if (!isImmutable( QString::fromLatin1( "OneOption" ) )) + mOneOption = v; + } + + /** + Get One option + */ + bool oneOption() const + { + return mOneOption; + } + + /** + Set Another option + */ + void setAnotherOption( int v ) + { + if (!isImmutable( QString::fromLatin1( "AnotherOption" ) )) + mAnotherOption = v; + } + + /** + Get Another option + */ + int anotherOption() const + { + return mAnotherOption; + } + + /** + Set This is some funky option + */ + void setListOption( int v ) + { + if (!isImmutable( QString::fromLatin1( "ListOption" ) )) + mListOption = v; + } + + /** + Get This is some funky option + */ + int listOption() const + { + return mListOption; + } + + /** + Set This is a string + */ + void setMyString( const QString & v ) + { + if (!isImmutable( QString::fromLatin1( "MyString" ) )) + mMyString = v; + } + + /** + Get This is a string + */ + QString myString() const + { + return mMyString; + } + + /** + Set This is a path + */ + void setMyPath( const QString & v ) + { + if (!isImmutable( QString::fromLatin1( "MyPath" ) )) + mMyPath = v; + } + + /** + Get This is a path + */ + QString myPath() const + { + return mMyPath; + } + + /** + Set Another option + */ + void setAnotherOption2( int v ) + { + if (!isImmutable( QString::fromLatin1( "AnotherOption2" ) )) + mAnotherOption2 = v; + } + + /** + Get Another option + */ + int anotherOption2() const + { + return mAnotherOption2; + } + + /** + Set MyStringList + */ + void setMyStringList( const QStringList & v ) + { + if (!isImmutable( QString::fromLatin1( "MyStringList" ) )) + mMyStringList = v; + } + + /** + Get MyStringList + */ + QStringList myStringList() const + { + return mMyStringList; + } + + /** + Set MyStringListHidden + */ + void setMyStringListHidden( const QStringList & v ) + { + if (!isImmutable( QString::fromLatin1( "MyStringListHidden" ) )) + mMyStringListHidden = v; + } + + /** + Get MyStringListHidden + */ + QStringList myStringListHidden() const + { + return mMyStringListHidden; + } + + /** + Set List Number + */ + void setMyNumber( int v ) + { + if (!isImmutable( QString::fromLatin1( "MyNumber" ) )) + mMyNumber = v; + } + + /** + Get List Number + */ + int myNumber() const + { + return mMyNumber; + } + + protected: + QString mParamtransport; + QString mParamfolder; + + // General-$(folder) + bool mOneOption; + int mAnotherOption; + int mListOption; + + // MyOptions + QString mMyString; + QString mMyPath; + int mAnotherOption2; + QStringList mMyStringList; + QStringList mMyStringListHidden; + int mMyNumber; + + private: +}; + +#endif + diff --git a/tier1/kconfig/autotests/kconfig_compiler/test1.kcfg b/tier1/kconfig/autotests/kconfig_compiler/test1.kcfg new file mode 100644 index 00000000..819bdac5 --- /dev/null +++ b/tier1/kconfig/autotests/kconfig_compiler/test1.kcfg @@ -0,0 +1,55 @@ +<?xml version="1.0" encoding="UTF-8"?> +<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0" + 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>qdir.h</include> + <kcfgfile name="examplerc"> + <parameter name="transport" /> + <parameter name="folder" /> + </kcfgfile> + <group name="General-$(folder)"> + <entry name="OneOption" type="Bool"> + <label>One option</label> + <default>true</default> + </entry> + <entry name="AnotherOption" type="Int" key="Another Option"> + <label>Another option</label> + <default>5</default> + </entry> + <entry name="ListOption" type="Enum"> + <label>This is some funky option</label> + <whatsthis>And this is a longer description of this option. Just wondering, how will the translations of those be handled?</whatsthis> + <choices> + <choice name="One"/> + <choice name="Two"/> + <choice name="Three"/> + </choices> + <default>One</default> + </entry> + </group> + <group name="MyOptions"> + <entry name="MyString" type="String"> + <label>This is a string</label> + <default>Default String</default> + </entry> + <entry name="MyPath" type="Path"> + <label>This is a path</label> + <default code="true">QDir::homePath()+QString::fromLatin1(".hidden_file")</default> + </entry> + <entry name="AnotherOption2" type="Int" key="Another Option"> + <label>Another option</label> + <default>10</default> + </entry> + <entry name="MyStringList" type="StringList"> + <default>up,down</default> + </entry> + <entry name="MyStringListHidden" hidden="true" type="StringList"> + <default>up,down</default> + </entry> + <entry name="MyNumber" type="Int" key="List-$(transport)-$(folder)"> + <label>List Number</label> + <default>1</default> + </entry> + </group> +</kcfg> diff --git a/tier1/kconfig/autotests/kconfig_compiler/test1.kcfgc b/tier1/kconfig/autotests/kconfig_compiler/test1.kcfgc new file mode 100644 index 00000000..6e0edd36 --- /dev/null +++ b/tier1/kconfig/autotests/kconfig_compiler/test1.kcfgc @@ -0,0 +1,18 @@ +# Code generation options for kconfig_compiler +ClassName=Test1 +# +# Singleton=false +# +# Inherits=KConfigSkeleton +# +# IncludeFiles=libkdepim/kpimprefs.h +# +# MemberVariables=public +# +### The following line includes the file exampleprefs_base_addon.h +### It can be used to add extra functions and variables to the +### class. +# CustomAdditions=true +# +### Provide setFooBar(int) style functions +Mutators=true diff --git a/tier1/kconfig/autotests/kconfig_compiler/test10.cpp.ref b/tier1/kconfig/autotests/kconfig_compiler/test10.cpp.ref new file mode 100644 index 00000000..ac28ab2f --- /dev/null +++ b/tier1/kconfig/autotests/kconfig_compiler/test10.cpp.ref @@ -0,0 +1,46 @@ +// This file is generated by kconfig_compiler from test10.kcfg. +// All changes you do to this file will be lost. + +#include "test10.h" + +#include <qglobal.h> +#include <QtCore/QFile> + +class Test10Helper +{ + public: + Test10Helper() : q(0) {} + ~Test10Helper() { delete q; } + Test10 *q; +}; +Q_GLOBAL_STATIC(Test10Helper, s_globalTest10) +Test10 *Test10::self() +{ + if (!s_globalTest10()->q) { + new Test10; + s_globalTest10()->q->readConfig(); + } + + return s_globalTest10()->q; +} + +Test10::Test10( ) + : KConfigSkeleton( QLatin1String( "test10rc" ) ) +{ + Q_ASSERT(!s_globalTest10()->q); + s_globalTest10()->q = this; + setCurrentGroup( QLatin1String( "Foo" ) ); + + KConfigSkeleton::ItemUrl *itemFooBar; + itemFooBar = new KConfigSkeleton::ItemUrl( currentGroup(), QLatin1String( "foo bar" ), mFooBar ); + addItem( itemFooBar, QLatin1String( "FooBar" ) ); + KConfigSkeleton::ItemUrlList *itemBarFoo; + itemBarFoo = new KConfigSkeleton::ItemUrlList( currentGroup(), QLatin1String( "bar foo" ), mBarFoo ); + addItem( itemBarFoo, QLatin1String( "BarFoo" ) ); +} + +Test10::~Test10() +{ + s_globalTest10()->q = 0; +} + diff --git a/tier1/kconfig/autotests/kconfig_compiler/test10.h.ref b/tier1/kconfig/autotests/kconfig_compiler/test10.h.ref new file mode 100644 index 00000000..f3f441d3 --- /dev/null +++ b/tier1/kconfig/autotests/kconfig_compiler/test10.h.ref @@ -0,0 +1,50 @@ +// This file is generated by kconfig_compiler from test10.kcfg. +// All changes you do to this file will be lost. +#ifndef TEST10_H +#define TEST10_H + +#include <kconfigskeleton.h> +#include <QCoreApplication> +#include <QDebug> + +class Test10 : public KConfigSkeleton +{ + public: + + static Test10 *self(); + ~Test10(); + + + /** + Get foo bar + */ + static + QUrl fooBar() + { + return self()->mFooBar; + } + + + /** + Get bar foo + */ + static + QList<QUrl> barFoo() + { + return self()->mBarFoo; + } + + protected: + Test10(); + friend class Test10Helper; + + + // Foo + QUrl mFooBar; + QList<QUrl> mBarFoo; + + private: +}; + +#endif + diff --git a/tier1/kconfig/autotests/kconfig_compiler/test10.kcfg b/tier1/kconfig/autotests/kconfig_compiler/test10.kcfg new file mode 100644 index 00000000..d7be2c3d --- /dev/null +++ b/tier1/kconfig/autotests/kconfig_compiler/test10.kcfg @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="UTF-8"?> +<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0" + 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" > + <kcfgfile name="test10rc"/> + + <group name="Foo"> + <entry name="FooBar" key="foo bar" type="Url"/> + <entry name="BarFoo" key="bar foo" type="UrlList"/> + </group> + +</kcfg> diff --git a/tier1/kconfig/autotests/kconfig_compiler/test10.kcfgc b/tier1/kconfig/autotests/kconfig_compiler/test10.kcfgc new file mode 100644 index 00000000..83ac2111 --- /dev/null +++ b/tier1/kconfig/autotests/kconfig_compiler/test10.kcfgc @@ -0,0 +1,4 @@ +# Code generation options for kconfig_compiler +File=test10.kcfg +ClassName=Test10 +Singleton=true diff --git a/tier1/kconfig/autotests/kconfig_compiler/test10main.cpp b/tier1/kconfig/autotests/kconfig_compiler/test10main.cpp new file mode 100644 index 00000000..9e9a7db8 --- /dev/null +++ b/tier1/kconfig/autotests/kconfig_compiler/test10main.cpp @@ -0,0 +1,32 @@ +/* +Copyright (c) 2007 Andreas Pakulat <apaku@gmx.de> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#include "test10.h" +#include <QGuiApplication> + +int main( int argc, char **argv ) +{ + QGuiApplication app(argc, argv); + Q_UNUSED(app); + Test10 *t = Test10::self(); + delete t; + return 0; +} diff --git a/tier1/kconfig/autotests/kconfig_compiler/test11.cpp.ref b/tier1/kconfig/autotests/kconfig_compiler/test11.cpp.ref new file mode 100644 index 00000000..5a1f5b92 --- /dev/null +++ b/tier1/kconfig/autotests/kconfig_compiler/test11.cpp.ref @@ -0,0 +1,278 @@ +// This file is generated by kconfig_compiler from test11.kcfg. +// All changes you do to this file will be lost. + +#include "test11.h" + +Test11::Test11( ) + : MyPrefs( QLatin1String( "korganizerrc" ) ) +{ + setCurrentGroup( QLatin1String( "General" ) ); + + mAutoSaveItem = new MyPrefs::ItemBool( currentGroup(), QLatin1String( "Auto Save" ), mAutoSave, false ); + mAutoSaveItem->setLabel( QCoreApplication::translate("Test11", "Enable automatic saving of calendar") ); + mAutoSaveItem->setWhatsThis( QCoreApplication::translate("Test11", "WhatsThis text for AutoSave option") ); + addItem( mAutoSaveItem, QLatin1String( "AutoSave" ) ); + mAutoSaveIntervalItem = new MyPrefs::ItemInt( currentGroup(), QLatin1String( "Auto Save Interval" ), mAutoSaveInterval, 10 ); + mAutoSaveIntervalItem->setLabel( QCoreApplication::translate("Test11", "Auto Save Interval") ); + addItem( mAutoSaveIntervalItem, QLatin1String( "AutoSaveInterval" ) ); + mConfirmItem = new MyPrefs::ItemBool( currentGroup(), QLatin1String( "Confirm Deletes" ), mConfirm, true ); + mConfirmItem->setLabel( QCoreApplication::translate("Test11", "Confirm deletes") ); + addItem( mConfirmItem, QLatin1String( "Confirm" ) ); + mArchiveFileItem = new MyPrefs::ItemString( currentGroup(), QLatin1String( "Archive File" ), mArchiveFile ); + mArchiveFileItem->setLabel( QCoreApplication::translate("Test11", "Archive File") ); + addItem( mArchiveFileItem, QLatin1String( "ArchiveFile" ) ); + QList<MyPrefs::ItemEnum::Choice> valuesDestination; + { + MyPrefs::ItemEnum::Choice choice; + choice.name = QLatin1String("standardDestination"); + valuesDestination.append( choice ); + } + { + MyPrefs::ItemEnum::Choice choice; + choice.name = QLatin1String("askDestination"); + valuesDestination.append( choice ); + } + { + MyPrefs::ItemEnum::Choice choice; + choice.name = QLatin1String("argl1"); + choice.label = QCoreApplication::translate("Test11", "Argl1 Label"); + valuesDestination.append( choice ); + } + { + MyPrefs::ItemEnum::Choice choice; + choice.name = QLatin1String("argl2"); + choice.whatsThis = QCoreApplication::translate("Test11", "Argl2 Whatsthis"); + valuesDestination.append( choice ); + } + { + MyPrefs::ItemEnum::Choice choice; + choice.name = QLatin1String("argl3"); + choice.label = QCoreApplication::translate("Test11", "Argl3 Label"); + choice.whatsThis = QCoreApplication::translate("Test11", "Argl3 Whatsthis"); + valuesDestination.append( choice ); + } + mDestinationItem = new MyPrefs::ItemEnum( currentGroup(), QLatin1String( "Destination" ), mDestination, valuesDestination, EnumDestination::standardDestination ); + mDestinationItem->setLabel( QCoreApplication::translate("Test11", "New Events/Todos Should") ); + addItem( mDestinationItem, QLatin1String( "Destination" ) ); + + setCurrentGroup( QLatin1String( "Views" ) ); + + mHourSizeItem = new MyPrefs::ItemInt( currentGroup(), QLatin1String( "Hour Size" ), mHourSize, 10 ); + mHourSizeItem->setLabel( QCoreApplication::translate("Test11", "Hour Size") ); + addItem( mHourSizeItem, QLatin1String( "HourSize" ) ); + mSelectionStartsEditorItem = new MyPrefs::ItemBool( currentGroup(), QLatin1String( "SelectionStartsEditor" ), mSelectionStartsEditor, false ); + mSelectionStartsEditorItem->setLabel( QCoreApplication::translate("Test11", "Time range selection in agenda view starts event editor") ); + addItem( mSelectionStartsEditorItem, QLatin1String( "SelectionStartsEditor" ) ); + + setCurrentGroup( QLatin1String( "KOrganizer Plugins" ) ); + + QStringList defaultSelectedPlugins; + defaultSelectedPlugins.append( QString::fromUtf8( "holidays" ) ); + defaultSelectedPlugins.append( QString::fromUtf8( "webexport" ) ); + + mSelectedPluginsItem = new MyPrefs::ItemStringList( currentGroup(), QLatin1String( "SelectedPlugins" ), mSelectedPlugins, defaultSelectedPlugins ); + mSelectedPluginsItem->setLabel( QCoreApplication::translate("Test11", "SelectedPlugins") ); + addItem( mSelectedPluginsItem, QLatin1String( "SelectedPlugins" ) ); + + setCurrentGroup( QLatin1String( "Colors" ) ); + + mHighlightColorItem = new MyPrefs::ItemColor( currentGroup(), QLatin1String( "Highlight Color" ), mHighlightColor, QColor( 100, 100, 255 ) ); + mHighlightColorItem->setLabel( QCoreApplication::translate("Test11", "Highlight color") ); + addItem( mHighlightColorItem, QLatin1String( "HighlightColor" ) ); + mAgendaBgColorItem = new MyPrefs::ItemColor( currentGroup(), QLatin1String( "Agenda Background Color" ), mAgendaBgColor, QColor( 255, 255, 255 ) ); + mAgendaBgColorItem->setLabel( QCoreApplication::translate("Test11", "Agenda view background color") ); + addItem( mAgendaBgColorItem, QLatin1String( "AgendaBgColor" ) ); + + setCurrentGroup( QLatin1String( "Fonts" ) ); + + mTimeBarFontItem = new MyPrefs::ItemFont( currentGroup(), QLatin1String( "TimeBar Font" ), mTimeBarFont ); + mTimeBarFontItem->setLabel( QCoreApplication::translate("Test11", "Time bar") ); + addItem( mTimeBarFontItem, QLatin1String( "TimeBarFont" ) ); + + setCurrentGroup( QLatin1String( "Email" ) ); + + QList<MyPrefs::ItemEnum::Choice> valuesEmailClient; + { + MyPrefs::ItemEnum::Choice choice; + choice.name = QLatin1String("sendmail"); + choice.label = /*: @option */ QCoreApplication::translate("Test11", "Sendmail"); + valuesEmailClient.append( choice ); + } + { + MyPrefs::ItemEnum::Choice choice; + choice.name = QLatin1String("kmail"); + choice.label = /*: @option */ QCoreApplication::translate("Test11", "KMail"); + valuesEmailClient.append( choice ); + } + mEmailClientItem = new MyPrefs::ItemEnum( currentGroup(), QLatin1String( "EmailClient" ), mEmailClient, valuesEmailClient, kmail ); + mEmailClientItem->setLabel( /*: @label */ QCoreApplication::translate("Test11", "Email client") ); + mEmailClientItem->setWhatsThis( /*: @info:whatsthis */ QCoreApplication::translate("Test11", "<para>How to send email when an email alarm is triggered.<list><item>KMail: The email is sent automatically via <application>KMail</application>. <application>KMail</application> is started first if necessary.</item><item>Sendmail: The email is sent automatically. This option will only work if your system is configured to use <application>sendmail</application> or a sendmail compatible mail transport agent.</item></list></para>") ); + addItem( mEmailClientItem, QLatin1String( "EmailClient" ) ); + QList<MyPrefs::ItemEnum::Choice> valuesDefaultReminderUnits; + { + MyPrefs::ItemEnum::Choice choice; + choice.name = QLatin1String("Minutes"); + valuesDefaultReminderUnits.append( choice ); + } + { + MyPrefs::ItemEnum::Choice choice; + choice.name = QLatin1String("HoursMinutes"); + choice.label = /*: @option */ QCoreApplication::translate("Test11", "Hours/Minutes"); + valuesDefaultReminderUnits.append( choice ); + } + mDefaultReminderUnitsItem = new MyPrefs::ItemEnum( currentGroup(), QLatin1String( "RemindUnits" ), mDefaultReminderUnits, valuesDefaultReminderUnits, TimePeriod::HoursMinutes ); + mDefaultReminderUnitsItem->setLabel( /*: @label */ QCoreApplication::translate("Test11", "Reminder units") ); + mDefaultReminderUnitsItem->setToolTip( /*: @info:tooltip */ QCoreApplication::translate("Test11", "Default reminder time units in the alarm edit dialog.") ); + mDefaultReminderUnitsItem->setWhatsThis( /*: @info:whatsthis */ QCoreApplication::translate("Test11", "Default reminder time units in the alarm edit dialog.") ); + addItem( mDefaultReminderUnitsItem, QLatin1String( "DefaultReminderUnits" ) ); + + setCurrentGroup( QLatin1String( "QueueRates" ) ); + + QList< QList<int> > defaultRate; + QList< int > defaultRateInit; + + defaultRateInit.append( 15 ); + defaultRateInit.append( 60 ); + defaultRateInit.append( 0 ); + defaultRate.append( defaultRateInit ); + + defaultRateInit.clear(); + defaultRateInit.append( 40 ); + defaultRateInit.append( 60 ); + defaultRateInit.append( 0 ); + defaultRate.append( defaultRateInit ); + + defaultRateInit.clear(); + defaultRateInit.append( 1 ); + defaultRateInit.append( 1 ); + defaultRateInit.append( 0 ); + defaultRate.append( defaultRateInit ); + + QList<int> defaultqueueRate; + + mQueueRateItem[0] = new MyPrefs::ItemIntList( currentGroup(), QLatin1String( "EmptyingRate 0" ), mQueueRate[0], defaultRate[0] ); + mQueueRateItem[0]->setLabel( QCoreApplication::translate("Test11", "EmptyingRate queueRate$(QueueIndex)") ); + addItem( mQueueRateItem[0], QLatin1String( "queueRate0" ) ); + mQueueRateItem[1] = new MyPrefs::ItemIntList( currentGroup(), QLatin1String( "EmptyingRate 1" ), mQueueRate[1], defaultqueueRate ); + mQueueRateItem[1]->setLabel( QCoreApplication::translate("Test11", "EmptyingRate queueRate$(QueueIndex)") ); + addItem( mQueueRateItem[1], QLatin1String( "queueRate1" ) ); + mQueueRateItem[2] = new MyPrefs::ItemIntList( currentGroup(), QLatin1String( "EmptyingRate 2" ), mQueueRate[2], defaultRate[2] ); + mQueueRateItem[2]->setLabel( QCoreApplication::translate("Test11", "EmptyingRate queueRate$(QueueIndex)") ); + addItem( mQueueRateItem[2], QLatin1String( "queueRate2" ) ); + mShowQueueTunerItem = new MyPrefs::ItemBool( currentGroup(), QLatin1String( "ShowQueueTuner" ), mShowQueueTuner, false ); + mShowQueueTunerItem->setLabel( QCoreApplication::translate("Test11", "ShowQueueTuner") ); + addItem( mShowQueueTunerItem, QLatin1String( "ShowQueueTuner" ) ); +} + +bool Test11::defaultAutoSaveValue_helper() const +{ + + return false; +} + +int Test11::defaultAutoSaveIntervalValue_helper() const +{ + + return 10; +} + +bool Test11::defaultConfirmValue_helper() const +{ + + return true; +} + +int Test11::defaultDestinationValue_helper() const +{ + + return EnumDestination::standardDestination; +} + +int Test11::defaultHourSizeValue_helper() const +{ + + return 10; +} + +bool Test11::defaultSelectionStartsEditorValue_helper() const +{ + + return false; +} + +QStringList Test11::defaultSelectedPluginsValue_helper() const +{ + QStringList defaultSelectedPlugins; + defaultSelectedPlugins.append( QString::fromUtf8( "holidays" ) ); + defaultSelectedPlugins.append( QString::fromUtf8( "webexport" ) ); + + return defaultSelectedPlugins; +} + +QColor Test11::defaultHighlightColorValue_helper() const +{ + + return QColor( 100, 100, 255 ); +} + +QColor Test11::defaultAgendaBgColorValue_helper() const +{ + + return QColor( 255, 255, 255 ); +} + +int Test11::defaultEmailClientValue_helper() const +{ + + return kmail; +} + +int Test11::defaultDefaultReminderUnitsValue_helper() const +{ + + return TimePeriod::HoursMinutes; +} + +QList<int> Test11::defaultQueueRateValue_helper( int i ) const +{ + QList< QList<int> > defaultRate; + QList< int > defaultRateInit; + + defaultRateInit.append( 15 ); + defaultRateInit.append( 60 ); + defaultRateInit.append( 0 ); + defaultRate.append( defaultRateInit ); + + defaultRateInit.clear(); + defaultRateInit.append( 40 ); + defaultRateInit.append( 60 ); + defaultRateInit.append( 0 ); + defaultRate.append( defaultRateInit ); + + defaultRateInit.clear(); + defaultRateInit.append( 1 ); + defaultRateInit.append( 1 ); + defaultRateInit.append( 0 ); + defaultRate.append( defaultRateInit ); + + QList<int> defaultqueueRate; + + switch (i) { + case 0: return defaultRate[0]; + case 2: return defaultRate[2]; + default: + return defaultqueueRate; + } + +} + +bool Test11::defaultShowQueueTunerValue_helper() const +{ + + return false; +} + +Test11::~Test11() +{ +} + diff --git a/tier1/kconfig/autotests/kconfig_compiler/test11.h.ref b/tier1/kconfig/autotests/kconfig_compiler/test11.h.ref new file mode 100644 index 00000000..b5eeb74c --- /dev/null +++ b/tier1/kconfig/autotests/kconfig_compiler/test11.h.ref @@ -0,0 +1,572 @@ +// This file is generated by kconfig_compiler from test11.kcfg. +// All changes you do to this file will be lost. +#ifndef TEST11_H +#define TEST11_H + +#include <myprefs.h> + +#include <qglobal.h> +#include <kconfigskeleton.h> +#include <QCoreApplication> +#include <QDebug> + +#include "test11_types.h" +class Test11 : public MyPrefs +{ + public: + class EnumDestination + { + public: + enum type { standardDestination, askDestination, argl1, argl2, argl3, COUNT }; + }; + enum MailClient { sendmail, kmail }; + + Test11( ); + ~Test11(); + + /** + Set Enable automatic saving of calendar + */ + void setAutoSave( bool v ) + { + if (!isImmutable( QString::fromLatin1( "AutoSave" ) )) + mAutoSave = v; + } + + /** + Get Enable automatic saving of calendar + */ + bool autoSave() const + { + return mAutoSave; + } + + /** + Get Enable automatic saving of calendar default value + */ + bool defaultAutoSaveValue() const + { + return defaultAutoSaveValue_helper(); + } + + /** + Get Item object corresponding to AutoSave() + */ + ItemBool *autoSaveItem() + { + return mAutoSaveItem; + } + + /** + Set Auto Save Interval + */ + void setAutoSaveInterval( int v ) + { + if (!isImmutable( QString::fromLatin1( "AutoSaveInterval" ) )) + mAutoSaveInterval = v; + } + + /** + Get Auto Save Interval + */ + int autoSaveInterval() const + { + return mAutoSaveInterval; + } + + /** + Get Auto Save Interval default value + */ + int defaultAutoSaveIntervalValue() const + { + return defaultAutoSaveIntervalValue_helper(); + } + + /** + Get Item object corresponding to AutoSaveInterval() + */ + ItemInt *autoSaveIntervalItem() + { + return mAutoSaveIntervalItem; + } + + /** + Set Confirm deletes + */ + void setConfirm( bool v ) + { + if (!isImmutable( QString::fromLatin1( "Confirm" ) )) + mConfirm = v; + } + + /** + Get Confirm deletes + */ + bool confirm() const + { + return mConfirm; + } + + /** + Get Confirm deletes default value + */ + bool defaultConfirmValue() const + { + return defaultConfirmValue_helper(); + } + + /** + Get Item object corresponding to Confirm() + */ + ItemBool *confirmItem() + { + return mConfirmItem; + } + + /** + Set Archive File + */ + void setArchiveFile( const QString & v ) + { + if (!isImmutable( QString::fromLatin1( "ArchiveFile" ) )) + mArchiveFile = v; + } + + /** + Get Archive File + */ + QString archiveFile() const + { + return mArchiveFile; + } + + /** + Get Item object corresponding to ArchiveFile() + */ + ItemString *archiveFileItem() + { + return mArchiveFileItem; + } + + /** + Set New Events/Todos Should + */ + void setDestination( EnumDestination::type v ) + { + if (!isImmutable( QString::fromLatin1( "Destination" ) )) + mDestination = v; + } + + /** + Get New Events/Todos Should + */ + EnumDestination::type destination() const + { + return static_cast<EnumDestination::type>(mDestination); + } + + /** + Get New Events/Todos Should default value + */ + EnumDestination::type defaultDestinationValue() const + { + return static_cast<EnumDestination::type>(defaultDestinationValue_helper()); + } + + /** + Get Item object corresponding to Destination() + */ + ItemEnum *destinationItem() + { + return mDestinationItem; + } + + /** + Set Hour Size + */ + void setHourSize( int v ) + { + if (!isImmutable( QString::fromLatin1( "HourSize" ) )) + mHourSize = v; + } + + /** + Get Hour Size + */ + int hourSize() const + { + return mHourSize; + } + + /** + Get Hour Size default value + */ + int defaultHourSizeValue() const + { + return defaultHourSizeValue_helper(); + } + + /** + Get Item object corresponding to HourSize() + */ + ItemInt *hourSizeItem() + { + return mHourSizeItem; + } + + /** + Set Time range selection in agenda view starts event editor + */ + void setSelectionStartsEditor( bool v ) + { + if (!isImmutable( QString::fromLatin1( "SelectionStartsEditor" ) )) + mSelectionStartsEditor = v; + } + + /** + Get Time range selection in agenda view starts event editor + */ + bool selectionStartsEditor() const + { + return mSelectionStartsEditor; + } + + /** + Get Time range selection in agenda view starts event editor default value + */ + bool defaultSelectionStartsEditorValue() const + { + return defaultSelectionStartsEditorValue_helper(); + } + + /** + Get Item object corresponding to SelectionStartsEditor() + */ + ItemBool *selectionStartsEditorItem() + { + return mSelectionStartsEditorItem; + } + + /** + Set SelectedPlugins + */ + void setSelectedPlugins( const QStringList & v ) + { + if (!isImmutable( QString::fromLatin1( "SelectedPlugins" ) )) + mSelectedPlugins = v; + } + + /** + Get SelectedPlugins + */ + QStringList selectedPlugins() const + { + return mSelectedPlugins; + } + + /** + Get SelectedPlugins default value + */ + QStringList defaultSelectedPluginsValue() const + { + return defaultSelectedPluginsValue_helper(); + } + + /** + Get Item object corresponding to SelectedPlugins() + */ + ItemStringList *selectedPluginsItem() + { + return mSelectedPluginsItem; + } + + /** + Set Highlight color + */ + void setHighlightColor( const QColor & v ) + { + if (!isImmutable( QString::fromLatin1( "HighlightColor" ) )) + mHighlightColor = v; + } + + /** + Get Highlight color + */ + QColor highlightColor() const + { + return mHighlightColor; + } + + /** + Get Highlight color default value + */ + QColor defaultHighlightColorValue() const + { + return defaultHighlightColorValue_helper(); + } + + /** + Get Item object corresponding to HighlightColor() + */ + ItemColor *highlightColorItem() + { + return mHighlightColorItem; + } + + /** + Set Agenda view background color + */ + void setAgendaBgColor( const QColor & v ) + { + if (!isImmutable( QString::fromLatin1( "AgendaBgColor" ) )) + mAgendaBgColor = v; + } + + /** + Get Agenda view background color + */ + QColor agendaBgColor() const + { + return mAgendaBgColor; + } + + /** + Get Agenda view background color default value + */ + QColor defaultAgendaBgColorValue() const + { + return defaultAgendaBgColorValue_helper(); + } + + /** + Get Item object corresponding to AgendaBgColor() + */ + ItemColor *agendaBgColorItem() + { + return mAgendaBgColorItem; + } + + /** + Set Time bar + */ + void setTimeBarFont( const QFont & v ) + { + if (!isImmutable( QString::fromLatin1( "TimeBarFont" ) )) + mTimeBarFont = v; + } + + /** + Get Time bar + */ + QFont timeBarFont() const + { + return mTimeBarFont; + } + + /** + Get Item object corresponding to TimeBarFont() + */ + ItemFont *timeBarFontItem() + { + return mTimeBarFontItem; + } + + /** + Set Email client + */ + void setEmailClient( MailClient v ) + { + if (!isImmutable( QString::fromLatin1( "EmailClient" ) )) + mEmailClient = v; + } + + /** + Get Email client + */ + MailClient emailClient() const + { + return static_cast<MailClient>(mEmailClient); + } + + /** + Get Email client default value + */ + MailClient defaultEmailClientValue() const + { + return static_cast<MailClient>(defaultEmailClientValue_helper()); + } + + /** + Get Item object corresponding to EmailClient() + */ + ItemEnum *emailClientItem() + { + return mEmailClientItem; + } + + /** + Set Reminder units + */ + void setDefaultReminderUnits( TimePeriod::Units v ) + { + if (!isImmutable( QString::fromLatin1( "DefaultReminderUnits" ) )) + mDefaultReminderUnits = v; + } + + /** + Get Reminder units + */ + TimePeriod::Units defaultReminderUnits() const + { + return static_cast<TimePeriod::Units>(mDefaultReminderUnits); + } + + /** + Get Reminder units default value + */ + TimePeriod::Units defaultDefaultReminderUnitsValue() const + { + return static_cast<TimePeriod::Units>(defaultDefaultReminderUnitsValue_helper()); + } + + /** + Get Item object corresponding to DefaultReminderUnits() + */ + ItemEnum *defaultReminderUnitsItem() + { + return mDefaultReminderUnitsItem; + } + + /** + Set EmptyingRate $(QueueIndex) + */ + void setQueueRate( int i, const QList<int> & v ) + { + if (!isImmutable( QString::fromLatin1( "queueRate%1" ).arg( i ) )) + mQueueRate[i] = v; + } + + /** + Get EmptyingRate $(QueueIndex) + */ + QList<int> queueRate( int i ) const + { + return mQueueRate[i]; + } + + /** + Get EmptyingRate $(QueueIndex) default value + */ + QList<int> defaultQueueRateValue( int i ) const + { + return defaultQueueRateValue_helper( i ); + } + + /** + Get Item object corresponding to queueRate() + */ + ItemIntList *queueRateItem( int i ) + { + return mQueueRateItem[i]; + } + + /** + Set ShowQueueTuner + */ + void setShowQueueTuner( bool v ) + { + if (!isImmutable( QString::fromLatin1( "ShowQueueTuner" ) )) + mShowQueueTuner = v; + } + + /** + Get ShowQueueTuner + */ + bool showQueueTuner() const + { + return mShowQueueTuner; + } + + /** + Get ShowQueueTuner default value + */ + bool defaultShowQueueTunerValue() const + { + return defaultShowQueueTunerValue_helper(); + } + + /** + Get Item object corresponding to ShowQueueTuner() + */ + ItemBool *showQueueTunerItem() + { + return mShowQueueTunerItem; + } + + protected: + public: + + // General + bool mAutoSave; + bool defaultAutoSaveValue_helper() const; + int mAutoSaveInterval; + int defaultAutoSaveIntervalValue_helper() const; + bool mConfirm; + bool defaultConfirmValue_helper() const; + QString mArchiveFile; + QString defaultArchiveFileValue_helper() const; + int mDestination; + int defaultDestinationValue_helper() const; + + // Views + int mHourSize; + int defaultHourSizeValue_helper() const; + bool mSelectionStartsEditor; + bool defaultSelectionStartsEditorValue_helper() const; + + // KOrganizer Plugins + QStringList mSelectedPlugins; + QStringList defaultSelectedPluginsValue_helper() const; + + // Colors + QColor mHighlightColor; + QColor defaultHighlightColorValue_helper() const; + QColor mAgendaBgColor; + QColor defaultAgendaBgColorValue_helper() const; + + // Fonts + QFont mTimeBarFont; + QFont defaultTimeBarFontValue_helper() const; + + // Email + int mEmailClient; + int defaultEmailClientValue_helper() const; + int mDefaultReminderUnits; + int defaultDefaultReminderUnitsValue_helper() const; + + // QueueRates + QList<int> mQueueRate[3]; + QList<int> defaultQueueRateValue_helper( int i ) const; + bool mShowQueueTuner; + bool defaultShowQueueTunerValue_helper() const; + + private: + ItemBool *mAutoSaveItem; + ItemInt *mAutoSaveIntervalItem; + ItemBool *mConfirmItem; + ItemString *mArchiveFileItem; + ItemEnum *mDestinationItem; + ItemInt *mHourSizeItem; + ItemBool *mSelectionStartsEditorItem; + ItemStringList *mSelectedPluginsItem; + ItemColor *mHighlightColorItem; + ItemColor *mAgendaBgColorItem; + ItemFont *mTimeBarFontItem; + ItemEnum *mEmailClientItem; + ItemEnum *mDefaultReminderUnitsItem; + ItemIntList *mQueueRateItem[3]; + ItemBool *mShowQueueTunerItem; +}; + +#endif + diff --git a/tier1/kconfig/autotests/kconfig_compiler/test11.kcfg b/tier1/kconfig/autotests/kconfig_compiler/test11.kcfg new file mode 100644 index 00000000..d82e1326 --- /dev/null +++ b/tier1/kconfig/autotests/kconfig_compiler/test11.kcfg @@ -0,0 +1,136 @@ +<?xml version="1.0" encoding="UTF-8"?> +<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0" + 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>"test11_types.h"</include> + + <kcfgfile name="korganizerrc"/> + + <group name="General"> + <entry type="Bool" key="Auto Save"> + <label>Enable automatic saving of calendar</label> + <whatsthis>WhatsThis text for AutoSave option</whatsthis> + <default>false</default> + </entry> + <entry type="Int" key="Auto Save Interval"> + <default>10</default> + </entry> + <entry type="Bool" key="Confirm Deletes" name="Confirm"> + <label>Confirm deletes</label> + <default>true</default> + </entry> + <entry type="String" key="Archive File"> + </entry> + <entry type="Enum" key="Destination" name="Destination"> + <label>New Events/Todos Should</label> + <choices> + <choice name="standardDestination"> + </choice> + <choice name="askDestination"> + </choice> + <choice name="argl1"> + <label>Argl1 Label</label> + </choice> + <choice name="argl2"> + <whatsthis>Argl2 Whatsthis</whatsthis> + </choice> + <choice name="argl3"> + <label>Argl3 Label</label> + <whatsthis>Argl3 Whatsthis</whatsthis> + </choice> + </choices> + <default>standardDestination</default> + </entry> + </group> + + <group name="Views"> + <entry type="Int" key="Hour Size"> + <default>10</default> + </entry> + <entry type="Bool" name="SelectionStartsEditor"> + <label>Time range selection in agenda view starts event editor</label> + <default>false</default> + </entry> + </group> + + <group name="KOrganizer Plugins"> + <entry type="StringList" name="SelectedPlugins"> + <default>holidays,webexport</default> + </entry> + </group> + + <group name="Colors"> + <entry type="Color" key="Highlight Color"> + <label>Highlight color</label> + <default>100, 100, 255</default> + </entry> + <entry type="Color" key="Agenda Background Color" name="AgendaBgColor"> + <label>Agenda view background color</label> + <default>255, 255, 255</default> + </entry> + </group> + + <group name="Fonts"> + <entry type="Font" key="TimeBar Font"> + <label>Time bar</label> + </entry> + </group> + + <group name="Email"> + <entry name="EmailClient" key="EmailClient" type="Enum"> + <label context="@label">Email client</label> + <whatsthis context="@info:whatsthis"><para>How to send email when an email alarm is triggered.<list><item>KMail: The email is sent automatically via <application>KMail</application>. <application>KMail</application> is started first if necessary.</item><item>Sendmail: The email is sent automatically. This option will only work if your system is configured to use <application>sendmail</application> or a sendmail compatible mail transport agent.</item></list></para></whatsthis> + <choices name="MailClient"> + <choice name="sendmail"><label context="@option">Sendmail</label></choice> + <choice name="kmail"><label context="@option">KMail</label></choice> + </choices> + <default>kmail</default> + </entry> + + <entry name="DefaultReminderUnits" key="RemindUnits" type="Enum"> + <label context="@label">Reminder units</label> + <whatsthis context="@info:whatsthis">Default reminder time units in the alarm edit dialog.</whatsthis> + <tooltip context="@info:tooltip">Default reminder time units in the alarm edit dialog.</tooltip> + <choices name="TimePeriod::Units"> + <choice name="Minutes"></choice> + <choice name="HoursMinutes"><label context="@option">Hours/Minutes</label></choice> + </choices> + <default>HoursMinutes</default> + </entry> + </group> + + <group name="QueueRates"> + <entry name="queueRate$(QueueIndex)" type="IntList" key="EmptyingRate $(QueueIndex)"> + <!-- kconfig_compiler really should do this for me... --> + <code> QList< QList<int> > defaultRate; + QList< int > defaultRateInit; + + defaultRateInit.append( 15 ); + defaultRateInit.append( 60 ); + defaultRateInit.append( 0 ); + defaultRate.append( defaultRateInit ); + + defaultRateInit.clear(); + defaultRateInit.append( 40 ); + defaultRateInit.append( 60 ); + defaultRateInit.append( 0 ); + defaultRate.append( defaultRateInit ); + + defaultRateInit.clear(); + defaultRateInit.append( 1 ); + defaultRateInit.append( 1 ); + defaultRateInit.append( 0 ); + defaultRate.append( defaultRateInit ); + </code> + <parameter name="QueueIndex" type="Int" max="2"/> + <default param="0" code="true">defaultRate[0]</default> + <default param="2" code="true">defaultRate[2]</default> + </entry> + <entry key="ShowQueueTuner" type="Bool"> + <default>false</default> + </entry> + </group> + +</kcfg> diff --git a/tier1/kconfig/autotests/kconfig_compiler/test11.kcfgc b/tier1/kconfig/autotests/kconfig_compiler/test11.kcfgc new file mode 100644 index 00000000..2b6fee15 --- /dev/null +++ b/tier1/kconfig/autotests/kconfig_compiler/test11.kcfgc @@ -0,0 +1,13 @@ +# Code generation options for kconfig_compiler +File=test11.kcfg +ClassName=Test11 +Singleton=false +Mutators=true +Inherits=MyPrefs +IncludeFiles=myprefs.h +MemberVariables=public +GlobalEnums=false +ItemAccessors=true +SetUserTexts=true +UseEnumTypes=true +DefaultValueGetters=true diff --git a/tier1/kconfig/autotests/kconfig_compiler/test11_types.h b/tier1/kconfig/autotests/kconfig_compiler/test11_types.h new file mode 100644 index 00000000..5b21aa97 --- /dev/null +++ b/tier1/kconfig/autotests/kconfig_compiler/test11_types.h @@ -0,0 +1,31 @@ +/* +Copyright (c) 2009 Pino Toscano <pino@kde.org> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#ifndef TEST11_TYPES_H +#define TEST11_TYPES_H + +class TimePeriod +{ +public: + enum Units { Minutes, HoursMinutes, Days, Weeks }; +}; + +#endif diff --git a/tier1/kconfig/autotests/kconfig_compiler/test11a.cpp.ref b/tier1/kconfig/autotests/kconfig_compiler/test11a.cpp.ref new file mode 100644 index 00000000..f826fc16 --- /dev/null +++ b/tier1/kconfig/autotests/kconfig_compiler/test11a.cpp.ref @@ -0,0 +1,187 @@ +// This file is generated by kconfig_compiler from test11a.kcfg. +// All changes you do to this file will be lost. + +#include "test11a.h" + +Test11a::Test11a( ) + : MyPrefs( QLatin1String( "korganizerrc" ) ) +{ + setCurrentGroup( QLatin1String( "General" ) ); + + mAutoSaveItem = new MyPrefs::ItemBool( currentGroup(), QLatin1String( "Auto Save" ), mAutoSave, false ); + mAutoSaveItem->setLabel( QCoreApplication::translate("Test11a", "Enable automatic saving of calendar") ); + mAutoSaveItem->setWhatsThis( QCoreApplication::translate("Test11a", "WhatsThis text for AutoSave option") ); + addItem( mAutoSaveItem, QLatin1String( "AutoSave" ) ); + mAutoSaveIntervalItem = new MyPrefs::ItemInt( currentGroup(), QLatin1String( "Auto Save Interval" ), mAutoSaveInterval, 10 ); + mAutoSaveIntervalItem->setLabel( QCoreApplication::translate("Test11a", "Auto Save Interval") ); + addItem( mAutoSaveIntervalItem, QLatin1String( "AutoSaveInterval" ) ); + mConfirmItem = new MyPrefs::ItemBool( currentGroup(), QLatin1String( "Confirm Deletes" ), mConfirm, true ); + mConfirmItem->setLabel( QCoreApplication::translate("Test11a", "Confirm deletes") ); + addItem( mConfirmItem, QLatin1String( "Confirm" ) ); + mArchiveFileItem = new MyPrefs::ItemString( currentGroup(), QLatin1String( "Archive File" ), mArchiveFile ); + mArchiveFileItem->setLabel( QCoreApplication::translate("Test11a", "Archive File") ); + addItem( mArchiveFileItem, QLatin1String( "ArchiveFile" ) ); + QList<MyPrefs::ItemEnum::Choice> valuesDestination; + { + MyPrefs::ItemEnum::Choice choice; + choice.name = QLatin1String("standardDestination"); + valuesDestination.append( choice ); + } + { + MyPrefs::ItemEnum::Choice choice; + choice.name = QLatin1String("askDestination"); + valuesDestination.append( choice ); + } + { + MyPrefs::ItemEnum::Choice choice; + choice.name = QLatin1String("argl1"); + choice.label = QCoreApplication::translate("Test11a", "Argl1 Label"); + valuesDestination.append( choice ); + } + { + MyPrefs::ItemEnum::Choice choice; + choice.name = QLatin1String("argl2"); + choice.whatsThis = QCoreApplication::translate("Test11a", "Argl2 Whatsthis"); + valuesDestination.append( choice ); + } + { + MyPrefs::ItemEnum::Choice choice; + choice.name = QLatin1String("argl3"); + choice.label = QCoreApplication::translate("Test11a", "Argl3 Label"); + choice.whatsThis = QCoreApplication::translate("Test11a", "Argl3 Whatsthis"); + valuesDestination.append( choice ); + } + mDestinationItem = new MyPrefs::ItemEnum( currentGroup(), QLatin1String( "Destination" ), mDestination, valuesDestination, EnumDestination::standardDestination ); + mDestinationItem->setLabel( QCoreApplication::translate("Test11a", "New Events/Todos Should") ); + addItem( mDestinationItem, QLatin1String( "Destination" ) ); + + setCurrentGroup( QLatin1String( "Views" ) ); + + mHourSizeItem = new MyPrefs::ItemInt( currentGroup(), QLatin1String( "Hour Size" ), mHourSize, 10 ); + mHourSizeItem->setLabel( QCoreApplication::translate("Test11a", "Hour Size") ); + addItem( mHourSizeItem, QLatin1String( "HourSize" ) ); + mSelectionStartsEditorItem = new MyPrefs::ItemBool( currentGroup(), QLatin1String( "SelectionStartsEditor" ), mSelectionStartsEditor, false ); + mSelectionStartsEditorItem->setLabel( QCoreApplication::translate("Test11a", "Time range selection in agenda view starts event editor") ); + addItem( mSelectionStartsEditorItem, QLatin1String( "SelectionStartsEditor" ) ); + + setCurrentGroup( QLatin1String( "KOrganizer Plugins" ) ); + + QStringList defaultSelectedPlugins; + defaultSelectedPlugins.append( QString::fromUtf8( "holidays" ) ); + defaultSelectedPlugins.append( QString::fromUtf8( "webexport" ) ); + + mSelectedPluginsItem = new MyPrefs::ItemStringList( currentGroup(), QLatin1String( "SelectedPlugins" ), mSelectedPlugins, defaultSelectedPlugins ); + mSelectedPluginsItem->setLabel( QCoreApplication::translate("Test11a", "SelectedPlugins") ); + addItem( mSelectedPluginsItem, QLatin1String( "SelectedPlugins" ) ); + + setCurrentGroup( QLatin1String( "Colors" ) ); + + mHighlightColorItem = new MyPrefs::ItemColor( currentGroup(), QLatin1String( "Highlight Color" ), mHighlightColor, QColor( 100, 100, 255 ) ); + mHighlightColorItem->setLabel( QCoreApplication::translate("Test11a", "Highlight color") ); + addItem( mHighlightColorItem, QLatin1String( "HighlightColor" ) ); + mAgendaBgColorItem = new MyPrefs::ItemColor( currentGroup(), QLatin1String( "Agenda Background Color" ), mAgendaBgColor, QColor( 255, 255, 255 ) ); + mAgendaBgColorItem->setLabel( QCoreApplication::translate("Test11a", "Agenda view background color") ); + addItem( mAgendaBgColorItem, QLatin1String( "AgendaBgColor" ) ); + + setCurrentGroup( QLatin1String( "Fonts" ) ); + + mTimeBarFontItem = new MyPrefs::ItemFont( currentGroup(), QLatin1String( "TimeBar Font" ), mTimeBarFont ); + mTimeBarFontItem->setLabel( QCoreApplication::translate("Test11a", "Time bar") ); + addItem( mTimeBarFontItem, QLatin1String( "TimeBarFont" ) ); + + setCurrentGroup( QLatin1String( "Email" ) ); + + QList<MyPrefs::ItemEnum::Choice> valuesEmailClient; + { + MyPrefs::ItemEnum::Choice choice; + choice.name = QLatin1String("sendmail"); + choice.label = /*: @option */ QCoreApplication::translate("Test11a", "Sendmail"); + valuesEmailClient.append( choice ); + } + { + MyPrefs::ItemEnum::Choice choice; + choice.name = QLatin1String("kmail"); + choice.label = /*: @option */ QCoreApplication::translate("Test11a", "KMail"); + valuesEmailClient.append( choice ); + } + mEmailClientItem = new MyPrefs::ItemEnum( currentGroup(), QLatin1String( "EmailClient" ), mEmailClient, valuesEmailClient, kmail ); + mEmailClientItem->setLabel( /*: @label */ QCoreApplication::translate("Test11a", "Email client") ); + mEmailClientItem->setWhatsThis( /*: @info:whatsthis */ QCoreApplication::translate("Test11a", "<para>How to send email when an email alarm is triggered.<list><item>KMail: The email is sent automatically via <application>KMail</application>. <application>KMail</application> is started first if necessary.</item><item>Sendmail: The email is sent automatically. This option will only work if your system is configured to use <application>sendmail</application> or a sendmail compatible mail transport agent.</item></list></para>") ); + addItem( mEmailClientItem, QLatin1String( "EmailClient" ) ); + QList<MyPrefs::ItemEnum::Choice> valuesDefaultReminderUnits; + { + MyPrefs::ItemEnum::Choice choice; + choice.name = QLatin1String("Minutes"); + valuesDefaultReminderUnits.append( choice ); + } + { + MyPrefs::ItemEnum::Choice choice; + choice.name = QLatin1String("HoursMinutes"); + choice.label = /*: @option */ QCoreApplication::translate("Test11a", "Hours/Minutes"); + valuesDefaultReminderUnits.append( choice ); + } + mDefaultReminderUnitsItem = new MyPrefs::ItemEnum( currentGroup(), QLatin1String( "RemindUnits" ), mDefaultReminderUnits, valuesDefaultReminderUnits, TimePeriod::HoursMinutes ); + mDefaultReminderUnitsItem->setLabel( /*: @label */ QCoreApplication::translate("Test11a", "Reminder units") ); + mDefaultReminderUnitsItem->setWhatsThis( /*: @info:whatsthis */ QCoreApplication::translate("Test11a", "Default reminder time units in the alarm edit dialog.") ); + addItem( mDefaultReminderUnitsItem, QLatin1String( "DefaultReminderUnits" ) ); + + setCurrentGroup( QLatin1String( "QueueRates" ) ); + + QList< QList<int> > defaultRate; + QList< int > defaultRateInit; + + defaultRateInit.append( 15 ); + defaultRateInit.append( 60 ); + defaultRateInit.append( 0 ); + defaultRate.append( defaultRateInit ); + + defaultRateInit.clear(); + defaultRateInit.append( 40 ); + defaultRateInit.append( 60 ); + defaultRateInit.append( 0 ); + defaultRate.append( defaultRateInit ); + + defaultRateInit.clear(); + defaultRateInit.append( 1 ); + defaultRateInit.append( 1 ); + defaultRateInit.append( 0 ); + defaultRate.append( defaultRateInit ); + + QList<int> defaultqueueRate; + + mQueueRateItem[0] = new MyPrefs::ItemIntList( currentGroup(), QLatin1String( "EmptyingRate 0" ), mQueueRate[0], defaultRate[0] ); + mQueueRateItem[0]->setLabel( QCoreApplication::translate("Test11a", "EmptyingRate queueRate$(QueueIndex)") ); + addItem( mQueueRateItem[0], QLatin1String( "queueRate0" ) ); + mQueueRateItem[1] = new MyPrefs::ItemIntList( currentGroup(), QLatin1String( "EmptyingRate 1" ), mQueueRate[1], defaultqueueRate ); + mQueueRateItem[1]->setLabel( QCoreApplication::translate("Test11a", "EmptyingRate queueRate$(QueueIndex)") ); + addItem( mQueueRateItem[1], QLatin1String( "queueRate1" ) ); + mQueueRateItem[2] = new MyPrefs::ItemIntList( currentGroup(), QLatin1String( "EmptyingRate 2" ), mQueueRate[2], defaultRate[2] ); + mQueueRateItem[2]->setLabel( QCoreApplication::translate("Test11a", "EmptyingRate queueRate$(QueueIndex)") ); + addItem( mQueueRateItem[2], QLatin1String( "queueRate2" ) ); + mShowQueueTunerItem = new MyPrefs::ItemBool( currentGroup(), QLatin1String( "ShowQueueTuner" ), mShowQueueTuner, false ); + mShowQueueTunerItem->setLabel( QCoreApplication::translate("Test11a", "ShowQueueTuner") ); + addItem( mShowQueueTunerItem, QLatin1String( "ShowQueueTuner" ) ); +} + +int Test11a::defaultDestinationValue_helper() const +{ + + return EnumDestination::standardDestination; +} + +bool Test11a::defaultSelectionStartsEditorValue_helper() const +{ + + return false; +} + +int Test11a::defaultDefaultReminderUnitsValue_helper() const +{ + + return TimePeriod::HoursMinutes; +} + +Test11a::~Test11a() +{ +} + diff --git a/tier1/kconfig/autotests/kconfig_compiler/test11a.h.ref b/tier1/kconfig/autotests/kconfig_compiler/test11a.h.ref new file mode 100644 index 00000000..4410ce29 --- /dev/null +++ b/tier1/kconfig/autotests/kconfig_compiler/test11a.h.ref @@ -0,0 +1,480 @@ +// This file is generated by kconfig_compiler from test11a.kcfg. +// All changes you do to this file will be lost. +#ifndef TEST11A_H +#define TEST11A_H + +#include <myprefs.h> + +#include <qglobal.h> +#include <kconfigskeleton.h> +#include <QCoreApplication> +#include <QDebug> + +#include "test11_types.h" +class Test11a : public MyPrefs +{ + public: + class EnumDestination + { + public: + enum type { standardDestination, askDestination, argl1, argl2, argl3, COUNT }; + }; + enum MailClient { sendmail, kmail }; + + Test11a( ); + ~Test11a(); + + /** + Set Enable automatic saving of calendar + */ + void setAutoSave( bool v ) + { + if (!isImmutable( QString::fromLatin1( "AutoSave" ) )) + mAutoSave = v; + } + + /** + Get Enable automatic saving of calendar + */ + bool autoSave() const + { + return mAutoSave; + } + + /** + Get Item object corresponding to AutoSave() + */ + ItemBool *autoSaveItem() + { + return mAutoSaveItem; + } + + /** + Set Auto Save Interval + */ + void setAutoSaveInterval( int v ) + { + if (!isImmutable( QString::fromLatin1( "AutoSaveInterval" ) )) + mAutoSaveInterval = v; + } + + /** + Get Auto Save Interval + */ + int autoSaveInterval() const + { + return mAutoSaveInterval; + } + + /** + Get Item object corresponding to AutoSaveInterval() + */ + ItemInt *autoSaveIntervalItem() + { + return mAutoSaveIntervalItem; + } + + /** + Set Confirm deletes + */ + void setConfirm( bool v ) + { + if (!isImmutable( QString::fromLatin1( "Confirm" ) )) + mConfirm = v; + } + + /** + Get Confirm deletes + */ + bool confirm() const + { + return mConfirm; + } + + /** + Get Item object corresponding to Confirm() + */ + ItemBool *confirmItem() + { + return mConfirmItem; + } + + /** + Set Archive File + */ + void setArchiveFile( const QString & v ) + { + if (!isImmutable( QString::fromLatin1( "ArchiveFile" ) )) + mArchiveFile = v; + } + + /** + Get Archive File + */ + QString archiveFile() const + { + return mArchiveFile; + } + + /** + Get Item object corresponding to ArchiveFile() + */ + ItemString *archiveFileItem() + { + return mArchiveFileItem; + } + + /** + Set New Events/Todos Should + */ + void setDestination( EnumDestination::type v ) + { + if (!isImmutable( QString::fromLatin1( "Destination" ) )) + mDestination = v; + } + + /** + Get New Events/Todos Should + */ + EnumDestination::type destination() const + { + return static_cast<EnumDestination::type>(mDestination); + } + + /** + Get New Events/Todos Should default value + */ + EnumDestination::type defaultDestinationValue() const + { + return static_cast<EnumDestination::type>(defaultDestinationValue_helper()); + } + + /** + Get Item object corresponding to Destination() + */ + ItemEnum *destinationItem() + { + return mDestinationItem; + } + + /** + Set Hour Size + */ + void setHourSize( int v ) + { + if (!isImmutable( QString::fromLatin1( "HourSize" ) )) + mHourSize = v; + } + + /** + Get Hour Size + */ + int hourSize() const + { + return mHourSize; + } + + /** + Get Item object corresponding to HourSize() + */ + ItemInt *hourSizeItem() + { + return mHourSizeItem; + } + + /** + Set Time range selection in agenda view starts event editor + */ + void setSelectionStartsEditor( bool v ) + { + if (!isImmutable( QString::fromLatin1( "SelectionStartsEditor" ) )) + mSelectionStartsEditor = v; + } + + /** + Get Time range selection in agenda view starts event editor + */ + bool selectionStartsEditor() const + { + return mSelectionStartsEditor; + } + + /** + Get Time range selection in agenda view starts event editor default value + */ + bool defaultSelectionStartsEditorValue() const + { + return defaultSelectionStartsEditorValue_helper(); + } + + /** + Get Item object corresponding to SelectionStartsEditor() + */ + ItemBool *selectionStartsEditorItem() + { + return mSelectionStartsEditorItem; + } + + /** + Set SelectedPlugins + */ + void setSelectedPlugins( const QStringList & v ) + { + if (!isImmutable( QString::fromLatin1( "SelectedPlugins" ) )) + mSelectedPlugins = v; + } + + /** + Get SelectedPlugins + */ + QStringList selectedPlugins() const + { + return mSelectedPlugins; + } + + /** + Get Item object corresponding to SelectedPlugins() + */ + ItemStringList *selectedPluginsItem() + { + return mSelectedPluginsItem; + } + + /** + Set Highlight color + */ + void setHighlightColor( const QColor & v ) + { + if (!isImmutable( QString::fromLatin1( "HighlightColor" ) )) + mHighlightColor = v; + } + + /** + Get Highlight color + */ + QColor highlightColor() const + { + return mHighlightColor; + } + + /** + Get Item object corresponding to HighlightColor() + */ + ItemColor *highlightColorItem() + { + return mHighlightColorItem; + } + + /** + Set Agenda view background color + */ + void setAgendaBgColor( const QColor & v ) + { + if (!isImmutable( QString::fromLatin1( "AgendaBgColor" ) )) + mAgendaBgColor = v; + } + + /** + Get Agenda view background color + */ + QColor agendaBgColor() const + { + return mAgendaBgColor; + } + + /** + Get Item object corresponding to AgendaBgColor() + */ + ItemColor *agendaBgColorItem() + { + return mAgendaBgColorItem; + } + + /** + Set Time bar + */ + void setTimeBarFont( const QFont & v ) + { + if (!isImmutable( QString::fromLatin1( "TimeBarFont" ) )) + mTimeBarFont = v; + } + + /** + Get Time bar + */ + QFont timeBarFont() const + { + return mTimeBarFont; + } + + /** + Get Item object corresponding to TimeBarFont() + */ + ItemFont *timeBarFontItem() + { + return mTimeBarFontItem; + } + + /** + Set Email client + */ + void setEmailClient( MailClient v ) + { + if (!isImmutable( QString::fromLatin1( "EmailClient" ) )) + mEmailClient = v; + } + + /** + Get Email client + */ + MailClient emailClient() const + { + return static_cast<MailClient>(mEmailClient); + } + + /** + Get Item object corresponding to EmailClient() + */ + ItemEnum *emailClientItem() + { + return mEmailClientItem; + } + + /** + Set Reminder units + */ + void setDefaultReminderUnits( TimePeriod::Units v ) + { + if (!isImmutable( QString::fromLatin1( "DefaultReminderUnits" ) )) + mDefaultReminderUnits = v; + } + + /** + Get Reminder units + */ + TimePeriod::Units defaultReminderUnits() const + { + return static_cast<TimePeriod::Units>(mDefaultReminderUnits); + } + + /** + Get Reminder units default value + */ + TimePeriod::Units defaultDefaultReminderUnitsValue() const + { + return static_cast<TimePeriod::Units>(defaultDefaultReminderUnitsValue_helper()); + } + + /** + Get Item object corresponding to DefaultReminderUnits() + */ + ItemEnum *defaultReminderUnitsItem() + { + return mDefaultReminderUnitsItem; + } + + /** + Set EmptyingRate $(QueueIndex) + */ + void setQueueRate( int i, const QList<int> & v ) + { + if (!isImmutable( QString::fromLatin1( "queueRate%1" ).arg( i ) )) + mQueueRate[i] = v; + } + + /** + Get EmptyingRate $(QueueIndex) + */ + QList<int> queueRate( int i ) const + { + return mQueueRate[i]; + } + + /** + Get Item object corresponding to queueRate() + */ + ItemIntList *queueRateItem( int i ) + { + return mQueueRateItem[i]; + } + + /** + Set ShowQueueTuner + */ + void setShowQueueTuner( bool v ) + { + if (!isImmutable( QString::fromLatin1( "ShowQueueTuner" ) )) + mShowQueueTuner = v; + } + + /** + Get ShowQueueTuner + */ + bool showQueueTuner() const + { + return mShowQueueTuner; + } + + /** + Get Item object corresponding to ShowQueueTuner() + */ + ItemBool *showQueueTunerItem() + { + return mShowQueueTunerItem; + } + + protected: + public: + + // General + bool mAutoSave; + int mAutoSaveInterval; + bool mConfirm; + QString mArchiveFile; + int mDestination; + int defaultDestinationValue_helper() const; + + // Views + int mHourSize; + bool mSelectionStartsEditor; + bool defaultSelectionStartsEditorValue_helper() const; + + // KOrganizer Plugins + QStringList mSelectedPlugins; + + // Colors + QColor mHighlightColor; + QColor mAgendaBgColor; + + // Fonts + QFont mTimeBarFont; + + // Email + int mEmailClient; + int mDefaultReminderUnits; + int defaultDefaultReminderUnitsValue_helper() const; + + // QueueRates + QList<int> mQueueRate[3]; + bool mShowQueueTuner; + + private: + ItemBool *mAutoSaveItem; + ItemInt *mAutoSaveIntervalItem; + ItemBool *mConfirmItem; + ItemString *mArchiveFileItem; + ItemEnum *mDestinationItem; + ItemInt *mHourSizeItem; + ItemBool *mSelectionStartsEditorItem; + ItemStringList *mSelectedPluginsItem; + ItemColor *mHighlightColorItem; + ItemColor *mAgendaBgColorItem; + ItemFont *mTimeBarFontItem; + ItemEnum *mEmailClientItem; + ItemEnum *mDefaultReminderUnitsItem; + ItemIntList *mQueueRateItem[3]; + ItemBool *mShowQueueTunerItem; +}; + +#endif + diff --git a/tier1/kconfig/autotests/kconfig_compiler/test11a.kcfg b/tier1/kconfig/autotests/kconfig_compiler/test11a.kcfg new file mode 100644 index 00000000..da027067 --- /dev/null +++ b/tier1/kconfig/autotests/kconfig_compiler/test11a.kcfg @@ -0,0 +1,135 @@ +<?xml version="1.0" encoding="UTF-8"?> +<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0" + 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>"test11_types.h"</include> + + <kcfgfile name="korganizerrc"/> + + <group name="General"> + <entry type="Bool" key="Auto Save"> + <label>Enable automatic saving of calendar</label> + <whatsthis>WhatsThis text for AutoSave option</whatsthis> + <default>false</default> + </entry> + <entry type="Int" key="Auto Save Interval"> + <default>10</default> + </entry> + <entry type="Bool" key="Confirm Deletes" name="Confirm"> + <label>Confirm deletes</label> + <default>true</default> + </entry> + <entry type="String" key="Archive File"> + </entry> + <entry type="Enum" key="Destination" name="Destination"> + <label>New Events/Todos Should</label> + <choices> + <choice name="standardDestination"> + </choice> + <choice name="askDestination"> + </choice> + <choice name="argl1"> + <label>Argl1 Label</label> + </choice> + <choice name="argl2"> + <whatsthis>Argl2 Whatsthis</whatsthis> + </choice> + <choice name="argl3"> + <label>Argl3 Label</label> + <whatsthis>Argl3 Whatsthis</whatsthis> + </choice> + </choices> + <default>standardDestination</default> + </entry> + </group> + + <group name="Views"> + <entry type="Int" key="Hour Size"> + <default>10</default> + </entry> + <entry type="Bool" name="SelectionStartsEditor"> + <label>Time range selection in agenda view starts event editor</label> + <default>false</default> + </entry> + </group> + + <group name="KOrganizer Plugins"> + <entry type="StringList" name="SelectedPlugins"> + <default>holidays,webexport</default> + </entry> + </group> + + <group name="Colors"> + <entry type="Color" key="Highlight Color"> + <label>Highlight color</label> + <default>100, 100, 255</default> + </entry> + <entry type="Color" key="Agenda Background Color" name="AgendaBgColor"> + <label>Agenda view background color</label> + <default>255, 255, 255</default> + </entry> + </group> + + <group name="Fonts"> + <entry type="Font" key="TimeBar Font"> + <label>Time bar</label> + </entry> + </group> + + <group name="Email"> + <entry name="EmailClient" key="EmailClient" type="Enum"> + <label context="@label">Email client</label> + <whatsthis context="@info:whatsthis"><para>How to send email when an email alarm is triggered.<list><item>KMail: The email is sent automatically via <application>KMail</application>. <application>KMail</application> is started first if necessary.</item><item>Sendmail: The email is sent automatically. This option will only work if your system is configured to use <application>sendmail</application> or a sendmail compatible mail transport agent.</item></list></para></whatsthis> + <choices name="MailClient"> + <choice name="sendmail"><label context="@option">Sendmail</label></choice> + <choice name="kmail"><label context="@option">KMail</label></choice> + </choices> + <default>kmail</default> + </entry> + + <entry name="DefaultReminderUnits" key="RemindUnits" type="Enum"> + <label context="@label">Reminder units</label> + <whatsthis context="@info:whatsthis">Default reminder time units in the alarm edit dialog.</whatsthis> + <choices name="TimePeriod::Units"> + <choice name="Minutes"></choice> + <choice name="HoursMinutes"><label context="@option">Hours/Minutes</label></choice> + </choices> + <default>HoursMinutes</default> + </entry> + </group> + + <group name="QueueRates"> + <entry name="queueRate$(QueueIndex)" type="IntList" key="EmptyingRate $(QueueIndex)"> + <!-- kconfig_compiler really should do this for me... --> + <code> QList< QList<int> > defaultRate; + QList< int > defaultRateInit; + + defaultRateInit.append( 15 ); + defaultRateInit.append( 60 ); + defaultRateInit.append( 0 ); + defaultRate.append( defaultRateInit ); + + defaultRateInit.clear(); + defaultRateInit.append( 40 ); + defaultRateInit.append( 60 ); + defaultRateInit.append( 0 ); + defaultRate.append( defaultRateInit ); + + defaultRateInit.clear(); + defaultRateInit.append( 1 ); + defaultRateInit.append( 1 ); + defaultRateInit.append( 0 ); + defaultRate.append( defaultRateInit ); + </code> + <parameter name="QueueIndex" type="Int" max="2"/> + <default param="0" code="true">defaultRate[0]</default> + <default param="2" code="true">defaultRate[2]</default> + </entry> + <entry key="ShowQueueTuner" type="Bool"> + <default>false</default> + </entry> + </group> + +</kcfg> diff --git a/tier1/kconfig/autotests/kconfig_compiler/test11a.kcfgc b/tier1/kconfig/autotests/kconfig_compiler/test11a.kcfgc new file mode 100644 index 00000000..cf0b0d8d --- /dev/null +++ b/tier1/kconfig/autotests/kconfig_compiler/test11a.kcfgc @@ -0,0 +1,13 @@ +# Code generation options for kconfig_compiler +File=test11a.kcfg +ClassName=Test11a +Singleton=false +Mutators=true +Inherits=MyPrefs +IncludeFiles=myprefs.h +MemberVariables=public +GlobalEnums=false +ItemAccessors=true +SetUserTexts=true +UseEnumTypes=true +DefaultValueGetters=Destination,SelectionStartsEditor,DefaultReminderUnits diff --git a/tier1/kconfig/autotests/kconfig_compiler/test11main.cpp b/tier1/kconfig/autotests/kconfig_compiler/test11main.cpp new file mode 100644 index 00000000..4f5fc80c --- /dev/null +++ b/tier1/kconfig/autotests/kconfig_compiler/test11main.cpp @@ -0,0 +1,34 @@ +/* +Copyright (c) 2009 Pino Toscano <pino@kde.org> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ +#include "test11.h" +#include "test11a.h" +#include <QGuiApplication> + +int main( int argc, char **argv ) +{ + QGuiApplication app(argc, argv); + Q_UNUSED(app); + Test11 *t = new Test11(); + Test11a *t2 = new Test11a(); + delete t; + delete t2; + return 0; +} diff --git a/tier1/kconfig/autotests/kconfig_compiler/test12.cpp.ref b/tier1/kconfig/autotests/kconfig_compiler/test12.cpp.ref new file mode 100644 index 00000000..69d5bba9 --- /dev/null +++ b/tier1/kconfig/autotests/kconfig_compiler/test12.cpp.ref @@ -0,0 +1,22 @@ +// This file is generated by kconfig_compiler from test12.kcfg. +// All changes you do to this file will be lost. + +#include "test12.h" + +Test12::Test12( ) + : KConfigSkeleton( QLatin1String( "muondatasourcesrc" ) ) +{ + setCurrentGroup( QLatin1String( "muon" ) ); + + QList<QUrl> defaultRnRSource; + defaultRnRSource.append( QUrl::fromUserInput(QString::fromUtf8( "http://kde.org" ) ) ); + + KConfigSkeleton::ItemUrlList *itemRnRSource; + itemRnRSource = new KConfigSkeleton::ItemUrlList( currentGroup(), QLatin1String( "RnRSource" ), mRnRSource, defaultRnRSource ); + addItem( itemRnRSource, QLatin1String( "RnRSource" ) ); +} + +Test12::~Test12() +{ +} + diff --git a/tier1/kconfig/autotests/kconfig_compiler/test12.h.ref b/tier1/kconfig/autotests/kconfig_compiler/test12.h.ref new file mode 100644 index 00000000..d55414ec --- /dev/null +++ b/tier1/kconfig/autotests/kconfig_compiler/test12.h.ref @@ -0,0 +1,36 @@ +// This file is generated by kconfig_compiler from test12.kcfg. +// All changes you do to this file will be lost. +#ifndef TEST12_H +#define TEST12_H + +#include <qglobal.h> +#include <kconfigskeleton.h> +#include <QCoreApplication> +#include <QDebug> + +class Test12 : public KConfigSkeleton +{ + public: + + Test12( ); + ~Test12(); + + + /** + Get RnRSource + */ + QList<QUrl> rnRSource() const + { + return mRnRSource; + } + + protected: + + // muon + QList<QUrl> mRnRSource; + + private: +}; + +#endif + diff --git a/tier1/kconfig/autotests/kconfig_compiler/test12.kcfg b/tier1/kconfig/autotests/kconfig_compiler/test12.kcfg new file mode 100644 index 00000000..57663ab9 --- /dev/null +++ b/tier1/kconfig/autotests/kconfig_compiler/test12.kcfg @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="UTF-8"?> +<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0" + 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" > + <kcfgfile name="muondatasourcesrc"/> + <group name="muon"> + <entry name="RnRSource" type="UrlList"><default>http://kde.org</default></entry> + </group> +</kcfg> diff --git a/tier1/kconfig/autotests/kconfig_compiler/test12.kcfgc b/tier1/kconfig/autotests/kconfig_compiler/test12.kcfgc new file mode 100644 index 00000000..1ed82e7e --- /dev/null +++ b/tier1/kconfig/autotests/kconfig_compiler/test12.kcfgc @@ -0,0 +1 @@ +ClassName=Test12 diff --git a/tier1/kconfig/autotests/kconfig_compiler/test12main.cpp b/tier1/kconfig/autotests/kconfig_compiler/test12main.cpp new file mode 100644 index 00000000..b8a05294 --- /dev/null +++ b/tier1/kconfig/autotests/kconfig_compiler/test12main.cpp @@ -0,0 +1,28 @@ +/* +Copyright (c) 2003 Cornelius Schumacher <schumacher@kde.org> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ +#include "test12.h" + +int main( int, char** ) +{ + Test12 *t = new Test12(); + delete t; + return 0; +} diff --git a/tier1/kconfig/autotests/kconfig_compiler/test1main.cpp b/tier1/kconfig/autotests/kconfig_compiler/test1main.cpp new file mode 100644 index 00000000..f1f61c0a --- /dev/null +++ b/tier1/kconfig/autotests/kconfig_compiler/test1main.cpp @@ -0,0 +1,31 @@ +/* +Copyright (c) 2003 Cornelius Schumacher <schumacher@kde.org> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ +#include "test1.h" +#include <QGuiApplication> + +int main( int argc, char **argv ) +{ + QGuiApplication app(argc, argv); + Q_UNUSED(app); + Test1 *t = new Test1( QString(), QString() ); + delete t; + return 0; +} diff --git a/tier1/kconfig/autotests/kconfig_compiler/test2.cpp.ref b/tier1/kconfig/autotests/kconfig_compiler/test2.cpp.ref new file mode 100644 index 00000000..476b34c5 --- /dev/null +++ b/tier1/kconfig/autotests/kconfig_compiler/test2.cpp.ref @@ -0,0 +1,96 @@ +// This file is generated by kconfig_compiler from test2.kcfg. +// All changes you do to this file will be lost. + +#include "test2.h" + +Test2::Test2( ) + : MyPrefs( QLatin1String( "korganizerrc" ) ) +{ + setCurrentGroup( QLatin1String( "General" ) ); + + mAutoSaveItem = new MyPrefs::ItemBool( currentGroup(), QLatin1String( "Auto Save" ), mAutoSave, false ); + mAutoSaveItem->setLabel( QCoreApplication::translate("Test2", "Enable automatic saving of calendar") ); + mAutoSaveItem->setWhatsThis( QCoreApplication::translate("Test2", "WhatsThis text for AutoSave option") ); + addItem( mAutoSaveItem, QLatin1String( "AutoSave" ) ); + mAutoSaveIntervalItem = new MyPrefs::ItemInt( currentGroup(), QLatin1String( "Auto Save Interval" ), mAutoSaveInterval, 10 ); + mAutoSaveIntervalItem->setLabel( QCoreApplication::translate("Test2", "Auto Save Interval") ); + addItem( mAutoSaveIntervalItem, QLatin1String( "AutoSaveInterval" ) ); + mConfirmItem = new MyPrefs::ItemBool( currentGroup(), QLatin1String( "Confirm Deletes" ), mConfirm, true ); + mConfirmItem->setLabel( QCoreApplication::translate("Test2", "Confirm deletes") ); + addItem( mConfirmItem, QLatin1String( "Confirm" ) ); + mArchiveFileItem = new MyPrefs::ItemString( currentGroup(), QLatin1String( "Archive File" ), mArchiveFile ); + mArchiveFileItem->setLabel( QCoreApplication::translate("Test2", "Archive File") ); + addItem( mArchiveFileItem, QLatin1String( "ArchiveFile" ) ); + QList<MyPrefs::ItemEnum::Choice> valuesDestination; + { + MyPrefs::ItemEnum::Choice choice; + choice.name = QLatin1String("standardDestination"); + valuesDestination.append( choice ); + } + { + MyPrefs::ItemEnum::Choice choice; + choice.name = QLatin1String("askDestination"); + valuesDestination.append( choice ); + } + { + MyPrefs::ItemEnum::Choice choice; + choice.name = QLatin1String("argl1"); + choice.label = QCoreApplication::translate("Test2", "Argl1 Label"); + valuesDestination.append( choice ); + } + { + MyPrefs::ItemEnum::Choice choice; + choice.name = QLatin1String("argl2"); + choice.whatsThis = QCoreApplication::translate("Test2", "Argl2 Whatsthis"); + valuesDestination.append( choice ); + } + { + MyPrefs::ItemEnum::Choice choice; + choice.name = QLatin1String("argl3"); + choice.label = QCoreApplication::translate("Test2", "Argl3 Label"); + choice.whatsThis = QCoreApplication::translate("Test2", "Argl3 Whatsthis"); + valuesDestination.append( choice ); + } + mDestinationItem = new MyPrefs::ItemEnum( currentGroup(), QLatin1String( "Destination" ), mDestination, valuesDestination, standardDestination ); + mDestinationItem->setLabel( QCoreApplication::translate("Test2", "New Events/Todos Should") ); + addItem( mDestinationItem, QLatin1String( "Destination" ) ); + + setCurrentGroup( QLatin1String( "Views" ) ); + + mHourSizeItem = new MyPrefs::ItemInt( currentGroup(), QLatin1String( "Hour Size" ), mHourSize, 10 ); + mHourSizeItem->setLabel( QCoreApplication::translate("Test2", "Hour Size") ); + addItem( mHourSizeItem, QLatin1String( "HourSize" ) ); + mSelectionStartsEditorItem = new MyPrefs::ItemBool( currentGroup(), QLatin1String( "SelectionStartsEditor" ), mSelectionStartsEditor, false ); + mSelectionStartsEditorItem->setLabel( QCoreApplication::translate("Test2", "Time range selection in agenda view starts event editor") ); + addItem( mSelectionStartsEditorItem, QLatin1String( "SelectionStartsEditor" ) ); + + setCurrentGroup( QLatin1String( "KOrganizer Plugins" ) ); + + QStringList defaultSelectedPlugins; + defaultSelectedPlugins.append( QString::fromUtf8( "holidays" ) ); + defaultSelectedPlugins.append( QString::fromUtf8( "webexport" ) ); + + mSelectedPluginsItem = new MyPrefs::ItemStringList( currentGroup(), QLatin1String( "SelectedPlugins" ), mSelectedPlugins, defaultSelectedPlugins ); + mSelectedPluginsItem->setLabel( QCoreApplication::translate("Test2", "SelectedPlugins") ); + addItem( mSelectedPluginsItem, QLatin1String( "SelectedPlugins" ) ); + + setCurrentGroup( QLatin1String( "Colors" ) ); + + mHighlightColorItem = new MyPrefs::ItemColor( currentGroup(), QLatin1String( "Highlight Color" ), mHighlightColor, QColor( 100, 100, 255 ) ); + mHighlightColorItem->setLabel( QCoreApplication::translate("Test2", "Highlight color") ); + addItem( mHighlightColorItem, QLatin1String( "HighlightColor" ) ); + mAgendaBgColorItem = new MyPrefs::ItemColor( currentGroup(), QLatin1String( "Agenda Background Color" ), mAgendaBgColor, QColor( 255, 255, 255 ) ); + mAgendaBgColorItem->setLabel( QCoreApplication::translate("Test2", "Agenda view background color") ); + addItem( mAgendaBgColorItem, QLatin1String( "AgendaBgColor" ) ); + + setCurrentGroup( QLatin1String( "Fonts" ) ); + + mTimeBarFontItem = new MyPrefs::ItemFont( currentGroup(), QLatin1String( "TimeBar Font" ), mTimeBarFont ); + mTimeBarFontItem->setLabel( QCoreApplication::translate("Test2", "Time bar") ); + addItem( mTimeBarFontItem, QLatin1String( "TimeBarFont" ) ); +} + +Test2::~Test2() +{ +} + diff --git a/tier1/kconfig/autotests/kconfig_compiler/test2.h.ref b/tier1/kconfig/autotests/kconfig_compiler/test2.h.ref new file mode 100644 index 00000000..49af161e --- /dev/null +++ b/tier1/kconfig/autotests/kconfig_compiler/test2.h.ref @@ -0,0 +1,335 @@ +// This file is generated by kconfig_compiler from test2.kcfg. +// All changes you do to this file will be lost. +#ifndef TEST2_H +#define TEST2_H + +#include <myprefs.h> + +#include <qglobal.h> +#include <kconfigskeleton.h> +#include <QCoreApplication> +#include <QDebug> + +class Test2 : public MyPrefs +{ + public: + enum EnumDestination { standardDestination, askDestination, argl1, argl2, argl3 }; + + Test2( ); + ~Test2(); + + /** + Set Enable automatic saving of calendar + */ + void setAutoSave( bool v ) + { + if (!isImmutable( QString::fromLatin1( "AutoSave" ) )) + mAutoSave = v; + } + + /** + Get Enable automatic saving of calendar + */ + bool autoSave() const + { + return mAutoSave; + } + + /** + Get Item object corresponding to AutoSave() + */ + ItemBool *autoSaveItem() + { + return mAutoSaveItem; + } + + /** + Set Auto Save Interval + */ + void setAutoSaveInterval( int v ) + { + if (!isImmutable( QString::fromLatin1( "AutoSaveInterval" ) )) + mAutoSaveInterval = v; + } + + /** + Get Auto Save Interval + */ + int autoSaveInterval() const + { + return mAutoSaveInterval; + } + + /** + Get Item object corresponding to AutoSaveInterval() + */ + ItemInt *autoSaveIntervalItem() + { + return mAutoSaveIntervalItem; + } + + /** + Set Confirm deletes + */ + void setConfirm( bool v ) + { + if (!isImmutable( QString::fromLatin1( "Confirm" ) )) + mConfirm = v; + } + + /** + Get Confirm deletes + */ + bool confirm() const + { + return mConfirm; + } + + /** + Get Item object corresponding to Confirm() + */ + ItemBool *confirmItem() + { + return mConfirmItem; + } + + /** + Set Archive File + */ + void setArchiveFile( const QString & v ) + { + if (!isImmutable( QString::fromLatin1( "ArchiveFile" ) )) + mArchiveFile = v; + } + + /** + Get Archive File + */ + QString archiveFile() const + { + return mArchiveFile; + } + + /** + Get Item object corresponding to ArchiveFile() + */ + ItemString *archiveFileItem() + { + return mArchiveFileItem; + } + + /** + Set New Events/Todos Should + */ + void setDestination( int v ) + { + if (!isImmutable( QString::fromLatin1( "Destination" ) )) + mDestination = v; + } + + /** + Get New Events/Todos Should + */ + int destination() const + { + return mDestination; + } + + /** + Get Item object corresponding to Destination() + */ + ItemEnum *destinationItem() + { + return mDestinationItem; + } + + /** + Set Hour Size + */ + void setHourSize( int v ) + { + if (!isImmutable( QString::fromLatin1( "HourSize" ) )) + mHourSize = v; + } + + /** + Get Hour Size + */ + int hourSize() const + { + return mHourSize; + } + + /** + Get Item object corresponding to HourSize() + */ + ItemInt *hourSizeItem() + { + return mHourSizeItem; + } + + /** + Set Time range selection in agenda view starts event editor + */ + void setSelectionStartsEditor( bool v ) + { + if (!isImmutable( QString::fromLatin1( "SelectionStartsEditor" ) )) + mSelectionStartsEditor = v; + } + + /** + Get Time range selection in agenda view starts event editor + */ + bool selectionStartsEditor() const + { + return mSelectionStartsEditor; + } + + /** + Get Item object corresponding to SelectionStartsEditor() + */ + ItemBool *selectionStartsEditorItem() + { + return mSelectionStartsEditorItem; + } + + /** + Set SelectedPlugins + */ + void setSelectedPlugins( const QStringList & v ) + { + if (!isImmutable( QString::fromLatin1( "SelectedPlugins" ) )) + mSelectedPlugins = v; + } + + /** + Get SelectedPlugins + */ + QStringList selectedPlugins() const + { + return mSelectedPlugins; + } + + /** + Get Item object corresponding to SelectedPlugins() + */ + ItemStringList *selectedPluginsItem() + { + return mSelectedPluginsItem; + } + + /** + Set Highlight color + */ + void setHighlightColor( const QColor & v ) + { + if (!isImmutable( QString::fromLatin1( "HighlightColor" ) )) + mHighlightColor = v; + } + + /** + Get Highlight color + */ + QColor highlightColor() const + { + return mHighlightColor; + } + + /** + Get Item object corresponding to HighlightColor() + */ + ItemColor *highlightColorItem() + { + return mHighlightColorItem; + } + + /** + Set Agenda view background color + */ + void setAgendaBgColor( const QColor & v ) + { + if (!isImmutable( QString::fromLatin1( "AgendaBgColor" ) )) + mAgendaBgColor = v; + } + + /** + Get Agenda view background color + */ + QColor agendaBgColor() const + { + return mAgendaBgColor; + } + + /** + Get Item object corresponding to AgendaBgColor() + */ + ItemColor *agendaBgColorItem() + { + return mAgendaBgColorItem; + } + + /** + Set Time bar + */ + void setTimeBarFont( const QFont & v ) + { + if (!isImmutable( QString::fromLatin1( "TimeBarFont" ) )) + mTimeBarFont = v; + } + + /** + Get Time bar + */ + QFont timeBarFont() const + { + return mTimeBarFont; + } + + /** + Get Item object corresponding to TimeBarFont() + */ + ItemFont *timeBarFontItem() + { + return mTimeBarFontItem; + } + + protected: + public: + + // General + bool mAutoSave; + int mAutoSaveInterval; + bool mConfirm; + QString mArchiveFile; + int mDestination; + + // Views + int mHourSize; + bool mSelectionStartsEditor; + + // KOrganizer Plugins + QStringList mSelectedPlugins; + + // Colors + QColor mHighlightColor; + QColor mAgendaBgColor; + + // Fonts + QFont mTimeBarFont; + + private: + ItemBool *mAutoSaveItem; + ItemInt *mAutoSaveIntervalItem; + ItemBool *mConfirmItem; + ItemString *mArchiveFileItem; + ItemEnum *mDestinationItem; + ItemInt *mHourSizeItem; + ItemBool *mSelectionStartsEditorItem; + ItemStringList *mSelectedPluginsItem; + ItemColor *mHighlightColorItem; + ItemColor *mAgendaBgColorItem; + ItemFont *mTimeBarFontItem; +}; + +#endif + diff --git a/tier1/kconfig/autotests/kconfig_compiler/test2.kcfg b/tier1/kconfig/autotests/kconfig_compiler/test2.kcfg new file mode 100644 index 00000000..3b19e270 --- /dev/null +++ b/tier1/kconfig/autotests/kconfig_compiler/test2.kcfg @@ -0,0 +1,78 @@ +<?xml version="1.0" encoding="UTF-8"?> +<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0" + 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" > + <kcfgfile name="korganizerrc"/> + + <group name="General"> + <entry type="Bool" key="Auto Save"> + <label>Enable automatic saving of calendar</label> + <whatsthis>WhatsThis text for AutoSave option</whatsthis> + <default>false</default> + </entry> + <entry type="Int" key="Auto Save Interval"> + <default>10</default> + </entry> + <entry type="Bool" key="Confirm Deletes" name="Confirm"> + <label>Confirm deletes</label> + <default>true</default> + </entry> + <entry type="String" key="Archive File"> + </entry> + <entry type="Enum" key="Destination" name="Destination"> + <label>New Events/Todos Should</label> + <choices> + <choice name="standardDestination"> + </choice> + <choice name="askDestination"> + </choice> + <choice name="argl1"> + <label>Argl1 Label</label> + </choice> + <choice name="argl2"> + <whatsthis>Argl2 Whatsthis</whatsthis> + </choice> + <choice name="argl3"> + <label>Argl3 Label</label> + <whatsthis>Argl3 Whatsthis</whatsthis> + </choice> + </choices> + <default>standardDestination</default> + </entry> + </group> + + <group name="Views"> + <entry type="Int" key="Hour Size"> + <default>10</default> + </entry> + <entry type="Bool" name="SelectionStartsEditor"> + <label>Time range selection in agenda view starts event editor</label> + <default>false</default> + </entry> + </group> + + <group name="KOrganizer Plugins"> + <entry type="StringList" name="SelectedPlugins"> + <default>holidays,webexport</default> + </entry> + </group> + + <group name="Colors"> + <entry type="Color" key="Highlight Color"> + <label>Highlight color</label> + <default>100, 100, 255</default> + </entry> + <entry type="Color" key="Agenda Background Color" name="AgendaBgColor"> + <label>Agenda view background color</label> + <default>255, 255, 255</default> + </entry> + </group> + + <group name="Fonts"> + <entry type="Font" key="TimeBar Font"> + <label>Time bar</label> + </entry> + </group> + +</kcfg> diff --git a/tier1/kconfig/autotests/kconfig_compiler/test2.kcfgc b/tier1/kconfig/autotests/kconfig_compiler/test2.kcfgc new file mode 100644 index 00000000..56620d2f --- /dev/null +++ b/tier1/kconfig/autotests/kconfig_compiler/test2.kcfgc @@ -0,0 +1,11 @@ +# Code generation options for kconfig_compiler +File=test2.kcfg +ClassName=Test2 +Singleton=false +Mutators=true +Inherits=MyPrefs +IncludeFiles=myprefs.h +MemberVariables=public +GlobalEnums=true +ItemAccessors=true +SetUserTexts=true diff --git a/tier1/kconfig/autotests/kconfig_compiler/test2main.cpp b/tier1/kconfig/autotests/kconfig_compiler/test2main.cpp new file mode 100644 index 00000000..80203c65 --- /dev/null +++ b/tier1/kconfig/autotests/kconfig_compiler/test2main.cpp @@ -0,0 +1,31 @@ +/* +Copyright (c) 2003 Cornelius Schumacher <schumacher@kde.org> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ +#include "test2.h" +#include <QGuiApplication> + +int main( int argc, char **argv ) +{ + QGuiApplication app(argc, argv); + Q_UNUSED(app); + Test2 *t = new Test2(); + delete t; + return 0; +} diff --git a/tier1/kconfig/autotests/kconfig_compiler/test3.cpp.ref b/tier1/kconfig/autotests/kconfig_compiler/test3.cpp.ref new file mode 100644 index 00000000..0c9187a1 --- /dev/null +++ b/tier1/kconfig/autotests/kconfig_compiler/test3.cpp.ref @@ -0,0 +1,29 @@ +// This file is generated by kconfig_compiler from test3.kcfg. +// All changes you do to this file will be lost. + +#include "test3.h" + +using namespace TestNameSpace; + +Test3::Test3( ) + : KConfigSkeleton( QLatin1String( "test3rc" ) ) +{ + setCurrentGroup( QLatin1String( "General" ) ); + + mAutoSaveItem = new KConfigSkeleton::ItemBool( currentGroup(), QLatin1String( "Auto Save" ), mAutoSave, false ); + addItem( mAutoSaveItem, QLatin1String( "AutoSave" ) ); + + setCurrentGroup( QLatin1String( "Blah" ) ); + + mBlubbItem = new KConfigSkeleton::ItemInt( currentGroup(), QLatin1String( "Blubb" ), mBlubb, 10 ); + addItem( mBlubbItem, QLatin1String( "Blubb" ) ); + mBlahBlahItem = new KConfigSkeleton::ItemString( currentGroup(), QLatin1String( "BlahBlah" ), mBlahBlah, QLatin1String( "a string" ) ); + addItem( mBlahBlahItem, QLatin1String( "BlahBlah" ) ); + mMyPasswordItem = new KConfigSkeleton::ItemPassword( currentGroup(), QLatin1String( "MyPassword" ), mMyPassword ); + addItem( mMyPasswordItem, QLatin1String( "MyPassword" ) ); +} + +Test3::~Test3() +{ +} + diff --git a/tier1/kconfig/autotests/kconfig_compiler/test3.h.ref b/tier1/kconfig/autotests/kconfig_compiler/test3.h.ref new file mode 100644 index 00000000..931e2e26 --- /dev/null +++ b/tier1/kconfig/autotests/kconfig_compiler/test3.h.ref @@ -0,0 +1,140 @@ +// This file is generated by kconfig_compiler from test3.kcfg. +// All changes you do to this file will be lost. +#ifndef TESTNAMESPACE_TEST3_H +#define TESTNAMESPACE_TEST3_H + +#include <qglobal.h> +#include <kconfigskeleton.h> +#include <QCoreApplication> +#include <QDebug> + +namespace TestNameSpace { + +class Test3 : public KConfigSkeleton +{ + public: + + Test3( ); + ~Test3(); + + /** + Set Enable automatic saving of calendar + */ + void setAutoSave( bool v ) + { + if (!isImmutable( QString::fromLatin1( "AutoSave" ) )) + mAutoSave = v; + } + + /** + Get Enable automatic saving of calendar + */ + bool autoSave() const + { + return mAutoSave; + } + + /** + Get Item object corresponding to AutoSave() + */ + ItemBool *autoSaveItem() + { + return mAutoSaveItem; + } + + /** + Set Blubb + */ + void setBlubb( int v ) + { + if (!isImmutable( QString::fromLatin1( "Blubb" ) )) + mBlubb = v; + } + + /** + Get Blubb + */ + int blubb() const + { + return mBlubb; + } + + /** + Get Item object corresponding to Blubb() + */ + ItemInt *blubbItem() + { + return mBlubbItem; + } + + /** + Set BlahBlah + */ + void setBlahBlah( const QString & v ) + { + if (!isImmutable( QString::fromLatin1( "BlahBlah" ) )) + mBlahBlah = v; + } + + /** + Get BlahBlah + */ + QString blahBlah() const + { + return mBlahBlah; + } + + /** + Get Item object corresponding to BlahBlah() + */ + ItemString *blahBlahItem() + { + return mBlahBlahItem; + } + + /** + Set MyPassword + */ + void setMyPassword( const QString & v ) + { + if (!isImmutable( QString::fromLatin1( "MyPassword" ) )) + mMyPassword = v; + } + + /** + Get MyPassword + */ + QString myPassword() const + { + return mMyPassword; + } + + /** + Get Item object corresponding to MyPassword() + */ + ItemPassword *myPasswordItem() + { + return mMyPasswordItem; + } + + protected: + + // General + bool mAutoSave; + + // Blah + int mBlubb; + QString mBlahBlah; + QString mMyPassword; + + private: + ItemBool *mAutoSaveItem; + ItemInt *mBlubbItem; + ItemString *mBlahBlahItem; + ItemPassword *mMyPasswordItem; +}; + +} + +#endif + diff --git a/tier1/kconfig/autotests/kconfig_compiler/test3.kcfg b/tier1/kconfig/autotests/kconfig_compiler/test3.kcfg new file mode 100644 index 00000000..77916da4 --- /dev/null +++ b/tier1/kconfig/autotests/kconfig_compiler/test3.kcfg @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0" + 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" > + <kcfgfile name="test3rc"/> + + <group name="General"> + <entry type="Bool" key="Auto Save"> + <label>Enable automatic saving of calendar</label> + <whatsthis>WhatsThis text for AutoSave option</whatsthis> + <default>false</default> + </entry> + </group> + + <group name="Blah"> + <entry type="Int" name="Blubb"> + <default>10</default> + </entry> + <entry type="String" name="BlahBlah"> + <default>a string</default> + </entry> + <entry type="Password" name="MyPassword"/> + </group> + +</kcfg> diff --git a/tier1/kconfig/autotests/kconfig_compiler/test3.kcfgc b/tier1/kconfig/autotests/kconfig_compiler/test3.kcfgc new file mode 100644 index 00000000..ca2c2205 --- /dev/null +++ b/tier1/kconfig/autotests/kconfig_compiler/test3.kcfgc @@ -0,0 +1,12 @@ +# Code generation options for kconfig_compiler +File=test3.kcfg +NameSpace=TestNameSpace +ClassName=Test3 +#Singleton=false +Mutators=true +#Inherits=MyPrefs +#IncludeFiles=myprefs.h +#MemberVariables=public +GlobalEnums=true +ItemAccessors=true +#SetUserTexts=true diff --git a/tier1/kconfig/autotests/kconfig_compiler/test3a.cpp.ref b/tier1/kconfig/autotests/kconfig_compiler/test3a.cpp.ref new file mode 100644 index 00000000..34321e9e --- /dev/null +++ b/tier1/kconfig/autotests/kconfig_compiler/test3a.cpp.ref @@ -0,0 +1,29 @@ +// This file is generated by kconfig_compiler from test3a.kcfg. +// All changes you do to this file will be lost. + +#include "test3a.h" + +using namespace TestNameSpace::InnerNameSpace; + +Test3a::Test3a( ) + : KConfigSkeleton( QLatin1String( "test3arc" ) ) +{ + setCurrentGroup( QLatin1String( "General" ) ); + + mAutoSaveItem = new KConfigSkeleton::ItemBool( currentGroup(), QLatin1String( "Auto Save" ), mAutoSave, false ); + addItem( mAutoSaveItem, QLatin1String( "AutoSave" ) ); + + setCurrentGroup( QLatin1String( "Blah" ) ); + + mBlubbItem = new KConfigSkeleton::ItemInt( currentGroup(), QLatin1String( "Blubb" ), mBlubb, 10 ); + addItem( mBlubbItem, QLatin1String( "Blubb" ) ); + mBlahBlahItem = new KConfigSkeleton::ItemString( currentGroup(), QLatin1String( "BlahBlah" ), mBlahBlah, QLatin1String( "a string" ) ); + addItem( mBlahBlahItem, QLatin1String( "BlahBlah" ) ); + mMyPasswordItem = new KConfigSkeleton::ItemPassword( currentGroup(), QLatin1String( "MyPassword" ), mMyPassword ); + addItem( mMyPasswordItem, QLatin1String( "MyPassword" ) ); +} + +Test3a::~Test3a() +{ +} + diff --git a/tier1/kconfig/autotests/kconfig_compiler/test3a.h.ref b/tier1/kconfig/autotests/kconfig_compiler/test3a.h.ref new file mode 100644 index 00000000..56d672a3 --- /dev/null +++ b/tier1/kconfig/autotests/kconfig_compiler/test3a.h.ref @@ -0,0 +1,142 @@ +// This file is generated by kconfig_compiler from test3a.kcfg. +// All changes you do to this file will be lost. +#ifndef TESTNAMESPACE_INNERNAMESPACE_TEST3A_H +#define TESTNAMESPACE_INNERNAMESPACE_TEST3A_H + +#include <qglobal.h> +#include <kconfigskeleton.h> +#include <QCoreApplication> +#include <QDebug> + +namespace TestNameSpace { +namespace InnerNameSpace { + +class Test3a : public KConfigSkeleton +{ + public: + + Test3a( ); + ~Test3a(); + + /** + Set Enable automatic saving of calendar + */ + void setAutoSave( bool v ) + { + if (!isImmutable( QString::fromLatin1( "AutoSave" ) )) + mAutoSave = v; + } + + /** + Get Enable automatic saving of calendar + */ + bool autoSave() const + { + return mAutoSave; + } + + /** + Get Item object corresponding to AutoSave() + */ + ItemBool *autoSaveItem() + { + return mAutoSaveItem; + } + + /** + Set Blubb + */ + void setBlubb( int v ) + { + if (!isImmutable( QString::fromLatin1( "Blubb" ) )) + mBlubb = v; + } + + /** + Get Blubb + */ + int blubb() const + { + return mBlubb; + } + + /** + Get Item object corresponding to Blubb() + */ + ItemInt *blubbItem() + { + return mBlubbItem; + } + + /** + Set BlahBlah + */ + void setBlahBlah( const QString & v ) + { + if (!isImmutable( QString::fromLatin1( "BlahBlah" ) )) + mBlahBlah = v; + } + + /** + Get BlahBlah + */ + QString blahBlah() const + { + return mBlahBlah; + } + + /** + Get Item object corresponding to BlahBlah() + */ + ItemString *blahBlahItem() + { + return mBlahBlahItem; + } + + /** + Set MyPassword + */ + void setMyPassword( const QString & v ) + { + if (!isImmutable( QString::fromLatin1( "MyPassword" ) )) + mMyPassword = v; + } + + /** + Get MyPassword + */ + QString myPassword() const + { + return mMyPassword; + } + + /** + Get Item object corresponding to MyPassword() + */ + ItemPassword *myPasswordItem() + { + return mMyPasswordItem; + } + + protected: + + // General + bool mAutoSave; + + // Blah + int mBlubb; + QString mBlahBlah; + QString mMyPassword; + + private: + ItemBool *mAutoSaveItem; + ItemInt *mBlubbItem; + ItemString *mBlahBlahItem; + ItemPassword *mMyPasswordItem; +}; + +} +} + +#endif + diff --git a/tier1/kconfig/autotests/kconfig_compiler/test3a.kcfg b/tier1/kconfig/autotests/kconfig_compiler/test3a.kcfg new file mode 100644 index 00000000..d49b4d65 --- /dev/null +++ b/tier1/kconfig/autotests/kconfig_compiler/test3a.kcfg @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0" + 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" > + <kcfgfile name="test3arc"/> + + <group name="General"> + <entry type="Bool" key="Auto Save"> + <label>Enable automatic saving of calendar</label> + <whatsthis>WhatsThis text for AutoSave option</whatsthis> + <default>false</default> + </entry> + </group> + + <group name="Blah"> + <entry type="Int" name="Blubb"> + <default>10</default> + </entry> + <entry type="String" name="BlahBlah"> + <default>a string</default> + </entry> + <entry type="Password" name="MyPassword"/> + </group> + +</kcfg> diff --git a/tier1/kconfig/autotests/kconfig_compiler/test3a.kcfgc b/tier1/kconfig/autotests/kconfig_compiler/test3a.kcfgc new file mode 100644 index 00000000..ca849a81 --- /dev/null +++ b/tier1/kconfig/autotests/kconfig_compiler/test3a.kcfgc @@ -0,0 +1,12 @@ +# Code generation options for kconfig_compiler +File=test3a.kcfg +NameSpace=TestNameSpace::InnerNameSpace +ClassName=Test3a +#Singleton=false +Mutators=true +#Inherits=MyPrefs +#IncludeFiles=myprefs.h +#MemberVariables=public +GlobalEnums=true +ItemAccessors=true +#SetUserTexts=true diff --git a/tier1/kconfig/autotests/kconfig_compiler/test3amain.cpp b/tier1/kconfig/autotests/kconfig_compiler/test3amain.cpp new file mode 100644 index 00000000..fa33f1cb --- /dev/null +++ b/tier1/kconfig/autotests/kconfig_compiler/test3amain.cpp @@ -0,0 +1,31 @@ +/* +Copyright (c) 2009 Pino Toscano <pino@kde.org> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ +#include "test3a.h" +#include <QGuiApplication> + +int main( int argc, char **argv ) +{ + QGuiApplication app(argc, argv); + Q_UNUSED(app); + TestNameSpace::InnerNameSpace::Test3a *t = new TestNameSpace::InnerNameSpace::Test3a(); + delete t; + return 0; +} diff --git a/tier1/kconfig/autotests/kconfig_compiler/test3main.cpp b/tier1/kconfig/autotests/kconfig_compiler/test3main.cpp new file mode 100644 index 00000000..bf2846c1 --- /dev/null +++ b/tier1/kconfig/autotests/kconfig_compiler/test3main.cpp @@ -0,0 +1,31 @@ +/* +Copyright (c) 2003 Cornelius Schumacher <schumacher@kde.org> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ +#include "test3.h" +#include <QGuiApplication> + +int main( int argc, char **argv ) +{ + QGuiApplication app(argc, argv); + Q_UNUSED(app); + TestNameSpace::Test3 *t = new TestNameSpace::Test3(); + delete t; + return 0; +} diff --git a/tier1/kconfig/autotests/kconfig_compiler/test4.cpp.ref b/tier1/kconfig/autotests/kconfig_compiler/test4.cpp.ref new file mode 100644 index 00000000..171d655d --- /dev/null +++ b/tier1/kconfig/autotests/kconfig_compiler/test4.cpp.ref @@ -0,0 +1,178 @@ +// This file is generated by kconfig_compiler from test4.kcfg. +// All changes you do to this file will be lost. + +#include "test4.h" + +#include <qglobal.h> +#include <QtCore/QFile> + +class Test4Helper +{ + public: + Test4Helper() : q(0) {} + ~Test4Helper() { delete q; } + Test4 *q; +}; +Q_GLOBAL_STATIC(Test4Helper, s_globalTest4) +Test4 *Test4::self() +{ + if (!s_globalTest4()->q) { + new Test4; + s_globalTest4()->q->readConfig(); + } + + return s_globalTest4()->q; +} + +const char* const Test4::EnumButton::enumToString[] = { "right", "mid", "left" }; + +Test4::Test4( ) + : KConfigSkeleton( QLatin1String( "test4rc" ) ) +{ + Q_ASSERT(!s_globalTest4()->q); + s_globalTest4()->q = this; + setCurrentGroup( QLatin1String( "Foo" ) ); + +QColor defaultColor[4] = { Qt::red, Qt::blue, Qt::green, Qt::black }; + KConfigSkeleton::ItemColor *itemColor[4]; + itemColor[0] = new KConfigSkeleton::ItemColor( currentGroup(), QLatin1String( "color #0" ), mColor[0], defaultColor[0] ); + addItem( itemColor[0], QLatin1String( "Color0" ) ); + itemColor[1] = new KConfigSkeleton::ItemColor( currentGroup(), QLatin1String( "color #1" ), mColor[1], defaultColor[1] ); + addItem( itemColor[1], QLatin1String( "Color1" ) ); + itemColor[2] = new KConfigSkeleton::ItemColor( currentGroup(), QLatin1String( "color #2" ), mColor[2], defaultColor[2] ); + addItem( itemColor[2], QLatin1String( "Color2" ) ); + itemColor[3] = new KConfigSkeleton::ItemColor( currentGroup(), QLatin1String( "color #3" ), mColor[3], defaultColor[3] ); + addItem( itemColor[3], QLatin1String( "Color3" ) ); + QList<KConfigSkeleton::ItemEnum::Choice> valuesMouseAction; + { + KConfigSkeleton::ItemEnum::Choice choice; + choice.name = QLatin1String("Encrypt"); + valuesMouseAction.append( choice ); + } + { + KConfigSkeleton::ItemEnum::Choice choice; + choice.name = QLatin1String("Decrypt"); + valuesMouseAction.append( choice ); + } + { + KConfigSkeleton::ItemEnum::Choice choice; + choice.name = QLatin1String("CrashNBurn"); + valuesMouseAction.append( choice ); + } + { + KConfigSkeleton::ItemEnum::Choice choice; + choice.name = QLatin1String("PumpNDump"); + valuesMouseAction.append( choice ); + } + KConfigSkeleton::ItemEnum *itemMouseAction[3]; + itemMouseAction[0] = new KConfigSkeleton::ItemEnum( currentGroup(), QLatin1String( "right_mouse_action" ), mMouseAction[0], valuesMouseAction, EnumMouseAction::Decrypt ); + addItem( itemMouseAction[0], QLatin1String( "MouseActionright" ) ); + itemMouseAction[1] = new KConfigSkeleton::ItemEnum( currentGroup(), QLatin1String( "mid_mouse_action" ), mMouseAction[1], valuesMouseAction, EnumMouseAction::Encrypt ); + addItem( itemMouseAction[1], QLatin1String( "MouseActionmid" ) ); + itemMouseAction[2] = new KConfigSkeleton::ItemEnum( currentGroup(), QLatin1String( "left_mouse_action" ), mMouseAction[2], valuesMouseAction, EnumMouseAction::PumpNDump ); + addItem( itemMouseAction[2], QLatin1String( "MouseActionleft" ) ); + KConfigSkeleton::ItemColor *itemGrayColor[11]; + itemGrayColor[0] = new KConfigSkeleton::ItemColor( currentGroup(), QLatin1String( "gray color #0" ), mGrayColor[0], + QColor::fromRgbF(0 / 10.0, 0 / 10.0, 0 / 10.0) + ); + addItem( itemGrayColor[0], QLatin1String( "GrayColor0" ) ); + itemGrayColor[1] = new KConfigSkeleton::ItemColor( currentGroup(), QLatin1String( "gray color #1" ), mGrayColor[1], + QColor::fromRgbF(1 / 10.0, 1 / 10.0, 1 / 10.0) + ); + addItem( itemGrayColor[1], QLatin1String( "GrayColor1" ) ); + itemGrayColor[2] = new KConfigSkeleton::ItemColor( currentGroup(), QLatin1String( "gray color #2" ), mGrayColor[2], + QColor::fromRgbF(2 / 10.0, 2 / 10.0, 2 / 10.0) + ); + addItem( itemGrayColor[2], QLatin1String( "GrayColor2" ) ); + itemGrayColor[3] = new KConfigSkeleton::ItemColor( currentGroup(), QLatin1String( "gray color #3" ), mGrayColor[3], + QColor::fromRgbF(3 / 10.0, 3 / 10.0, 3 / 10.0) + ); + addItem( itemGrayColor[3], QLatin1String( "GrayColor3" ) ); + itemGrayColor[4] = new KConfigSkeleton::ItemColor( currentGroup(), QLatin1String( "gray color #4" ), mGrayColor[4], + QColor::fromRgbF(4 / 10.0, 4 / 10.0, 4 / 10.0) + ); + addItem( itemGrayColor[4], QLatin1String( "GrayColor4" ) ); + itemGrayColor[5] = new KConfigSkeleton::ItemColor( currentGroup(), QLatin1String( "gray color #5" ), mGrayColor[5], + QColor::fromRgbF(5 / 10.0, 5 / 10.0, 5 / 10.0) + ); + addItem( itemGrayColor[5], QLatin1String( "GrayColor5" ) ); + itemGrayColor[6] = new KConfigSkeleton::ItemColor( currentGroup(), QLatin1String( "gray color #6" ), mGrayColor[6], + QColor::fromRgbF(6 / 10.0, 6 / 10.0, 6 / 10.0) + ); + addItem( itemGrayColor[6], QLatin1String( "GrayColor6" ) ); + itemGrayColor[7] = new KConfigSkeleton::ItemColor( currentGroup(), QLatin1String( "gray color #7" ), mGrayColor[7], + QColor::fromRgbF(7 / 10.0, 7 / 10.0, 7 / 10.0) + ); + addItem( itemGrayColor[7], QLatin1String( "GrayColor7" ) ); + itemGrayColor[8] = new KConfigSkeleton::ItemColor( currentGroup(), QLatin1String( "gray color #8" ), mGrayColor[8], + QColor::fromRgbF(8 / 10.0, 8 / 10.0, 8 / 10.0) + ); + addItem( itemGrayColor[8], QLatin1String( "GrayColor8" ) ); + itemGrayColor[9] = new KConfigSkeleton::ItemColor( currentGroup(), QLatin1String( "gray color #9" ), mGrayColor[9], + QColor::fromRgbF(9 / 10.0, 9 / 10.0, 9 / 10.0) + ); + addItem( itemGrayColor[9], QLatin1String( "GrayColor9" ) ); + itemGrayColor[10] = new KConfigSkeleton::ItemColor( currentGroup(), QLatin1String( "gray color #10" ), mGrayColor[10], + QColor::fromRgbF(10 / 10.0, 10 / 10.0, 10 / 10.0) + ); + addItem( itemGrayColor[10], QLatin1String( "GrayColor10" ) ); + KConfigSkeleton::ItemString *itemColorString[11]; + itemColorString[0] = new KConfigSkeleton::ItemString( currentGroup(), QLatin1String( "color string #0" ), mColorString[0], + QString::number(0) + ); + addItem( itemColorString[0], QLatin1String( "ColorString0" ) ); + itemColorString[1] = new KConfigSkeleton::ItemString( currentGroup(), QLatin1String( "color string #1" ), mColorString[1], + QString::number(1) + ); + addItem( itemColorString[1], QLatin1String( "ColorString1" ) ); + itemColorString[2] = new KConfigSkeleton::ItemString( currentGroup(), QLatin1String( "color string #2" ), mColorString[2], + QString::number(2) + ); + addItem( itemColorString[2], QLatin1String( "ColorString2" ) ); + itemColorString[3] = new KConfigSkeleton::ItemString( currentGroup(), QLatin1String( "color string #3" ), mColorString[3], + QString::number(3) + ); + addItem( itemColorString[3], QLatin1String( "ColorString3" ) ); + itemColorString[4] = new KConfigSkeleton::ItemString( currentGroup(), QLatin1String( "color string #4" ), mColorString[4], + QString::number(4) + ); + addItem( itemColorString[4], QLatin1String( "ColorString4" ) ); + itemColorString[5] = new KConfigSkeleton::ItemString( currentGroup(), QLatin1String( "color string #5" ), mColorString[5], + QString::number(5) + ); + addItem( itemColorString[5], QLatin1String( "ColorString5" ) ); + itemColorString[6] = new KConfigSkeleton::ItemString( currentGroup(), QLatin1String( "color string #6" ), mColorString[6], + QString::number(6) + ); + addItem( itemColorString[6], QLatin1String( "ColorString6" ) ); + itemColorString[7] = new KConfigSkeleton::ItemString( currentGroup(), QLatin1String( "color string #7" ), mColorString[7], + QString::number(7) + ); + addItem( itemColorString[7], QLatin1String( "ColorString7" ) ); + itemColorString[8] = new KConfigSkeleton::ItemString( currentGroup(), QLatin1String( "color string #8" ), mColorString[8], + QString::number(8) + ); + addItem( itemColorString[8], QLatin1String( "ColorString8" ) ); + itemColorString[9] = new KConfigSkeleton::ItemString( currentGroup(), QLatin1String( "color string #9" ), mColorString[9], + QString::number(9) + ); + addItem( itemColorString[9], QLatin1String( "ColorString9" ) ); + itemColorString[10] = new KConfigSkeleton::ItemString( currentGroup(), QLatin1String( "color string #10" ), mColorString[10], + QString::number(10) + ); + addItem( itemColorString[10], QLatin1String( "ColorString10" ) ); + KConfigSkeleton::ItemString *itemFooBar; + itemFooBar = new KConfigSkeleton::ItemString( currentGroup(), QLatin1String( "foo bar" ), mFooBar ); + addItem( itemFooBar, QLatin1String( "FooBar" ) ); + KConfigSkeleton::ItemInt *itemAge; + itemAge = new KConfigSkeleton::ItemInt( currentGroup(), QLatin1String( "Age" ), mAge, 35 ); + itemAge->setMinValue(8); + itemAge->setMaxValue(88); + addItem( itemAge, QLatin1String( "Age" ) ); +} + +Test4::~Test4() +{ + s_globalTest4()->q = 0; +} + diff --git a/tier1/kconfig/autotests/kconfig_compiler/test4.h.ref b/tier1/kconfig/autotests/kconfig_compiler/test4.h.ref new file mode 100644 index 00000000..991a4f7d --- /dev/null +++ b/tier1/kconfig/autotests/kconfig_compiler/test4.h.ref @@ -0,0 +1,171 @@ +// This file is generated by kconfig_compiler from test4.kcfg. +// All changes you do to this file will be lost. +#ifndef TEST4_H +#define TEST4_H + +#include <kconfigskeleton.h> +#include <QCoreApplication> +#include <QDebug> + +class Test4 : public KConfigSkeleton +{ + public: + class EnumMouseAction + { + public: + enum type { Encrypt, Decrypt, CrashNBurn, PumpNDump, COUNT }; + }; + class EnumButton + { + public: + enum type { right, mid, left, COUNT }; + static const char* const enumToString[]; + }; + + static Test4 *self(); + ~Test4(); + + /** + Set Block colors. + */ + static + void setColor( int i, const QColor & v ) + { + if (!self()->isImmutable( QString::fromLatin1( "Color%1" ).arg( i ) )) + self()->mColor[i] = v; + } + + /** + Get Block colors. + */ + static + QColor color( int i ) + { + return self()->mColor[i]; + } + + /** + Set Mouse actions. + */ + static + void setMouseAction( int i, int v ) + { + if (!self()->isImmutable( QString::fromLatin1( "MouseAction%1" ).arg( QLatin1String( EnumButton::enumToString[i] ) ) )) + self()->mMouseAction[i] = v; + } + + /** + Get Mouse actions. + */ + static + int mouseAction( int i ) + { + return self()->mMouseAction[i]; + } + + /** + Set Gray colors. + */ + static + void setGrayColor( int i, const QColor & v ) + { + if (!self()->isImmutable( QString::fromLatin1( "GrayColor%1" ).arg( i ) )) + self()->mGrayColor[i] = v; + } + + /** + Get Gray colors. + */ + static + QColor grayColor( int i ) + { + return self()->mGrayColor[i]; + } + + /** + Set Gray colors as string. + */ + static + void setColorString( int i, const QString & v ) + { + if (!self()->isImmutable( QString::fromLatin1( "ColorString%1" ).arg( i ) )) + self()->mColorString[i] = v; + } + + /** + Get Gray colors as string. + */ + static + QString colorString( int i ) + { + return self()->mColorString[i]; + } + + /** + Set foo bar + */ + static + void setFooBar( const QString & v ) + { + if (!self()->isImmutable( QString::fromLatin1( "FooBar" ) )) + self()->mFooBar = v; + } + + /** + Get foo bar + */ + static + QString fooBar() + { + return self()->mFooBar; + } + + /** + Set Age + */ + static + void setAge( int v ) + { + if (v < 8) + { + qDebug() << "setAge: value " << v << " is less than the minimum value of 8"; + v = 8; + } + + if (v > 88) + { + qDebug() << "setAge: value " << v << " is greater than the maximum value of 88"; + v = 88; + } + + if (!self()->isImmutable( QString::fromLatin1( "Age" ) )) + self()->mAge = v; + } + + /** + Get Age + */ + static + int age() + { + return self()->mAge; + } + + protected: + Test4(); + friend class Test4Helper; + + + // Foo + QColor mColor[4]; + int mMouseAction[3]; + QColor mGrayColor[11]; + QString mColorString[11]; + QString mFooBar; + int mAge; + + private: +}; + +#endif + diff --git a/tier1/kconfig/autotests/kconfig_compiler/test4.kcfg b/tier1/kconfig/autotests/kconfig_compiler/test4.kcfg new file mode 100644 index 00000000..0919b46f --- /dev/null +++ b/tier1/kconfig/autotests/kconfig_compiler/test4.kcfg @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="UTF-8"?> +<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0" + 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" > + <kcfgfile name="test4rc"/> + + <group name="Foo"> + <entry name="Color$(Number)" type="Color" key="color #$(Number)"> + <parameter name="Number" type="Int" max="3"/> + <label>Block colors.</label> + <code>QColor defaultColor[4] = { Qt::red, Qt::blue, Qt::green, Qt::black };</code> + <default code="true">defaultColor[$(Number)]</default> + </entry> + <entry name="MouseAction$(Button)" type="Enum" key="$(Button)_mouse_action"> + <parameter name="Button" type="Enum"> + <values> + <value>right</value> + <value>mid</value> + <value>left</value> + </values> + </parameter> + <label>Mouse actions.</label> + <choices> + <choice name="Encrypt"/> + <choice name="Decrypt"/> + <choice name="CrashNBurn"/> + <choice name="PumpNDump"/> + </choices> + <default param="right">Decrypt</default> + <default param="mid">Encrypt</default> + <default param="left">PumpNDump</default> + </entry> + <entry name="GrayColor$(Number)" type="Color" key="gray color #$(Number)"> + <parameter name="Number" type="Int" max="10"/> + <label>Gray colors.</label> + <default code="true"> + QColor::fromRgbF($(Number) / 10.0, $(Number) / 10.0, $(Number) / 10.0) + </default> + </entry> + <entry name="ColorString$(Number)" type="String" key="color string #$(Number)"> + <parameter name="Number" type="Int" max="10"/> + <label>Gray colors as string.</label> + <default code="true"> + QString::number($(Number)) + </default> + </entry> + <entry name="FooBar" key="foo bar" type="String"/> + <entry name="Age" type="Int"> + <default>35</default> + <min>8</min> + <max>88</max> + </entry> + </group> + +</kcfg> diff --git a/tier1/kconfig/autotests/kconfig_compiler/test4.kcfgc b/tier1/kconfig/autotests/kconfig_compiler/test4.kcfgc new file mode 100644 index 00000000..754706df --- /dev/null +++ b/tier1/kconfig/autotests/kconfig_compiler/test4.kcfgc @@ -0,0 +1,11 @@ +# Code generation options for kconfig_compiler +File=test4.kcfg +ClassName=Test4 +Singleton=true +Mutators=true +#Inherits=MyPrefs +#IncludeFiles=myprefs.h +#MemberVariables=public +GlobalEnums=false +ItemAccessors=false +#SetUserTexts=true diff --git a/tier1/kconfig/autotests/kconfig_compiler/test4main.cpp b/tier1/kconfig/autotests/kconfig_compiler/test4main.cpp new file mode 100644 index 00000000..3ef924c8 --- /dev/null +++ b/tier1/kconfig/autotests/kconfig_compiler/test4main.cpp @@ -0,0 +1,32 @@ +/* +Copyright (c) 2003,2004 Waldo Bastian <bastian@kde.org> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#include "test4.h" +#include <QGuiApplication> + +int main( int argc, char **argv ) +{ + QGuiApplication app(argc, argv); + Q_UNUSED(app); + Test4 *t = Test4::self(); + delete t; + return 0; +} diff --git a/tier1/kconfig/autotests/kconfig_compiler/test5.cpp.ref b/tier1/kconfig/autotests/kconfig_compiler/test5.cpp.ref new file mode 100644 index 00000000..2a95dcda --- /dev/null +++ b/tier1/kconfig/autotests/kconfig_compiler/test5.cpp.ref @@ -0,0 +1,88 @@ +// This file is generated by kconfig_compiler from test5.kcfg. +// All changes you do to this file will be lost. + +#include "test5.h" + +#include <qglobal.h> +#include <QtCore/QFile> + +class Test5Helper +{ + public: + Test5Helper() : q(0) {} + ~Test5Helper() { delete q; } + Test5 *q; +}; +Q_GLOBAL_STATIC(Test5Helper, s_globalTest5) +Test5 *Test5::self() +{ + if (!s_globalTest5()->q) { + new Test5; + s_globalTest5()->q->readConfig(); + } + + return s_globalTest5()->q; +} + +const char* const Test5::EnumButtonToString[] = { "right", "mid", "left" }; + +Test5::Test5( ) + : KConfigSkeleton( QLatin1String( "test4rc" ) ) +{ + Q_ASSERT(!s_globalTest5()->q); + s_globalTest5()->q = this; + setCurrentGroup( QLatin1String( "Foo" ) ); + +QColor defaultColor[4] = { Qt::red, Qt::blue, Qt::green, Qt::black }; + KConfigSkeleton::ItemColor *itemColor[4]; + itemColor[0] = new KConfigSkeleton::ItemColor( currentGroup(), QLatin1String( "color #0" ), mColor[0], defaultColor[0] ); + addItem( itemColor[0], QLatin1String( "Color0" ) ); + itemColor[1] = new KConfigSkeleton::ItemColor( currentGroup(), QLatin1String( "color #1" ), mColor[1], defaultColor[1] ); + addItem( itemColor[1], QLatin1String( "Color1" ) ); + itemColor[2] = new KConfigSkeleton::ItemColor( currentGroup(), QLatin1String( "color #2" ), mColor[2], defaultColor[2] ); + addItem( itemColor[2], QLatin1String( "Color2" ) ); + itemColor[3] = new KConfigSkeleton::ItemColor( currentGroup(), QLatin1String( "color #3" ), mColor[3], defaultColor[3] ); + addItem( itemColor[3], QLatin1String( "Color3" ) ); + QList<KConfigSkeleton::ItemEnum::Choice> valuesMouseAction; + { + KConfigSkeleton::ItemEnum::Choice choice; + choice.name = QLatin1String("Encrypt"); + valuesMouseAction.append( choice ); + } + { + KConfigSkeleton::ItemEnum::Choice choice; + choice.name = QLatin1String("Decrypt"); + valuesMouseAction.append( choice ); + } + { + KConfigSkeleton::ItemEnum::Choice choice; + choice.name = QLatin1String("CrashNBurn"); + valuesMouseAction.append( choice ); + } + { + KConfigSkeleton::ItemEnum::Choice choice; + choice.name = QLatin1String("PumpNDump"); + valuesMouseAction.append( choice ); + } + KConfigSkeleton::ItemEnum *itemMouseAction[3]; + itemMouseAction[0] = new KConfigSkeleton::ItemEnum( currentGroup(), QLatin1String( "right_mouse_action" ), mMouseAction[0], valuesMouseAction, Decrypt ); + addItem( itemMouseAction[0], QLatin1String( "MouseActionright" ) ); + itemMouseAction[1] = new KConfigSkeleton::ItemEnum( currentGroup(), QLatin1String( "mid_mouse_action" ), mMouseAction[1], valuesMouseAction, Encrypt ); + addItem( itemMouseAction[1], QLatin1String( "MouseActionmid" ) ); + itemMouseAction[2] = new KConfigSkeleton::ItemEnum( currentGroup(), QLatin1String( "left_mouse_action" ), mMouseAction[2], valuesMouseAction, PumpNDump ); + addItem( itemMouseAction[2], QLatin1String( "MouseActionleft" ) ); + KConfigSkeleton::ItemString *itemFooBar; + itemFooBar = new KConfigSkeleton::ItemString( currentGroup(), QLatin1String( "foo bar" ), mFooBar ); + addItem( itemFooBar, QLatin1String( "FooBar" ) ); + KConfigSkeleton::ItemInt *itemAge; + itemAge = new KConfigSkeleton::ItemInt( currentGroup(), QLatin1String( "Age" ), mAge, 35 ); + itemAge->setMinValue(8); + itemAge->setMaxValue(88); + addItem( itemAge, QLatin1String( "Age" ) ); +} + +Test5::~Test5() +{ + s_globalTest5()->q = 0; +} + diff --git a/tier1/kconfig/autotests/kconfig_compiler/test5.h.ref b/tier1/kconfig/autotests/kconfig_compiler/test5.h.ref new file mode 100644 index 00000000..46a591c1 --- /dev/null +++ b/tier1/kconfig/autotests/kconfig_compiler/test5.h.ref @@ -0,0 +1,123 @@ +// This file is generated by kconfig_compiler from test5.kcfg. +// All changes you do to this file will be lost. +#ifndef TEST5_H +#define TEST5_H + +#include <kconfigskeleton.h> +#include <QCoreApplication> +#include <QDebug> + +class Test5 : public KConfigSkeleton +{ + public: + enum EnumMouseAction { Encrypt, Decrypt, CrashNBurn, PumpNDump }; + enum EnumButton { right, mid, left }; + static const char* const EnumButtonToString[]; + + static Test5 *self(); + ~Test5(); + + /** + Set Block colors. + */ + static + void setColor( int i, const QColor & v ) + { + if (!self()->isImmutable( QString::fromLatin1( "Color%1" ).arg( i ) )) + self()->mColor[i] = v; + } + + /** + Get Block colors. + */ + static + QColor color( int i ) + { + return self()->mColor[i]; + } + + /** + Set Mouse actions. + */ + static + void setMouseAction( int i, int v ) + { + if (!self()->isImmutable( QString::fromLatin1( "MouseAction%1" ).arg( QLatin1String( EnumButtonToString[i] ) ) )) + self()->mMouseAction[i] = v; + } + + /** + Get Mouse actions. + */ + static + int mouseAction( int i ) + { + return self()->mMouseAction[i]; + } + + /** + Set foo bar + */ + static + void setFooBar( const QString & v ) + { + if (!self()->isImmutable( QString::fromLatin1( "FooBar" ) )) + self()->mFooBar = v; + } + + /** + Get foo bar + */ + static + QString fooBar() + { + return self()->mFooBar; + } + + /** + Set Age + */ + static + void setAge( int v ) + { + if (v < 8) + { + qDebug() << "setAge: value " << v << " is less than the minimum value of 8"; + v = 8; + } + + if (v > 88) + { + qDebug() << "setAge: value " << v << " is greater than the maximum value of 88"; + v = 88; + } + + if (!self()->isImmutable( QString::fromLatin1( "Age" ) )) + self()->mAge = v; + } + + /** + Get Age + */ + static + int age() + { + return self()->mAge; + } + + protected: + Test5(); + friend class Test5Helper; + + + // Foo + QColor mColor[4]; + int mMouseAction[3]; + QString mFooBar; + int mAge; + + private: +}; + +#endif + diff --git a/tier1/kconfig/autotests/kconfig_compiler/test5.kcfg b/tier1/kconfig/autotests/kconfig_compiler/test5.kcfg new file mode 100644 index 00000000..d8ef2bfa --- /dev/null +++ b/tier1/kconfig/autotests/kconfig_compiler/test5.kcfg @@ -0,0 +1,42 @@ +<?xml version="1.0" encoding="UTF-8"?> +<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0" + 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" > + <kcfgfile name="test4rc"/> + + <group name="Foo"> + <entry name="Color$(Number)" type="Color" key="color #$(Number)"> + <parameter name="Number" type="Int" max="3"/> + <label>Block colors.</label> + <code>QColor defaultColor[4] = { Qt::red, Qt::blue, Qt::green, Qt::black };</code> + <default code="true">defaultColor[$(Number)]</default> + </entry> + <entry name="MouseAction$(Button)" type="Enum" key="$(Button)_mouse_action"> + <parameter name="Button" type="Enum"> + <values> + <value>right</value> + <value>mid</value> + <value>left</value> + </values> + </parameter> + <label>Mouse actions.</label> + <choices> + <choice name="Encrypt"/> + <choice name="Decrypt"/> + <choice name="CrashNBurn"/> + <choice name="PumpNDump"/> + </choices> + <default param="right">Decrypt</default> + <default param="mid">Encrypt</default> + <default param="left">PumpNDump</default> + </entry> + <entry name="FooBar" key="foo bar" type="String"/> + <entry name="Age" type="Int"> + <default>35</default> + <min>8</min> + <max>88</max> + </entry> + </group> + +</kcfg> diff --git a/tier1/kconfig/autotests/kconfig_compiler/test5.kcfgc b/tier1/kconfig/autotests/kconfig_compiler/test5.kcfgc new file mode 100644 index 00000000..663005e5 --- /dev/null +++ b/tier1/kconfig/autotests/kconfig_compiler/test5.kcfgc @@ -0,0 +1,11 @@ +# Code generation options for kconfig_compiler +File=test5.kcfg +ClassName=Test5 +Singleton=true +Mutators=true +#Inherits=MyPrefs +#IncludeFiles=myprefs.h +#MemberVariables=public +GlobalEnums=true +ItemAccessors=false +#SetUserTexts=true diff --git a/tier1/kconfig/autotests/kconfig_compiler/test5main.cpp b/tier1/kconfig/autotests/kconfig_compiler/test5main.cpp new file mode 100644 index 00000000..55e30d07 --- /dev/null +++ b/tier1/kconfig/autotests/kconfig_compiler/test5main.cpp @@ -0,0 +1,32 @@ +/* +Copyright (c) 2004 Waldo Bastian <bastian@kde.org> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#include "test5.h" +#include <QGuiApplication> + +int main( int argc, char **argv ) +{ + QGuiApplication app(argc, argv); + Q_UNUSED(app); + Test5 *t = Test5::self(); + delete t; + return 0; +} diff --git a/tier1/kconfig/autotests/kconfig_compiler/test6.cpp.ref b/tier1/kconfig/autotests/kconfig_compiler/test6.cpp.ref new file mode 100644 index 00000000..0fce03a3 --- /dev/null +++ b/tier1/kconfig/autotests/kconfig_compiler/test6.cpp.ref @@ -0,0 +1,31 @@ +// This file is generated by kconfig_compiler from test6.kcfg. +// All changes you do to this file will be lost. + +#include "test6.h" + +Test6::Test6( const QString & Number ) + : KConfigSkeleton( QLatin1String( "test4rc" ) ) + , mParamNumber(Number) +{ + setCurrentGroup( QLatin1String( "Foo" ) ); + + KConfigSkeleton::ItemColor *itemColor; + itemColor = new KConfigSkeleton::ItemColor( currentGroup(), QString( QLatin1String( "color #%1" ) ).arg( mParamNumber ), mColor, QColor( "red" ) ); + addItem( itemColor, QLatin1String( "Color" ) ); + + setCurrentGroup( QString( QLatin1String( "Bar%1" ) ).arg( mParamNumber ) ); + + KConfigSkeleton::ItemString *itemFooBar; + itemFooBar = new KConfigSkeleton::ItemString( currentGroup(), QLatin1String( "foo bar" ), mFooBar ); + addItem( itemFooBar, QLatin1String( "FooBar" ) ); + KConfigSkeleton::ItemInt *itemAge; + itemAge = new KConfigSkeleton::ItemInt( currentGroup(), QLatin1String( "Age" ), mAge, 35 ); + itemAge->setMinValue(8); + itemAge->setMaxValue(88); + addItem( itemAge, QLatin1String( "Age" ) ); +} + +Test6::~Test6() +{ +} + diff --git a/tier1/kconfig/autotests/kconfig_compiler/test6.h.ref b/tier1/kconfig/autotests/kconfig_compiler/test6.h.ref new file mode 100644 index 00000000..f1fb59fd --- /dev/null +++ b/tier1/kconfig/autotests/kconfig_compiler/test6.h.ref @@ -0,0 +1,94 @@ +// This file is generated by kconfig_compiler from test6.kcfg. +// All changes you do to this file will be lost. +#ifndef TEST6_H +#define TEST6_H + +#include <kconfigskeleton.h> +#include <QCoreApplication> +#include <QDebug> + +class Test6 : public KConfigSkeleton +{ + public: + + Test6( const QString & Number ); + ~Test6(); + + /** + Set Block colors. + */ + void setColor( const QColor & v ) + { + if (!isImmutable( QString::fromLatin1( "Color" ) )) + mColor = v; + } + + /** + Get Block colors. + */ + QColor color() const + { + return mColor; + } + + /** + Set foo bar + */ + void setFooBar( const QString & v ) + { + if (!isImmutable( QString::fromLatin1( "FooBar" ) )) + mFooBar = v; + } + + /** + Get foo bar + */ + QString fooBar() const + { + return mFooBar; + } + + /** + Set Age + */ + void setAge( int v ) + { + if (v < 8) + { + qDebug() << "setAge: value " << v << " is less than the minimum value of 8"; + v = 8; + } + + if (v > 88) + { + qDebug() << "setAge: value " << v << " is greater than the maximum value of 88"; + v = 88; + } + + if (!isImmutable( QString::fromLatin1( "Age" ) )) + mAge = v; + } + + /** + Get Age + */ + int age() const + { + return mAge; + } + + protected: + QString mParamNumber; + + // Foo + QColor mColor; + + // Bar$(Number) + QString mFooBar; + int mAge; + + private: +}; + +#endif + diff --git a/tier1/kconfig/autotests/kconfig_compiler/test6.kcfg b/tier1/kconfig/autotests/kconfig_compiler/test6.kcfg new file mode 100644 index 00000000..e59fa88f --- /dev/null +++ b/tier1/kconfig/autotests/kconfig_compiler/test6.kcfg @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="UTF-8"?> +<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0" + 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" > + <kcfgfile name="test4rc"> + <parameter name="Number" type="String"/> + </kcfgfile> + + <group name="Foo"> + <entry name="Color" type="Color" key="color #$(Number)"> + <label>Block colors.</label> + <default>red</default> + </entry> + </group> + <group name="Bar$(Number)"> + <entry name="FooBar" key="foo bar" type="String"/> + <entry name="Age" type="Int"> + <default>35</default> + <min>8</min> + <max>88</max> + </entry> + </group> + +</kcfg> diff --git a/tier1/kconfig/autotests/kconfig_compiler/test6.kcfgc b/tier1/kconfig/autotests/kconfig_compiler/test6.kcfgc new file mode 100644 index 00000000..b69dc152 --- /dev/null +++ b/tier1/kconfig/autotests/kconfig_compiler/test6.kcfgc @@ -0,0 +1,11 @@ +# Code generation options for kconfig_compiler +File=test6.kcfg +ClassName=Test6 +Singleton=false +Mutators=true +#Inherits=MyPrefs +#IncludeFiles=myprefs.h +#MemberVariables=public +GlobalEnums=true +ItemAccessors=false +#SetUserTexts=true diff --git a/tier1/kconfig/autotests/kconfig_compiler/test6main.cpp b/tier1/kconfig/autotests/kconfig_compiler/test6main.cpp new file mode 100644 index 00000000..a60d8378 --- /dev/null +++ b/tier1/kconfig/autotests/kconfig_compiler/test6main.cpp @@ -0,0 +1,32 @@ +/* +Copyright (c) 2004 Waldo Bastian <bastian@kde.org> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#include "test6.h" +#include <QGuiApplication> + +int main( int argc, char **argv ) +{ + QGuiApplication app(argc, argv); + Q_UNUSED(app); + Test6 *t = new Test6(QString()); + delete t; + return 0; +} diff --git a/tier1/kconfig/autotests/kconfig_compiler/test7.cpp.ref b/tier1/kconfig/autotests/kconfig_compiler/test7.cpp.ref new file mode 100644 index 00000000..4ee7d280 --- /dev/null +++ b/tier1/kconfig/autotests/kconfig_compiler/test7.cpp.ref @@ -0,0 +1,31 @@ +// This file is generated by kconfig_compiler from test7.kcfg. +// All changes you do to this file will be lost. + +#include "test7.h" + +Test7::Test7( int Number ) + : KConfigSkeleton( QLatin1String( "test7rc" ) ) + , mParamNumber(Number) +{ + setCurrentGroup( QLatin1String( "Foo" ) ); + + KConfigSkeleton::ItemColor *itemColor; + itemColor = new KConfigSkeleton::ItemColor( currentGroup(), QString( QLatin1String( "color #%1" ) ).arg( mParamNumber ), mColor, QColor( "red" ) ); + addItem( itemColor, QLatin1String( "Color" ) ); + + setCurrentGroup( QString( QLatin1String( "Bar%1" ) ).arg( mParamNumber ) ); + + KConfigSkeleton::ItemString *itemFooBar; + itemFooBar = new KConfigSkeleton::ItemString( currentGroup(), QLatin1String( "foo bar" ), mFooBar ); + addItem( itemFooBar, QLatin1String( "FooBar" ) ); + KConfigSkeleton::ItemInt *itemAge; + itemAge = new KConfigSkeleton::ItemInt( currentGroup(), QLatin1String( "Age" ), mAge, 35 ); + itemAge->setMinValue(8); + itemAge->setMaxValue(88); + addItem( itemAge, QLatin1String( "Age" ) ); +} + +Test7::~Test7() +{ +} + diff --git a/tier1/kconfig/autotests/kconfig_compiler/test7.h.ref b/tier1/kconfig/autotests/kconfig_compiler/test7.h.ref new file mode 100644 index 00000000..417c75ad --- /dev/null +++ b/tier1/kconfig/autotests/kconfig_compiler/test7.h.ref @@ -0,0 +1,94 @@ +// This file is generated by kconfig_compiler from test7.kcfg. +// All changes you do to this file will be lost. +#ifndef TEST7_H +#define TEST7_H + +#include <kconfigskeleton.h> +#include <QCoreApplication> +#include <QDebug> + +class Test7 : public KConfigSkeleton +{ + public: + + Test7( int Number ); + ~Test7(); + + /** + Set Block colors. + */ + void setColor( const QColor & v ) + { + if (!isImmutable( QString::fromLatin1( "Color" ) )) + mColor = v; + } + + /** + Get Block colors. + */ + QColor color() const + { + return mColor; + } + + /** + Set foo bar + */ + void setFooBar( const QString & v ) + { + if (!isImmutable( QString::fromLatin1( "FooBar" ) )) + mFooBar = v; + } + + /** + Get foo bar + */ + QString fooBar() const + { + return mFooBar; + } + + /** + Set Age + */ + void setAge( int v ) + { + if (v < 8) + { + qDebug() << "setAge: value " << v << " is less than the minimum value of 8"; + v = 8; + } + + if (v > 88) + { + qDebug() << "setAge: value " << v << " is greater than the maximum value of 88"; + v = 88; + } + + if (!isImmutable( QString::fromLatin1( "Age" ) )) + mAge = v; + } + + /** + Get Age + */ + int age() const + { + return mAge; + } + + protected: + int mParamNumber; + + // Foo + QColor mColor; + + // Bar$(Number) + QString mFooBar; + int mAge; + + private: +}; + +#endif + diff --git a/tier1/kconfig/autotests/kconfig_compiler/test7.kcfg b/tier1/kconfig/autotests/kconfig_compiler/test7.kcfg new file mode 100644 index 00000000..0a7fd327 --- /dev/null +++ b/tier1/kconfig/autotests/kconfig_compiler/test7.kcfg @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="UTF-8"?> +<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0" + 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" > + <kcfgfile name="test7rc"> + <parameter name="Number" type="Int"/> + </kcfgfile> + + <group name="Foo"> + <entry name="Color" type="Color" key="color #$(Number)"> + <label>Block colors.</label> + <default>red</default> + </entry> + </group> + <group name="Bar$(Number)"> + <entry name="FooBar" key="foo bar" type="String"/> + <entry name="Age" type="Int"> + <default>35</default> + <min>8</min> + <max>88</max> + </entry> + </group> + +</kcfg> diff --git a/tier1/kconfig/autotests/kconfig_compiler/test7.kcfgc b/tier1/kconfig/autotests/kconfig_compiler/test7.kcfgc new file mode 100644 index 00000000..9a6c4095 --- /dev/null +++ b/tier1/kconfig/autotests/kconfig_compiler/test7.kcfgc @@ -0,0 +1,11 @@ +# Code generation options for kconfig_compiler +File=test7.kcfg +ClassName=Test7 +Singleton=false +Mutators=true +#Inherits=MyPrefs +#IncludeFiles=myprefs.h +#MemberVariables=public +GlobalEnums=true +ItemAccessors=false +#SetUserTexts=true diff --git a/tier1/kconfig/autotests/kconfig_compiler/test7main.cpp b/tier1/kconfig/autotests/kconfig_compiler/test7main.cpp new file mode 100644 index 00000000..bf55be20 --- /dev/null +++ b/tier1/kconfig/autotests/kconfig_compiler/test7main.cpp @@ -0,0 +1,32 @@ +/* +Copyright (c) 2004 Waldo Bastian <bastian@kde.org> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#include "test7.h" +#include <QGuiApplication> + +int main( int argc, char **argv ) +{ + QGuiApplication app(argc, argv); + Q_UNUSED(app); + Test7 *t = new Test7(42); + delete t; + return 0; +} diff --git a/tier1/kconfig/autotests/kconfig_compiler/test8a.cpp.ref b/tier1/kconfig/autotests/kconfig_compiler/test8a.cpp.ref new file mode 100644 index 00000000..af85f0ce --- /dev/null +++ b/tier1/kconfig/autotests/kconfig_compiler/test8a.cpp.ref @@ -0,0 +1,22 @@ +// This file is generated by kconfig_compiler from test8a.kcfg. +// All changes you do to this file will be lost. + +#include "test8a.h" + +Test8a::Test8a( KSharedConfig::Ptr config ) + : KConfigSkeleton( config ) +{ + setCurrentGroup( QLatin1String( "Group" ) ); + + KConfigSkeleton::ItemFont *itemFont; + itemFont = new KConfigSkeleton::ItemFont( currentGroup(), QLatin1String( "Font" ), mFont, QFont() ); + addItem( itemFont, QLatin1String( "Font" ) ); + KConfigSkeleton::ItemFont *itemTitleFont; + itemTitleFont = new KConfigSkeleton::ItemFont( currentGroup(), QLatin1String( "TitleFont" ), mTitleFont, QFont() ); + addItem( itemTitleFont, QLatin1String( "TitleFont" ) ); +} + +Test8a::~Test8a() +{ +} + diff --git a/tier1/kconfig/autotests/kconfig_compiler/test8a.h.ref b/tier1/kconfig/autotests/kconfig_compiler/test8a.h.ref new file mode 100644 index 00000000..fd1b3648 --- /dev/null +++ b/tier1/kconfig/autotests/kconfig_compiler/test8a.h.ref @@ -0,0 +1,62 @@ +// This file is generated by kconfig_compiler from test8a.kcfg. +// All changes you do to this file will be lost. +#ifndef TEST8A_H +#define TEST8A_H + +#include <qglobal.h> +#include <kconfigskeleton.h> +#include <QCoreApplication> +#include <QDebug> + +class Test8a : public KConfigSkeleton +{ + public: + + Test8a( KSharedConfig::Ptr config = KSharedConfig::openConfig() ); + ~Test8a(); + + /** + Set Font + */ + void setFont( const QFont & v ) + { + if (!isImmutable( QString::fromLatin1( "Font" ) )) + mFont = v; + } + + /** + Get Font + */ + QFont font() const + { + return mFont; + } + + /** + Set TitleFont + */ + void setTitleFont( const QFont & v ) + { + if (!isImmutable( QString::fromLatin1( "TitleFont" ) )) + mTitleFont = v; + } + + /** + Get TitleFont + */ + QFont titleFont() const + { + return mTitleFont; + } + + protected: + + // Group + QFont mFont; + QFont mTitleFont; + + private: +}; + +#endif + diff --git a/tier1/kconfig/autotests/kconfig_compiler/test8a.kcfg b/tier1/kconfig/autotests/kconfig_compiler/test8a.kcfg new file mode 100644 index 00000000..24038a69 --- /dev/null +++ b/tier1/kconfig/autotests/kconfig_compiler/test8a.kcfg @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8"?> +<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0" + 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" > + <kcfgfile arg="true"/> + + <group name="Group"> + <entry name="Font" type="Font"> + <default code="true">QFont()</default> + </entry> + + <entry name="TitleFont" type="Font"> + <default code="true">QFont()</default> + </entry> + </group> +</kcfg> diff --git a/tier1/kconfig/autotests/kconfig_compiler/test8a.kcfgc b/tier1/kconfig/autotests/kconfig_compiler/test8a.kcfgc new file mode 100644 index 00000000..5f63c31c --- /dev/null +++ b/tier1/kconfig/autotests/kconfig_compiler/test8a.kcfgc @@ -0,0 +1,3 @@ +File=test8a.kcfg +ClassName=Test8a +Mutators=true diff --git a/tier1/kconfig/autotests/kconfig_compiler/test8b.cpp.ref b/tier1/kconfig/autotests/kconfig_compiler/test8b.cpp.ref new file mode 100644 index 00000000..ba0c8b47 --- /dev/null +++ b/tier1/kconfig/autotests/kconfig_compiler/test8b.cpp.ref @@ -0,0 +1,52 @@ +// This file is generated by kconfig_compiler from test8b.kcfg. +// All changes you do to this file will be lost. + +#include "test8b.h" + +#include <qglobal.h> +#include <QtCore/QFile> + +class Test8bHelper +{ + public: + Test8bHelper() : q(0) {} + ~Test8bHelper() { delete q; } + Test8b *q; +}; +Q_GLOBAL_STATIC(Test8bHelper, s_globalTest8b) +Test8b *Test8b::self() +{ + if (!s_globalTest8b()->q) { + new Test8b; + s_globalTest8b()->q->readConfig(); + } + + return s_globalTest8b()->q; +} + +Test8b::Test8b( ) + : Test8a() +{ + Q_ASSERT(!s_globalTest8b()->q); + s_globalTest8b()->q = this; + setCurrentGroup( QLatin1String( "Group8b1" ) ); + + Test8a::ItemUInt *itemSomething; + itemSomething = new Test8a::ItemUInt( currentGroup(), QLatin1String( "Something" ), mSomething, 60 ); + addItem( itemSomething, QLatin1String( "Something" ) ); + + setCurrentGroup( QLatin1String( "Group8b2" ) ); + + Test8a::ItemBool *itemFooBoo; + itemFooBoo = new Test8a::ItemBool( currentGroup(), QLatin1String( "FooBoo" ), mFooBoo, false ); + addItem( itemFooBoo, QLatin1String( "FooBoo" ) ); + Test8a::ItemUInt *itemPort; + itemPort = new Test8a::ItemUInt( currentGroup(), QLatin1String( "Port" ), mPort, 1000 ); + addItem( itemPort, QLatin1String( "Port" ) ); +} + +Test8b::~Test8b() +{ + s_globalTest8b()->q = 0; +} + diff --git a/tier1/kconfig/autotests/kconfig_compiler/test8b.h.ref b/tier1/kconfig/autotests/kconfig_compiler/test8b.h.ref new file mode 100644 index 00000000..140bbb90 --- /dev/null +++ b/tier1/kconfig/autotests/kconfig_compiler/test8b.h.ref @@ -0,0 +1,92 @@ +// This file is generated by kconfig_compiler from test8b.kcfg. +// All changes you do to this file will be lost. +#ifndef TEST8B_H +#define TEST8B_H + +#include <test8a.h> + +#include <kconfigskeleton.h> +#include <QCoreApplication> +#include <QDebug> + +class Test8b : public Test8a +{ + public: + + static Test8b *self(); + ~Test8b(); + + /** + Set Something + */ + static + void setSomething( uint v ) + { + if (!self()->isImmutable( QString::fromLatin1( "Something" ) )) + self()->mSomething = v; + } + + /** + Get Something + */ + static + uint something() + { + return self()->mSomething; + } + + /** + Set FooBoo + */ + static + void setFooBoo( bool v ) + { + if (!self()->isImmutable( QString::fromLatin1( "FooBoo" ) )) + self()->mFooBoo = v; + } + + /** + Get FooBoo + */ + static + bool fooBoo() + { + return self()->mFooBoo; + } + + /** + Set Port + */ + static + void setPort( uint v ) + { + if (!self()->isImmutable( QString::fromLatin1( "Port" ) )) + self()->mPort = v; + } + + /** + Get Port + */ + static + uint port() + { + return self()->mPort; + } + + protected: + Test8b(); + friend class Test8bHelper; + + + // Group8b1 + uint mSomething; + + // Group8b2 + bool mFooBoo; + uint mPort; + + private: +}; + +#endif + diff --git a/tier1/kconfig/autotests/kconfig_compiler/test8b.kcfg b/tier1/kconfig/autotests/kconfig_compiler/test8b.kcfg new file mode 100644 index 00000000..3e203a15 --- /dev/null +++ b/tier1/kconfig/autotests/kconfig_compiler/test8b.kcfg @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="UTF-8"?> +<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0" + 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" > + <group name="Group8b1"> + <entry name="Something" type="UInt"> + <default>60</default> + </entry> + </group> + + <group name="Group8b2"> + <entry name="FooBoo" type="Bool"> + <default>false</default> + </entry> + + <entry name="Port" type="UInt"> + <default>1000</default> + </entry> + </group> +</kcfg> diff --git a/tier1/kconfig/autotests/kconfig_compiler/test8b.kcfgc b/tier1/kconfig/autotests/kconfig_compiler/test8b.kcfgc new file mode 100644 index 00000000..7be05520 --- /dev/null +++ b/tier1/kconfig/autotests/kconfig_compiler/test8b.kcfgc @@ -0,0 +1,6 @@ +File=test8b.kcfg +ClassName=Test8b +Mutators=true +Singleton=true +IncludeFiles=test8a.h +Inherits=Test8a diff --git a/tier1/kconfig/autotests/kconfig_compiler/test8main.cpp b/tier1/kconfig/autotests/kconfig_compiler/test8main.cpp new file mode 100644 index 00000000..c4576911 --- /dev/null +++ b/tier1/kconfig/autotests/kconfig_compiler/test8main.cpp @@ -0,0 +1,36 @@ +/* +Copyright (c) 2005 Michael Brade <brade@kde.org> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#include "test8a.h" +#include "test8b.h" +#include <QGuiApplication> + +int main( int argc, char **argv ) +{ + QGuiApplication app(argc, argv); + Q_UNUSED(app); + Test8a *config1 = new Test8a( KSharedConfig::openConfig( QString() ) ); + Test8a *config2 = new Test8a(); + Test8b::self(); + delete config1; + delete config2; + return 0; +} diff --git a/tier1/kconfig/autotests/kconfig_compiler/test9.cpp.ref b/tier1/kconfig/autotests/kconfig_compiler/test9.cpp.ref new file mode 100644 index 00000000..af90acd9 --- /dev/null +++ b/tier1/kconfig/autotests/kconfig_compiler/test9.cpp.ref @@ -0,0 +1,35 @@ +// This file is generated by kconfig_compiler from test9.kcfg. +// All changes you do to this file will be lost. + +#include "test9.h" + +Test9::Test9( const QString & transport, const QString & folder ) + : KConfigSkeleton( QLatin1String( "examplerc" ) ) + , mParamtransport(transport) + , mParamfolder(folder) +{ + setCurrentGroup( QLatin1String( "MyOptionsXX" ) ); + + QStringList defaultMyStringList; + defaultMyStringList.append( QString::fromUtf8( "up" ) ); + defaultMyStringList.append( QString::fromUtf8( "down" ) ); + + KConfigSkeleton::ItemStringList *itemMyStringList; + itemMyStringList = new KConfigSkeleton::ItemStringList( currentGroup(), QLatin1String( "MyStringList" ), mMyStringList, defaultMyStringList ); + addItem( itemMyStringList, QLatin1String( "MyStringList" ) ); + QStringList defaultMyPathList; + defaultMyPathList.append( QString::fromUtf8( "/home" ) ); + defaultMyPathList.append( QString::fromUtf8( "~" ) ); + + KConfigSkeleton::ItemPathList *itemMyPathList; + itemMyPathList = new KConfigSkeleton::ItemPathList( currentGroup(), QLatin1String( "MyPathList" ), mMyPathList, defaultMyPathList ); + addItem( itemMyPathList, QLatin1String( "MyPathList" ) ); + KConfigSkeleton::ItemPathList *itemMyPathsList2; + itemMyPathsList2 = new KConfigSkeleton::ItemPathList( currentGroup(), QLatin1String( "MyPathsList2" ), mMyPathsList2, QStringList(QString::fromLatin1("/usr/bin")) << QDir::homePath() ); + addItem( itemMyPathsList2, QLatin1String( "MyPathsList2" ) ); +} + +Test9::~Test9() +{ +} + diff --git a/tier1/kconfig/autotests/kconfig_compiler/test9.h.ref b/tier1/kconfig/autotests/kconfig_compiler/test9.h.ref new file mode 100644 index 00000000..02b3d479 --- /dev/null +++ b/tier1/kconfig/autotests/kconfig_compiler/test9.h.ref @@ -0,0 +1,83 @@ +// This file is generated by kconfig_compiler from test9.kcfg. +// All changes you do to this file will be lost. +#ifndef TEST9_H +#define TEST9_H + +#include <kconfigskeleton.h> +#include <QCoreApplication> +#include <QDebug> + +#include <qdir.h> +class Test9 : public KConfigSkeleton +{ + public: + + Test9( const QString & transport, const QString & folder ); + ~Test9(); + + /** + Set MyStringList + */ + void setMyStringList( const QStringList & v ) + { + if (!isImmutable( QString::fromLatin1( "MyStringList" ) )) + mMyStringList = v; + } + + /** + Get MyStringList + */ + QStringList myStringList() const + { + return mMyStringList; + } + + /** + Set This is a list of paths + */ + void setMyPathList( const QStringList & v ) + { + if (!isImmutable( QString::fromLatin1( "MyPathList" ) )) + mMyPathList = v; + } + + /** + Get This is a list of paths + */ + QStringList myPathList() const + { + return mMyPathList; + } + + /** + Set This is an additional test for PathList + */ + void setMyPathsList2( const QStringList & v ) + { + if (!isImmutable( QString::fromLatin1( "MyPathsList2" ) )) + mMyPathsList2 = v; + } + + /** + Get This is an additional test for PathList + */ + QStringList myPathsList2() const + { + return mMyPathsList2; + } + + protected: + public: + QString mParamtransport; + QString mParamfolder; + + // MyOptionsXX + QStringList mMyStringList; + QStringList mMyPathList; + QStringList mMyPathsList2; + + private: +}; + +#endif + diff --git a/tier1/kconfig/autotests/kconfig_compiler/test9.kcfg b/tier1/kconfig/autotests/kconfig_compiler/test9.kcfg new file mode 100644 index 00000000..73e96f49 --- /dev/null +++ b/tier1/kconfig/autotests/kconfig_compiler/test9.kcfg @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0" + 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>qdir.h</include> + <kcfgfile name="examplerc"> + <parameter name="transport" /> + <parameter name="folder" /> + </kcfgfile> + <group name="MyOptionsXX"> + <entry name="MyStringList" type="StringList"> + <default>up,down</default> + </entry> + <entry name="MyPathList" type="PathList"> + <label>This is a list of paths</label> + <default>/home,~</default> + </entry> + <entry name="MyPathsList2" type="PathList"> + <label>This is an additional test for PathList</label> + <default code="true">QStringList(QString::fromLatin1("/usr/bin")) << QDir::homePath()</default> + </entry> + </group> +</kcfg> diff --git a/tier1/kconfig/autotests/kconfig_compiler/test9.kcfgc b/tier1/kconfig/autotests/kconfig_compiler/test9.kcfgc new file mode 100644 index 00000000..d4423338 --- /dev/null +++ b/tier1/kconfig/autotests/kconfig_compiler/test9.kcfgc @@ -0,0 +1,18 @@ +# Code generation options for kconfig_compiler +ClassName=Test9 +# +# Singleton=false +# +# Inherits=KConfigSkeleton +# +# IncludeFiles=libkdepim/kpimprefs.h +# +MemberVariables=public +# +### The following line includes the file exampleprefs_base_addon.h +### It can be used to add extra functions and variables to the +### class. +# CustomAdditions=true +# +### Provide setFooBar(int) style functions +Mutators=true diff --git a/tier1/kconfig/autotests/kconfig_compiler/test9main.cpp b/tier1/kconfig/autotests/kconfig_compiler/test9main.cpp new file mode 100644 index 00000000..352613aa --- /dev/null +++ b/tier1/kconfig/autotests/kconfig_compiler/test9main.cpp @@ -0,0 +1,45 @@ +/* +Copyright (c) 2005 Helge Deller <deller@kde.org> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ +#include "test9.h" +#include <QtCore/QDir> +#include <QGuiApplication> +#include <QDebug> + +int main( int argc, char **argv ) +{ + QGuiApplication app(argc, argv); + Q_UNUSED(app); + Test9 *t = new Test9( QString(), QString() ); + + QStringList myPathsList2 = t->myPathsList2(); + qWarning() << myPathsList2; + + // add another path + QStringList newlist; + myPathsList2 << QDir::homePath() + QString::fromLatin1("/.kde"); + qWarning() << myPathsList2; + + t->setMyPathsList2(myPathsList2); + qWarning() << t->myPathsList2(); + + delete t; + return 0; +} diff --git a/tier1/kconfig/autotests/kconfig_compiler/test_dpointer.cpp.ref b/tier1/kconfig/autotests/kconfig_compiler/test_dpointer.cpp.ref new file mode 100644 index 00000000..ffe931e5 --- /dev/null +++ b/tier1/kconfig/autotests/kconfig_compiler/test_dpointer.cpp.ref @@ -0,0 +1,348 @@ +// This file is generated by kconfig_compiler from test_dpointer.kcfg. +// All changes you do to this file will be lost. + +#include "test_dpointer.h" + +#include <qglobal.h> +#include <QtCore/QFile> + +class TestDPointerPrivate +{ + public: + + // General + bool autoSave; + int autoSaveInterval; + bool confirm; + QString archiveFile; + int destination; + + // Views + int hourSize; + bool selectionStartsEditor; + + // KOrganizer Plugins + QStringList selectedPlugins; + + // Colors + QColor highlightColor; + QColor agendaBgColor; + + // Fonts + QFont timeBarFont; + + // items + KConfigSkeleton::ItemBool *autoSaveItem; + KConfigSkeleton::ItemInt *autoSaveIntervalItem; + KConfigSkeleton::ItemBool *confirmItem; + KConfigSkeleton::ItemString *archiveFileItem; + KConfigSkeleton::ItemEnum *destinationItem; + KConfigSkeleton::ItemInt *hourSizeItem; + KConfigSkeleton::ItemBool *selectionStartsEditorItem; + KConfigSkeleton::ItemStringList *selectedPluginsItem; + KConfigSkeleton::ItemColor *highlightColorItem; + KConfigSkeleton::ItemColor *agendaBgColorItem; + KConfigSkeleton::ItemFont *timeBarFontItem; +}; + +class TestDPointerHelper +{ + public: + TestDPointerHelper() : q(0) {} + ~TestDPointerHelper() { delete q; } + TestDPointer *q; +}; +Q_GLOBAL_STATIC(TestDPointerHelper, s_globalTestDPointer) +TestDPointer *TestDPointer::self() +{ + if (!s_globalTestDPointer()->q) { + new TestDPointer; + s_globalTestDPointer()->q->readConfig(); + } + + return s_globalTestDPointer()->q; +} + +TestDPointer::TestDPointer( ) + : KConfigSkeleton( QLatin1String( "korganizerrc" ) ) +{ + d = new TestDPointerPrivate; + Q_ASSERT(!s_globalTestDPointer()->q); + s_globalTestDPointer()->q = this; + setCurrentGroup( QLatin1String( "General" ) ); + + d->autoSaveItem = new KConfigSkeleton::ItemBool( currentGroup(), QLatin1String( "Auto Save" ), d->autoSave, false ); + d->autoSaveItem->setLabel( QCoreApplication::translate("TestDPointer", "Enable automatic saving of calendar") ); + d->autoSaveItem->setWhatsThis( QCoreApplication::translate("TestDPointer", "WhatsThis text for AutoSave option") ); + addItem( d->autoSaveItem, QLatin1String( "AutoSave" ) ); + d->autoSaveIntervalItem = new KConfigSkeleton::ItemInt( currentGroup(), QLatin1String( "Auto Save Interval" ), d->autoSaveInterval, 10 ); + d->autoSaveIntervalItem->setLabel( QCoreApplication::translate("TestDPointer", "Auto Save Interval") ); + addItem( d->autoSaveIntervalItem, QLatin1String( "AutoSaveInterval" ) ); + d->confirmItem = new KConfigSkeleton::ItemBool( currentGroup(), QLatin1String( "Confirm Deletes" ), d->confirm, true ); + d->confirmItem->setLabel( QCoreApplication::translate("TestDPointer", "Confirm deletes") ); + addItem( d->confirmItem, QLatin1String( "Confirm" ) ); + d->archiveFileItem = new KConfigSkeleton::ItemString( currentGroup(), QLatin1String( "Archive File" ), d->archiveFile ); + d->archiveFileItem->setLabel( QCoreApplication::translate("TestDPointer", "Archive File") ); + addItem( d->archiveFileItem, QLatin1String( "ArchiveFile" ) ); + QList<KConfigSkeleton::ItemEnum::Choice> valuesDestination; + { + KConfigSkeleton::ItemEnum::Choice choice; + choice.name = QLatin1String("standardDestination"); + valuesDestination.append( choice ); + } + { + KConfigSkeleton::ItemEnum::Choice choice; + choice.name = QLatin1String("askDestination"); + valuesDestination.append( choice ); + } + { + KConfigSkeleton::ItemEnum::Choice choice; + choice.name = QLatin1String("argl1"); + choice.label = QCoreApplication::translate("TestDPointer", "Argl1 Label"); + valuesDestination.append( choice ); + } + { + KConfigSkeleton::ItemEnum::Choice choice; + choice.name = QLatin1String("argl2"); + choice.whatsThis = QCoreApplication::translate("TestDPointer", "Argl2 Whatsthis"); + valuesDestination.append( choice ); + } + { + KConfigSkeleton::ItemEnum::Choice choice; + choice.name = QLatin1String("argl3"); + choice.label = QCoreApplication::translate("TestDPointer", "Argl3 Label"); + choice.whatsThis = QCoreApplication::translate("TestDPointer", "Argl3 Whatsthis"); + valuesDestination.append( choice ); + } + d->destinationItem = new KConfigSkeleton::ItemEnum( currentGroup(), QLatin1String( "Destination" ), d->destination, valuesDestination, EnumDestination::standardDestination ); + d->destinationItem->setLabel( QCoreApplication::translate("TestDPointer", "New Events/Todos Should") ); + addItem( d->destinationItem, QLatin1String( "Destination" ) ); + + setCurrentGroup( QLatin1String( "Views" ) ); + + d->hourSizeItem = new KConfigSkeleton::ItemInt( currentGroup(), QLatin1String( "Hour Size" ), d->hourSize, 10 ); + d->hourSizeItem->setLabel( QCoreApplication::translate("TestDPointer", "Hour Size") ); + addItem( d->hourSizeItem, QLatin1String( "HourSize" ) ); + d->selectionStartsEditorItem = new KConfigSkeleton::ItemBool( currentGroup(), QLatin1String( "SelectionStartsEditor" ), d->selectionStartsEditor, false ); + d->selectionStartsEditorItem->setLabel( QCoreApplication::translate("TestDPointer", "Time range selection in agenda view starts event editor") ); + addItem( d->selectionStartsEditorItem, QLatin1String( "SelectionStartsEditor" ) ); + + setCurrentGroup( QLatin1String( "KOrganizer Plugins" ) ); + + QStringList defaultSelectedPlugins; + defaultSelectedPlugins.append( QString::fromUtf8( "holidays" ) ); + defaultSelectedPlugins.append( QString::fromUtf8( "webexport" ) ); + + d->selectedPluginsItem = new KConfigSkeleton::ItemStringList( currentGroup(), QLatin1String( "SelectedPlugins" ), d->selectedPlugins, defaultSelectedPlugins ); + d->selectedPluginsItem->setLabel( QCoreApplication::translate("TestDPointer", "SelectedPlugins") ); + addItem( d->selectedPluginsItem, QLatin1String( "SelectedPlugins" ) ); + + setCurrentGroup( QLatin1String( "Colors" ) ); + + d->highlightColorItem = new KConfigSkeleton::ItemColor( currentGroup(), QLatin1String( "Highlight Color" ), d->highlightColor, QColor( 100, 100, 255 ) ); + d->highlightColorItem->setLabel( QCoreApplication::translate("TestDPointer", "Highlight color") ); + addItem( d->highlightColorItem, QLatin1String( "HighlightColor" ) ); + d->agendaBgColorItem = new KConfigSkeleton::ItemColor( currentGroup(), QLatin1String( "Agenda Background Color" ), d->agendaBgColor, QColor( 255, 255, 255 ) ); + d->agendaBgColorItem->setLabel( QCoreApplication::translate("TestDPointer", "Agenda view background color") ); + addItem( d->agendaBgColorItem, QLatin1String( "AgendaBgColor" ) ); + + setCurrentGroup( QLatin1String( "Fonts" ) ); + + d->timeBarFontItem = new KConfigSkeleton::ItemFont( currentGroup(), QLatin1String( "TimeBar Font" ), d->timeBarFont ); + d->timeBarFontItem->setLabel( QCoreApplication::translate("TestDPointer", "Time bar") ); + addItem( d->timeBarFontItem, QLatin1String( "TimeBarFont" ) ); +} + +void TestDPointer::setAutoSave( bool v ) +{ + if (!self()->isImmutable( QString::fromLatin1( "AutoSave" ) )) + self()->d->autoSave = v; +} + +bool TestDPointer::autoSave() +{ + return self()->d->autoSave; +} + + +KConfigSkeleton::ItemBool *TestDPointer::autoSaveItem() +{ + return d->autoSaveItem; +} + +void TestDPointer::setAutoSaveInterval( int v ) +{ + if (!self()->isImmutable( QString::fromLatin1( "AutoSaveInterval" ) )) + self()->d->autoSaveInterval = v; +} + +int TestDPointer::autoSaveInterval() +{ + return self()->d->autoSaveInterval; +} + + +KConfigSkeleton::ItemInt *TestDPointer::autoSaveIntervalItem() +{ + return d->autoSaveIntervalItem; +} + +void TestDPointer::setConfirm( bool v ) +{ + if (!self()->isImmutable( QString::fromLatin1( "Confirm" ) )) + self()->d->confirm = v; +} + +bool TestDPointer::confirm() +{ + return self()->d->confirm; +} + + +KConfigSkeleton::ItemBool *TestDPointer::confirmItem() +{ + return d->confirmItem; +} + +void TestDPointer::setArchiveFile( const QString & v ) +{ + if (!self()->isImmutable( QString::fromLatin1( "ArchiveFile" ) )) + self()->d->archiveFile = v; +} + +QString TestDPointer::archiveFile() +{ + return self()->d->archiveFile; +} + + +KConfigSkeleton::ItemString *TestDPointer::archiveFileItem() +{ + return d->archiveFileItem; +} + +void TestDPointer::setDestination( int v ) +{ + if (!self()->isImmutable( QString::fromLatin1( "Destination" ) )) + self()->d->destination = v; +} + +int TestDPointer::destination() +{ + return self()->d->destination; +} + + +KConfigSkeleton::ItemEnum *TestDPointer::destinationItem() +{ + return d->destinationItem; +} + +void TestDPointer::setHourSize( int v ) +{ + if (!self()->isImmutable( QString::fromLatin1( "HourSize" ) )) + self()->d->hourSize = v; +} + +int TestDPointer::hourSize() +{ + return self()->d->hourSize; +} + + +KConfigSkeleton::ItemInt *TestDPointer::hourSizeItem() +{ + return d->hourSizeItem; +} + +void TestDPointer::setSelectionStartsEditor( bool v ) +{ + if (!self()->isImmutable( QString::fromLatin1( "SelectionStartsEditor" ) )) + self()->d->selectionStartsEditor = v; +} + +bool TestDPointer::selectionStartsEditor() +{ + return self()->d->selectionStartsEditor; +} + + +KConfigSkeleton::ItemBool *TestDPointer::selectionStartsEditorItem() +{ + return d->selectionStartsEditorItem; +} + +void TestDPointer::setSelectedPlugins( const QStringList & v ) +{ + if (!self()->isImmutable( QString::fromLatin1( "SelectedPlugins" ) )) + self()->d->selectedPlugins = v; +} + +QStringList TestDPointer::selectedPlugins() +{ + return self()->d->selectedPlugins; +} + + +KConfigSkeleton::ItemStringList *TestDPointer::selectedPluginsItem() +{ + return d->selectedPluginsItem; +} + +void TestDPointer::setHighlightColor( const QColor & v ) +{ + if (!self()->isImmutable( QString::fromLatin1( "HighlightColor" ) )) + self()->d->highlightColor = v; +} + +QColor TestDPointer::highlightColor() +{ + return self()->d->highlightColor; +} + + +KConfigSkeleton::ItemColor *TestDPointer::highlightColorItem() +{ + return d->highlightColorItem; +} + +void TestDPointer::setAgendaBgColor( const QColor & v ) +{ + if (!self()->isImmutable( QString::fromLatin1( "AgendaBgColor" ) )) + self()->d->agendaBgColor = v; +} + +QColor TestDPointer::agendaBgColor() +{ + return self()->d->agendaBgColor; +} + + +KConfigSkeleton::ItemColor *TestDPointer::agendaBgColorItem() +{ + return d->agendaBgColorItem; +} + +void TestDPointer::setTimeBarFont( const QFont & v ) +{ + if (!self()->isImmutable( QString::fromLatin1( "TimeBarFont" ) )) + self()->d->timeBarFont = v; +} + +QFont TestDPointer::timeBarFont() +{ + return self()->d->timeBarFont; +} + + +KConfigSkeleton::ItemFont *TestDPointer::timeBarFontItem() +{ + return d->timeBarFontItem; +} + +TestDPointer::~TestDPointer() +{ + delete d; + s_globalTestDPointer()->q = 0; +} + diff --git a/tier1/kconfig/autotests/kconfig_compiler/test_dpointer.h.ref b/tier1/kconfig/autotests/kconfig_compiler/test_dpointer.h.ref new file mode 100644 index 00000000..e10c8c7c --- /dev/null +++ b/tier1/kconfig/autotests/kconfig_compiler/test_dpointer.h.ref @@ -0,0 +1,220 @@ +// This file is generated by kconfig_compiler from test_dpointer.kcfg. +// All changes you do to this file will be lost. +#ifndef TESTDPOINTER_H +#define TESTDPOINTER_H + +#include <kconfigskeleton.h> +#include <QCoreApplication> +#include <QDebug> + +class TestDPointerPrivate; + +class TestDPointer : public KConfigSkeleton +{ + public: + class EnumDestination + { + public: + enum type { standardDestination, askDestination, argl1, argl2, argl3, COUNT }; + }; + + static TestDPointer *self(); + ~TestDPointer(); + + /** + Set Enable automatic saving of calendar + */ + static + void setAutoSave( bool v ); + + /** + Get Enable automatic saving of calendar + */ + static + bool autoSave(); + + /** + Get Item object corresponding to AutoSave() + */ + ItemBool *autoSaveItem(); + + /** + Set Auto Save Interval + */ + static + void setAutoSaveInterval( int v ); + + /** + Get Auto Save Interval + */ + static + int autoSaveInterval(); + + /** + Get Item object corresponding to AutoSaveInterval() + */ + ItemInt *autoSaveIntervalItem(); + + /** + Set Confirm deletes + */ + static + void setConfirm( bool v ); + + /** + Get Confirm deletes + */ + static + bool confirm(); + + /** + Get Item object corresponding to Confirm() + */ + ItemBool *confirmItem(); + + /** + Set Archive File + */ + static + void setArchiveFile( const QString & v ); + + /** + Get Archive File + */ + static + QString archiveFile(); + + /** + Get Item object corresponding to ArchiveFile() + */ + ItemString *archiveFileItem(); + + /** + Set New Events/Todos Should + */ + static + void setDestination( int v ); + + /** + Get New Events/Todos Should + */ + static + int destination(); + + /** + Get Item object corresponding to Destination() + */ + ItemEnum *destinationItem(); + + /** + Set Hour Size + */ + static + void setHourSize( int v ); + + /** + Get Hour Size + */ + static + int hourSize(); + + /** + Get Item object corresponding to HourSize() + */ + ItemInt *hourSizeItem(); + + /** + Set Time range selection in agenda view starts event editor + */ + static + void setSelectionStartsEditor( bool v ); + + /** + Get Time range selection in agenda view starts event editor + */ + static + bool selectionStartsEditor(); + + /** + Get Item object corresponding to SelectionStartsEditor() + */ + ItemBool *selectionStartsEditorItem(); + + /** + Set SelectedPlugins + */ + static + void setSelectedPlugins( const QStringList & v ); + + /** + Get SelectedPlugins + */ + static + QStringList selectedPlugins(); + + /** + Get Item object corresponding to SelectedPlugins() + */ + ItemStringList *selectedPluginsItem(); + + /** + Set Highlight color + */ + static + void setHighlightColor( const QColor & v ); + + /** + Get Highlight color + */ + static + QColor highlightColor(); + + /** + Get Item object corresponding to HighlightColor() + */ + ItemColor *highlightColorItem(); + + /** + Set Agenda view background color + */ + static + void setAgendaBgColor( const QColor & v ); + + /** + Get Agenda view background color + */ + static + QColor agendaBgColor(); + + /** + Get Item object corresponding to AgendaBgColor() + */ + ItemColor *agendaBgColorItem(); + + /** + Set Time bar + */ + static + void setTimeBarFont( const QFont & v ); + + /** + Get Time bar + */ + static + QFont timeBarFont(); + + /** + Get Item object corresponding to TimeBarFont() + */ + ItemFont *timeBarFontItem(); + + protected: + TestDPointer(); + friend class TestDPointerHelper; + + private: + TestDPointerPrivate *d; +}; + +#endif + diff --git a/tier1/kconfig/autotests/kconfig_compiler/test_dpointer.kcfg b/tier1/kconfig/autotests/kconfig_compiler/test_dpointer.kcfg new file mode 100644 index 00000000..3b19e270 --- /dev/null +++ b/tier1/kconfig/autotests/kconfig_compiler/test_dpointer.kcfg @@ -0,0 +1,78 @@ +<?xml version="1.0" encoding="UTF-8"?> +<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0" + 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" > + <kcfgfile name="korganizerrc"/> + + <group name="General"> + <entry type="Bool" key="Auto Save"> + <label>Enable automatic saving of calendar</label> + <whatsthis>WhatsThis text for AutoSave option</whatsthis> + <default>false</default> + </entry> + <entry type="Int" key="Auto Save Interval"> + <default>10</default> + </entry> + <entry type="Bool" key="Confirm Deletes" name="Confirm"> + <label>Confirm deletes</label> + <default>true</default> + </entry> + <entry type="String" key="Archive File"> + </entry> + <entry type="Enum" key="Destination" name="Destination"> + <label>New Events/Todos Should</label> + <choices> + <choice name="standardDestination"> + </choice> + <choice name="askDestination"> + </choice> + <choice name="argl1"> + <label>Argl1 Label</label> + </choice> + <choice name="argl2"> + <whatsthis>Argl2 Whatsthis</whatsthis> + </choice> + <choice name="argl3"> + <label>Argl3 Label</label> + <whatsthis>Argl3 Whatsthis</whatsthis> + </choice> + </choices> + <default>standardDestination</default> + </entry> + </group> + + <group name="Views"> + <entry type="Int" key="Hour Size"> + <default>10</default> + </entry> + <entry type="Bool" name="SelectionStartsEditor"> + <label>Time range selection in agenda view starts event editor</label> + <default>false</default> + </entry> + </group> + + <group name="KOrganizer Plugins"> + <entry type="StringList" name="SelectedPlugins"> + <default>holidays,webexport</default> + </entry> + </group> + + <group name="Colors"> + <entry type="Color" key="Highlight Color"> + <label>Highlight color</label> + <default>100, 100, 255</default> + </entry> + <entry type="Color" key="Agenda Background Color" name="AgendaBgColor"> + <label>Agenda view background color</label> + <default>255, 255, 255</default> + </entry> + </group> + + <group name="Fonts"> + <entry type="Font" key="TimeBar Font"> + <label>Time bar</label> + </entry> + </group> + +</kcfg> diff --git a/tier1/kconfig/autotests/kconfig_compiler/test_dpointer.kcfgc b/tier1/kconfig/autotests/kconfig_compiler/test_dpointer.kcfgc new file mode 100644 index 00000000..48baa376 --- /dev/null +++ b/tier1/kconfig/autotests/kconfig_compiler/test_dpointer.kcfgc @@ -0,0 +1,11 @@ +# Code generation options for kconfig_compiler +File=test_dpointer.kcfg +ClassName=TestDPointer +Singleton=true +Mutators=true +#Inherits=MyPrefs +#IncludeFiles=myprefs.h +MemberVariables=dpointer +#GlobalEnums=true +ItemAccessors=true +SetUserTexts=true diff --git a/tier1/kconfig/autotests/kconfig_compiler/test_dpointer_main.cpp b/tier1/kconfig/autotests/kconfig_compiler/test_dpointer_main.cpp new file mode 100644 index 00000000..6e4cb806 --- /dev/null +++ b/tier1/kconfig/autotests/kconfig_compiler/test_dpointer_main.cpp @@ -0,0 +1,32 @@ +/* +Copyright (c) 2005 Duncan Mac-Vicar P. <duncan@kde.org> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#include "test_dpointer.h" +#include <QGuiApplication> + +int main( int argc, char **argv ) +{ + QGuiApplication app(argc, argv); + Q_UNUSED(app); + TestDPointer *t = TestDPointer::self(); + delete t; + return 0; +} diff --git a/tier1/kconfig/autotests/kconfig_compiler/test_signal.cpp.ref b/tier1/kconfig/autotests/kconfig_compiler/test_signal.cpp.ref new file mode 100644 index 00000000..1dad37b5 --- /dev/null +++ b/tier1/kconfig/autotests/kconfig_compiler/test_signal.cpp.ref @@ -0,0 +1,73 @@ +// This file is generated by kconfig_compiler from test_signal.kcfg. +// All changes you do to this file will be lost. + +#include "test_signal.h" + +#include <qglobal.h> +#include <QtCore/QFile> + +class TestSignalHelper +{ + public: + TestSignalHelper() : q(0) {} + ~TestSignalHelper() { delete q; } + TestSignal *q; +}; +Q_GLOBAL_STATIC(TestSignalHelper, s_globalTestSignal) +TestSignal *TestSignal::self() +{ + if (!s_globalTestSignal()->q) { + new TestSignal; + s_globalTestSignal()->q->readConfig(); + } + + return s_globalTestSignal()->q; +} + +TestSignal::TestSignal( ) + : KConfigSkeleton( QLatin1String( "kconfig_compiler_test_rc" ) ) + , mSettingsChanged(0) +{ + Q_ASSERT(!s_globalTestSignal()->q); + s_globalTestSignal()->q = this; + setCurrentGroup( QLatin1String( "Appearance" ) ); + + KConfigSkeleton::ItemString *itemEmoticonTheme; + itemEmoticonTheme = new KConfigSkeleton::ItemString( currentGroup(), QLatin1String( "emoticonTheme" ), mEmoticonTheme, QLatin1String( "Default" ) ); + addItem( itemEmoticonTheme, QLatin1String( "emoticonTheme" ) ); + KConfigSkeleton::ItemBool *itemUseEmoticon; + itemUseEmoticon = new KConfigSkeleton::ItemBool( currentGroup(), QLatin1String( "useEmoticon" ), mUseEmoticon, true ); + addItem( itemUseEmoticon, QLatin1String( "useEmoticon" ) ); + KConfigSkeleton::ItemBool *itemEmoticonRequireSpace; + itemEmoticonRequireSpace = new KConfigSkeleton::ItemBool( currentGroup(), QLatin1String( "emoticonRequireSpace" ), mEmoticonRequireSpace, true ); + addItem( itemEmoticonRequireSpace, QLatin1String( "emoticonRequireSpace" ) ); + KConfigSkeleton::ItemString *itemStylePath; + itemStylePath = new KConfigSkeleton::ItemString( currentGroup(), QLatin1String( "stylePath" ), mStylePath ); + addItem( itemStylePath, QLatin1String( "stylePath" ) ); + KConfigSkeleton::ItemString *itemStyleCSSVariant; + itemStyleCSSVariant = new KConfigSkeleton::ItemString( currentGroup(), QLatin1String( "styleVariant" ), mStyleCSSVariant ); + addItem( itemStyleCSSVariant, QLatin1String( "StyleCSSVariant" ) ); +} + +TestSignal::~TestSignal() +{ + s_globalTestSignal()->q = 0; +} + +bool TestSignal::usrWriteConfig() +{ + const bool res = KConfigSkeleton::usrWriteConfig(); + if (!res) return false; + + if ( mSettingsChanged & signalEmoticonSettingsChanged ) + emit emoticonSettingsChanged(); + + if ( mSettingsChanged & signalStyleChanged ) + emit styleChanged(mStylePath, mStyleCSSVariant); + + mSettingsChanged = 0; + return true; +} + +#include "test_signal.moc" + diff --git a/tier1/kconfig/autotests/kconfig_compiler/test_signal.h.ref b/tier1/kconfig/autotests/kconfig_compiler/test_signal.h.ref new file mode 100644 index 00000000..801ff926 --- /dev/null +++ b/tier1/kconfig/autotests/kconfig_compiler/test_signal.h.ref @@ -0,0 +1,153 @@ +// This file is generated by kconfig_compiler from test_signal.kcfg. +// All changes you do to this file will be lost. +#ifndef TESTSIGNAL_H +#define TESTSIGNAL_H + +#include <kconfigskeleton.h> +#include <QCoreApplication> +#include <QDebug> + +class TestSignal : public KConfigSkeleton +{ + Q_OBJECT + public: + + enum { + signalEmoticonSettingsChanged = 0x1, + signalStyleChanged = 0x2 + }; + + static TestSignal *self(); + ~TestSignal(); + + /** + Set Current emoticon theme. + */ + static + void setEmoticonTheme( const QString & v ) + { + if (!self()->isImmutable( QString::fromLatin1( "emoticonTheme" ) )) { + self()->mEmoticonTheme = v; + self()->mSettingsChanged |= signalEmoticonSettingsChanged; + } + } + + /** + Get Current emoticon theme. + */ + static + QString emoticonTheme() + { + return self()->mEmoticonTheme; + } + + /** + Set Enable emoticon support in Kopete. + */ + static + void setUseEmoticon( bool v ) + { + if (!self()->isImmutable( QString::fromLatin1( "useEmoticon" ) )) { + self()->mUseEmoticon = v; + self()->mSettingsChanged |= signalEmoticonSettingsChanged; + } + } + + /** + Get Enable emoticon support in Kopete. + */ + static + bool useEmoticon() + { + return self()->mUseEmoticon; + } + + /** + Set Use strict mode in emoticon parsing. + */ + static + void setEmoticonRequireSpace( bool v ) + { + if (!self()->isImmutable( QString::fromLatin1( "emoticonRequireSpace" ) )) { + self()->mEmoticonRequireSpace = v; + self()->mSettingsChanged |= signalEmoticonSettingsChanged; + } + } + + /** + Get Use strict mode in emoticon parsing. + */ + static + bool emoticonRequireSpace() + { + return self()->mEmoticonRequireSpace; + } + + /** + Set Absolute path to a directory containing a Adium/Kopete chat window style. + */ + static + void setStylePath( const QString & v ) + { + if (!self()->isImmutable( QString::fromLatin1( "stylePath" ) )) { + self()->mStylePath = v; + self()->mSettingsChanged |= signalStyleChanged; + } + } + + /** + Get Absolute path to a directory containing a Adium/Kopete chat window style. + */ + static + QString stylePath() + { + return self()->mStylePath; + } + + /** + Set Relative path to a CSS variant for the current style. + */ + static + void setStyleCSSVariant( const QString & v ) + { + if (!self()->isImmutable( QString::fromLatin1( "StyleCSSVariant" ) )) + self()->mStyleCSSVariant = v; + } + + /** + Get Relative path to a CSS variant for the current style. + */ + static + QString styleCSSVariant() + { + return self()->mStyleCSSVariant; + } + + + Q_SIGNALS: + void emoticonSettingsChanged(); + + /** + Tell when a complete style change. + */ + void styleChanged(const QString & stylePath, const QString & StyleCSSVariant); + + protected: + TestSignal(); + friend class TestSignalHelper; + + virtual bool usrWriteConfig(); + + // Appearance + QString mEmoticonTheme; + bool mUseEmoticon; + bool mEmoticonRequireSpace; + QString mStylePath; + QString mStyleCSSVariant; + + private: + uint mSettingsChanged; +}; + +#endif + diff --git a/tier1/kconfig/autotests/kconfig_compiler/test_signal.kcfg b/tier1/kconfig/autotests/kconfig_compiler/test_signal.kcfg new file mode 100644 index 00000000..1b2c36ec --- /dev/null +++ b/tier1/kconfig/autotests/kconfig_compiler/test_signal.kcfg @@ -0,0 +1,45 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Author: Michaël Larouche--> +<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0" + 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" > + <kcfgfile name="kconfig_compiler_test_rc"/> + + <signal name="emoticonSettingsChanged" /> + + <signal name="styleChanged"> + <label>Tell when a complete style change.</label> + <argument type="String">stylePath</argument> + <argument type="String">StyleCSSVariant</argument> + </signal> + + <group name="Appearance"> + <!-- Emoticon config --> + <entry key="emoticonTheme" type="String"> + <label>Current emoticon theme.</label> + <default>Default</default> + <emit signal="emoticonSettingsChanged" /> + </entry> + <entry key="useEmoticon" type="Bool"> + <label>Enable emoticon support in Kopete.</label> + <default>true</default> + <emit signal="emoticonSettingsChanged" /> + </entry> + <entry key="emoticonRequireSpace" type="Bool"> + <label>Use strict mode in emoticon parsing.</label> + <default>true</default> + <emit signal="emoticonSettingsChanged" /> + </entry> + + <!-- Chat Window Style preferences --> + <entry key="stylePath" type="String"> + <label>Absolute path to a directory containing a Adium/Kopete chat window style.</label> + <emit signal="styleChanged" /> + </entry> + + <entry key="styleVariant" type="String" name="StyleCSSVariant"> + <label>Relative path to a CSS variant for the current style.</label> + </entry> + </group> +</kcfg> diff --git a/tier1/kconfig/autotests/kconfig_compiler/test_signal.kcfgc b/tier1/kconfig/autotests/kconfig_compiler/test_signal.kcfgc new file mode 100644 index 00000000..b2a2fc06 --- /dev/null +++ b/tier1/kconfig/autotests/kconfig_compiler/test_signal.kcfgc @@ -0,0 +1,7 @@ +File=test_signal.kcfg +ClassName=TestSignal +Singleton=true +Mutators=true +MemberVariables=private +GlobalEnums=false +ItemAccessors=false diff --git a/tier1/kconfig/autotests/kconfig_compiler/test_signal_main.cpp b/tier1/kconfig/autotests/kconfig_compiler/test_signal_main.cpp new file mode 100644 index 00000000..3189e79a --- /dev/null +++ b/tier1/kconfig/autotests/kconfig_compiler/test_signal_main.cpp @@ -0,0 +1,32 @@ +/* +Copyright (c) 2006 Michael Larouche <michael.larouche@kdemail.net> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#include "test_signal.h" +#include <QGuiApplication> + +int main( int argc, char **argv ) +{ + QGuiApplication app(argc, argv); + Q_UNUSED(app); + TestSignal *t = TestSignal::self(); + delete t; + return 0; +} diff --git a/tier1/kconfig/autotests/kconfigguitest.cpp b/tier1/kconfig/autotests/kconfigguitest.cpp new file mode 100644 index 00000000..225f1719 --- /dev/null +++ b/tier1/kconfig/autotests/kconfigguitest.cpp @@ -0,0 +1,145 @@ +/* This file is part of the KDE libraries + Copyright (C) 1997 Matthias Kalle Dalheimer (kalle@kde.org) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include <QtTest/QtTestGui> +#include "kconfigguitest.h" + +#include <kconfig.h> +#include <QDir> +#include <QFont> +#include <kconfiggroup.h> +#include <kconfigskeleton.h> + +QTEST_MAIN( KConfigTest ) + +#define COLORENTRY1 QColor("steelblue") +#define COLORENTRY2 QColor(235, 235, 100, 125) +#define COLORENTRY3 QColor(234, 234, 127) +#define FONTENTRY QFont("Times", 16, QFont::Normal) + +void KConfigTest::initTestCase() +{ + // cheat the linker on windows to link against kconfiggui + KConfigSkeleton foo; + Q_UNUSED(foo); + + KConfig sc( "kconfigtest" ); + + KConfigGroup cg(&sc, "ComplexTypes"); + cg.writeEntry( "colorEntry1", COLORENTRY1 ); + cg.writeEntry( "colorEntry2", COLORENTRY2 ); + cg.writeEntry( "colorEntry3", (QList<int>() << 234 << 234 << 127)); + cg.writeEntry( "colorEntry4", (QList<int>() << 235 << 235 << 100 << 125)); + cg.writeEntry( "fontEntry", FONTENTRY ); + QVERIFY(sc.sync()); + + KConfig sc1("kdebugrc"); + KConfigGroup sg0(&sc1, "0"); + sg0.writeEntry("AbortFatal", false); + sg0.writeEntry("WarnOutput", 0); + sg0.writeEntry("FatalOutput", 0); + QVERIFY(sc1.sync()); +} + +void KConfigTest::cleanupTestCase() +{ + QDir local(QDir::homePath() + "/.kde-unit-test/share/config"); + + Q_FOREACH(const QString &file, local.entryList(QDir::Files)) + if(!local.remove(file)) + qWarning("%s: removing failed", qPrintable( file )); + + QCOMPARE((int)local.entryList(QDir::Files).count(), 0); + + local.cdUp(); + local.rmpath("config"); +} + +void KConfigTest::testComplex() +{ + KConfig sc2( "kconfigtest" ); + KConfigGroup sc3(&sc2, "ComplexTypes"); + + QCOMPARE( QVariant(sc3.readEntry( "colorEntry1", QColor(Qt::black) )).toString(), + QVariant(COLORENTRY1).toString() ); + QCOMPARE( sc3.readEntry( "colorEntry1", QColor() ), COLORENTRY1 ); + QCOMPARE( sc3.readEntry( "colorEntry2", QColor() ), COLORENTRY2 ); + QCOMPARE( sc3.readEntry( "colorEntry3", QColor() ), COLORENTRY3 ); + QCOMPARE( sc3.readEntry( "colorEntry4", QColor() ), COLORENTRY2 ); + QCOMPARE( sc3.readEntry( "defaultColorTest", QColor("black") ), QColor("black") ); + QCOMPARE( sc3.readEntry( "fontEntry", QFont() ), FONTENTRY ); +} + +void KConfigTest::testInvalid() +{ + KConfig sc( "kconfigtest" ); + + // all of these should print a message to the kdebug.dbg file + KConfigGroup sc3(&sc, "InvalidTypes" ); + + QList<int> list; + + // 1 element list + list << 1; + sc3.writeEntry( QString("badList"), list); + QVERIFY(sc.sync()); + + QVERIFY( sc3.readEntry( "badList", QColor() ) == QColor() ); + + // 2 element list + list << 2; + sc3.writeEntry( "badList", list); + QVERIFY(sc.sync()); + + QVERIFY( sc3.readEntry( "badList", QColor() ) == QColor() ); + + // 3 element list + list << 303; + sc3.writeEntry( "badList", list); + QVERIFY(sc.sync()); + + QVERIFY( sc3.readEntry( "badList", QColor() ) == QColor() ); // out of bounds + + // 4 element list + list << 4; + sc3.writeEntry( "badList", list ); + QVERIFY(sc.sync()); + + QVERIFY( sc3.readEntry( "badList", QColor() ) == QColor() ); // out of bounds + + list[2] = -3; + sc3.writeEntry( "badList", list ); + QVERIFY(sc.sync()); + QVERIFY( sc3.readEntry( "badList", QColor() ) == QColor() ); // out of bounds + + // 5 element list + list[2] = 3; + list << 5; + sc3.writeEntry( "badList", list); + QVERIFY(sc.sync()); + + QVERIFY( sc3.readEntry( "badList", QColor() ) == QColor() ); + + // 6 element list + list << 6; + sc3.writeEntry( "badList", list); + QVERIFY(sc.sync()); + + QVERIFY( sc3.readEntry( "badList", QColor() ) == QColor() ); +} diff --git a/tier1/kconfig/autotests/kconfigguitest.h b/tier1/kconfig/autotests/kconfigguitest.h new file mode 100644 index 00000000..2ac7261d --- /dev/null +++ b/tier1/kconfig/autotests/kconfigguitest.h @@ -0,0 +1,35 @@ +/* This file is part of the KDE libraries + Copyright (C) 1997 Matthias Kalle Dalheimer (kalle@kde.org) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ +#ifndef KCONFIGTEST_H +#define KCONFIGTEST_H + +#include <QtCore/QObject> + +class KConfigTest : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + void testComplex(); + void testInvalid(); + void initTestCase(); + void cleanupTestCase(); +}; + +#endif /* KCONFIGTEST_H */ diff --git a/tier1/kconfig/autotests/kconfigloadertest.cpp b/tier1/kconfig/autotests/kconfigloadertest.cpp new file mode 100644 index 00000000..a4403da9 --- /dev/null +++ b/tier1/kconfig/autotests/kconfigloadertest.cpp @@ -0,0 +1,208 @@ +/******************************************************************************** +* Copyright 2010 by Martin Blumenstingl <darklight.xdarklight@googlemail.com> * +* * +* This library is free software; you can redistribute it and/or * +* modify it under the terms of the GNU Library General Public * +* License as published by the Free Software Foundation; either * +* version 2 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 * +* Library General Public License for more details. * +* * +* You should have received a copy of the GNU Library General Public License * +* along with this library; see the file COPYING.LIB. If not, write to * +* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * +* Boston, MA 02110-1301, USA. * +*********************************************************************************/ +#include "kconfigloadertest.h" + +#include <kconfig.h> +#include <kconfiggroup.h> +#include <kconfigskeleton.h> +#include <kconfigloader.h> + +Q_DECLARE_METATYPE(QList<int>) + +#define TEST_NAME QString::fromLatin1("kconfigloadertest") + +#define GET_CONFIG_ITEM_VALUE(type, configName) \ + KConfigSkeletonItem* item = cl->findItem(TEST_NAME, configName); \ + /* Check if we got back a valid item. */ \ + QVERIFY(item != 0); \ + /* Cast the item to the given type. */ \ + type typeItem = dynamic_cast<type>(item); \ + /* Make sure the cast was successful. */ \ + QVERIFY(typeItem != 0); + +void ConfigLoaderTest::init() +{ + QString fileName = TEST_NAME + QString::fromLatin1(".xml"); + configFile = new QFile(QFINDTESTDATA(QString::fromLatin1("/") + fileName)); + cl = new KConfigLoader(configFile->fileName(), configFile); +} + +void ConfigLoaderTest::cleanup() +{ + delete cl; + delete configFile; +} + +void ConfigLoaderTest::boolDefaultValue() +{ + GET_CONFIG_ITEM_VALUE(KCoreConfigSkeleton::ItemBool*, "DefaultBoolItem"); + + QVERIFY(typeItem->isEqual(true)); +} + +void ConfigLoaderTest::colorDefaultValue() +{ + GET_CONFIG_ITEM_VALUE(KConfigSkeleton::ItemColor*, "DefaultColorItem"); + + QVERIFY(typeItem->isEqual(QColor("#00FF00"))); +} + +void ConfigLoaderTest::dateTimeDefaultValue() +{ + GET_CONFIG_ITEM_VALUE(KCoreConfigSkeleton::ItemDateTime*, "DefaultDateTimeItem"); + + QVERIFY(typeItem->isEqual(QDateTime::fromString("Thu Sep 09 2010"))); +} + +void ConfigLoaderTest::enumDefaultValue() +{ + GET_CONFIG_ITEM_VALUE(KConfigSkeleton::ItemEnum*, "DefaultEnumItem"); + + QVERIFY(typeItem->isEqual(3)); +} + +void ConfigLoaderTest::fontDefaultValue() +{ + GET_CONFIG_ITEM_VALUE(KConfigSkeleton::ItemFont*, "DefaultFontItem"); + + QVERIFY(typeItem->isEqual(QFont("DejaVu Sans"))); +} + +void ConfigLoaderTest::intDefaultValue() +{ + GET_CONFIG_ITEM_VALUE(KCoreConfigSkeleton::ItemInt*, "DefaultIntItem"); + + QVERIFY(typeItem->isEqual(27)); +} + +void ConfigLoaderTest::passwordDefaultValue() +{ + GET_CONFIG_ITEM_VALUE(KConfigSkeleton::ItemPassword*, "DefaultPasswordItem"); + + QVERIFY(typeItem->isEqual(QString::fromLatin1("h4x."))); +} + +void ConfigLoaderTest::pathDefaultValue() +{ + GET_CONFIG_ITEM_VALUE(KConfigSkeleton::ItemPath*, "DefaultPathItem"); + + QVERIFY(typeItem->isEqual(QString::fromLatin1("/dev/null"))); +} + +void ConfigLoaderTest::stringDefaultValue() +{ + GET_CONFIG_ITEM_VALUE(KConfigSkeleton::ItemString*, "DefaultStringItem"); + + QVERIFY(typeItem->isEqual(QString::fromLatin1("TestString"))); +} + +void ConfigLoaderTest::stringListDefaultValue() +{ + GET_CONFIG_ITEM_VALUE(KConfigSkeleton::ItemStringList*, "DefaultStringListItem"); + + // Create a string list with the expected values. + QStringList expected; + expected.append("One"); + expected.append("Two"); + expected.append("Three"); + expected.append("Four"); + expected.append("Five"); + + QVERIFY(typeItem->isEqual(expected)); +} + +void ConfigLoaderTest::uintDefaultValue() +{ + GET_CONFIG_ITEM_VALUE(KCoreConfigSkeleton::ItemUInt*, "DefaultUIntItem"); + + QVERIFY(typeItem->isEqual(7U)); +} + +void ConfigLoaderTest::urlDefaultValue() +{ + GET_CONFIG_ITEM_VALUE(KCoreConfigSkeleton::ItemUrl*, "DefaultUrlItem"); + + QVERIFY(typeItem->isEqual(QUrl("http://kde.org"))); +} + +void ConfigLoaderTest::doubleDefaultValue() +{ + GET_CONFIG_ITEM_VALUE(KCoreConfigSkeleton::ItemDouble*, "DefaultDoubleItem"); + + QVERIFY(typeItem->isEqual(13.37)); +} + +void ConfigLoaderTest::intListDefaultValue() +{ + GET_CONFIG_ITEM_VALUE(KCoreConfigSkeleton::ItemIntList*, "DefaultIntListItem"); + + // Create a int list with the expected values. + QList<int> expected; + expected.append(1); + expected.append(1); + expected.append(2); + expected.append(3); + expected.append(5); + expected.append(8); + + QVERIFY(typeItem->isEqual(qVariantFromValue(expected))); +} + +void ConfigLoaderTest::longLongDefaultValue() +{ + GET_CONFIG_ITEM_VALUE(KCoreConfigSkeleton::ItemLongLong*, "DefaultLongLongItem"); + + QVERIFY(typeItem->isEqual(Q_INT64_C(-9211372036854775808))); +} + +void ConfigLoaderTest::pointDefaultValue() +{ + GET_CONFIG_ITEM_VALUE(KCoreConfigSkeleton::ItemPoint*, "DefaultPointItem"); + + QVERIFY(typeItem->isEqual(QPoint(185, 857))); +} + +void ConfigLoaderTest::rectDefaultValue() +{ + GET_CONFIG_ITEM_VALUE(KCoreConfigSkeleton::ItemRect*, "DefaultRectItem"); + + // Create a new QRect with the expected value. + QRect expected; + expected.setCoords(3, 7, 951, 358); + + QVERIFY(typeItem->isEqual(expected)); +} + +void ConfigLoaderTest::sizeDefaultValue() +{ + GET_CONFIG_ITEM_VALUE(KCoreConfigSkeleton::ItemSize*, "DefaultSizeItem"); + + QVERIFY(typeItem->isEqual(QSize(640, 480))); +} + +void ConfigLoaderTest::ulongLongDefaultValue() +{ + GET_CONFIG_ITEM_VALUE(KCoreConfigSkeleton::ItemULongLong*, "DefaultULongLongItem"); + + QVERIFY(typeItem->isEqual(Q_UINT64_C(9223372036854775806))); +} + + +QTEST_MAIN(ConfigLoaderTest) + diff --git a/tier1/kconfig/autotests/kconfigloadertest.h b/tier1/kconfig/autotests/kconfigloadertest.h new file mode 100644 index 00000000..be8c7629 --- /dev/null +++ b/tier1/kconfig/autotests/kconfigloadertest.h @@ -0,0 +1,63 @@ +/******************************************************************************** +* Copyright 2010 by Martin Blumenstingl <darklight.xdarklight@googlemail.com> * +* * +* This library is free software; you can redistribute it and/or * +* modify it under the terms of the GNU Library General Public * +* License as published by the Free Software Foundation; either * +* version 2 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 * +* Library General Public License for more details. * +* * +* You should have received a copy of the GNU Library General Public License * +* along with this library; see the file COPYING.LIB. If not, write to * +* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * +* Boston, MA 02110-1301, USA. * +*********************************************************************************/ + +#ifndef KCONFIGLOADERTEST_H +#define KCONFIGLOADERTEST_H + +#include <QtTest/QtTest> + +class KConfigLoader; + +class QFile; + +class ConfigLoaderTest : public QObject +{ + Q_OBJECT + +public Q_SLOTS: + void init(); + void cleanup(); + +private Q_SLOTS: + void boolDefaultValue(); + void colorDefaultValue(); + void dateTimeDefaultValue(); + void enumDefaultValue(); + void fontDefaultValue(); + void intDefaultValue(); + void passwordDefaultValue(); + void pathDefaultValue(); + void stringDefaultValue(); + void stringListDefaultValue(); + void uintDefaultValue(); + void urlDefaultValue(); + void doubleDefaultValue(); + void intListDefaultValue(); + void longLongDefaultValue(); + void pointDefaultValue(); + void rectDefaultValue(); + void sizeDefaultValue(); + void ulongLongDefaultValue(); + +private: + KConfigLoader* cl; + QFile* configFile; +}; + +#endif diff --git a/tier1/kconfig/autotests/kconfigloadertest.xml b/tier1/kconfig/autotests/kconfigloadertest.xml new file mode 100644 index 00000000..024880f4 --- /dev/null +++ b/tier1/kconfig/autotests/kconfigloadertest.xml @@ -0,0 +1,71 @@ +<?xml version="1.0" encoding="UTF-8"?> +<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0" + 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" > + <kcfgfile name="keystatusplasmoidrc"/> + + <group name="kconfigloadertest"> + <entry name="DefaultBoolItem" type="Bool"> + <default>true</default> + </entry> + <entry name="DefaultColorItem" type="Color"> + <default>#00FF00</default> + </entry> + <entry name="DefaultDateTimeItem" type="DateTime"> + <default>Thu Sep 09 2010</default> + </entry> + <entry name="DefaultEnumItem" type="Enum"> + <default>3</default> + <choice name="One" value="1" /> + <choice name="Two" value="2" /> + <choice name="Three" value="3" /> + <choice name="Four" value="4" /> + </entry> + <entry name="DefaultFontItem" type="Font"> + <default>DejaVu Sans</default> + </entry> + <entry name="DefaultIntItem" type="Int"> + <default>27</default> + </entry> + <entry name="DefaultPasswordItem" type="Password"> + <default>h4x.</default> + </entry> + <entry name="DefaultPathItem" type="Path"> + <default>/dev/null</default> + </entry> + <entry name="DefaultStringItem" type="String"> + <default>TestString</default> + </entry> + <entry name="DefaultStringListItem" type="StringList"> + <default>One,Two,Three,Four,Five</default> + </entry> + <entry name="DefaultUIntItem" type="UInt"> + <default>7</default> + </entry> + <entry name="DefaultUrlItem" type="Url"> + <default>http://kde.org</default> + </entry> + <entry name="DefaultDoubleItem" type="Double"> + <default>13.37</default> + </entry> + <entry name="DefaultIntListItem" type="IntList"> + <default>1,1,2,3,5,8</default> + </entry> + <entry name="DefaultLongLongItem" type="LongLong"> + <default>-9211372036854775808</default> + </entry> + <entry name="DefaultPointItem" type="Point"> + <default>185,857</default> + </entry> + <entry name="DefaultRectItem" type="Rect"> + <default>3,7,951,358</default> + </entry> + <entry name="DefaultSizeItem" type="Size"> + <default>640,480</default> + </entry> + <entry name="DefaultULongLongItem" type="ULongLong"> + <default>9223372036854775806</default> + </entry> + </group> +</kcfg> diff --git a/tier1/kconfig/autotests/kconfignokdehometest.cpp b/tier1/kconfig/autotests/kconfignokdehometest.cpp new file mode 100644 index 00000000..0c7d8265 --- /dev/null +++ b/tier1/kconfig/autotests/kconfignokdehometest.cpp @@ -0,0 +1,64 @@ +/* This file is part of the KDE libraries + Copyright (C) 2011 David Faure <faure@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include <QObject> + +#include <QtTest/QtTest> +#include <QStandardPaths> +#include <ksharedconfig.h> + +#include <kconfig.h> +#include <kconfiggroup.h> + +class KConfigNoKdeHomeTest : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + void testNoKdeHome(); +}; + + +void KConfigNoKdeHomeTest::testNoKdeHome() +{ + QStandardPaths::setTestModeEnabled(true); + QString configPath = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation); + QDir configDir(configPath); + configDir.removeRecursively(); + QVERIFY(!QFile::exists(configPath)); + + // Do what kf5-config does, and ensure the config directory doesn't get created (#233892) + QVERIFY(!QFile::exists(configPath)); + KSharedConfig::openConfig(); + QVERIFY(!QFile::exists(configPath)); + + // Now try to actually save something, see if it works. + KConfigGroup group(KSharedConfig::openConfig(), "Group"); + group.writeEntry("Key", "Value"); + group.sync(); + QVERIFY(QFile::exists(configPath)); + QVERIFY(QFile::exists(configPath + QStringLiteral("/kconfignokdehometestrc"))); + + // Cleanup + configDir.removeRecursively(); +} + +QTEST_MAIN(KConfigNoKdeHomeTest) + +#include "kconfignokdehometest.moc" diff --git a/tier1/kconfig/autotests/kconfigskeletontest.cpp b/tier1/kconfig/autotests/kconfigskeletontest.cpp new file mode 100644 index 00000000..d3b30e84 --- /dev/null +++ b/tier1/kconfig/autotests/kconfigskeletontest.cpp @@ -0,0 +1,111 @@ +/* This file is part of the KDE libraries + Copyright (C) 2006 Olivier Goffart <ogoffart at kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "kconfigskeletontest.h" + +#include <kconfig.h> +#include <QFont> +#include <QtTest/QtTestGui> + + +QTEST_MAIN( KConfigSkeletonTest) + + +#define DEFAULT_SETTING1 false +#define DEFAULT_SETTING2 QColor(1,2,3) +#define DEFAULT_SETTING3 QFont("helvetica",12) +#define DEFAULT_SETTING4 QString("Hello World") + +#define WRITE_SETTING1 true +#define WRITE_SETTING2 QColor(3,2,1) +#define WRITE_SETTING3 QFont("helvetica",14) +#define WRITE_SETTING4 QString("KDE") + +void KConfigSkeletonTest::initTestCase() +{ + setCurrentGroup("MyGroup"); + addItemBool("MySetting1", mMyBool, DEFAULT_SETTING1); + addItemColor("MySetting2", mMyColor, DEFAULT_SETTING2); + + setCurrentGroup("MyOtherGroup"); + addItemFont("MySetting3", mMyFont, DEFAULT_SETTING3); + addItemString("MySetting4", mMyString, DEFAULT_SETTING4); + + QCOMPARE(mMyBool, DEFAULT_SETTING1); + QCOMPARE(mMyColor, DEFAULT_SETTING2); + QCOMPARE(mMyFont, DEFAULT_SETTING3); + QCOMPARE(mMyString, DEFAULT_SETTING4); +} + +void KConfigSkeletonTest::testSimple() +{ + mMyBool = WRITE_SETTING1; + mMyColor = WRITE_SETTING2; + mMyFont = WRITE_SETTING3; + mMyString = WRITE_SETTING4; + + writeConfig (); + + mMyBool = false; + mMyColor = QColor(); + mMyString.clear(); + mMyFont = QFont(); + + readConfig (); + + QCOMPARE(mMyBool, WRITE_SETTING1); + QCOMPARE(mMyColor, WRITE_SETTING2); + QCOMPARE(mMyFont, WRITE_SETTING3); + QCOMPARE(mMyString, WRITE_SETTING4); + +} + +void KConfigSkeletonTest::testRemoveItem() +{ + QVERIFY(findItem("MySetting1")); + removeItem("MySetting1"); + QVERIFY(!findItem("MySetting1")); +} + +void KConfigSkeletonTest::testClear() +{ + QVERIFY(findItem("MySetting2")); + QVERIFY(findItem("MySetting3")); + QVERIFY(findItem("MySetting4")); + + clearItems(); + + QVERIFY(!findItem("MySetting2")); + QVERIFY(!findItem("MySetting3")); + QVERIFY(!findItem("MySetting4")); +} + +void KConfigSkeletonTest::testDefaults() +{ + setDefaults (); + + QCOMPARE(mMyBool, DEFAULT_SETTING1); + QCOMPARE(mMyColor, DEFAULT_SETTING2); + QCOMPARE(mMyFont, DEFAULT_SETTING3); + QCOMPARE(mMyString, DEFAULT_SETTING4); + + writeConfig(); +} + + diff --git a/tier1/kconfig/autotests/kconfigskeletontest.h b/tier1/kconfig/autotests/kconfigskeletontest.h new file mode 100644 index 00000000..f65739dc --- /dev/null +++ b/tier1/kconfig/autotests/kconfigskeletontest.h @@ -0,0 +1,44 @@ +/* This file is part of the KDE libraries + Copyright (C) 2006 Olivier Goffart <ogoffart at kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ +#ifndef KCONFIGSKELETONTEST_H +#define KCONFIGSKELETONTEST_H + +#include <kconfigskeleton.h> + +class KConfigSkeletonTest : public KConfigSkeleton +{ + Q_OBJECT + public: + +private Q_SLOTS: + void initTestCase(); + void testSimple(); + void testDefaults(); + void testRemoveItem(); + void testClear(); + +private: + bool mMyBool; + QColor mMyColor; + QFont mMyFont; + QString mMyString; + +}; + +#endif diff --git a/tier1/kconfig/autotests/kconfigtest.cpp b/tier1/kconfig/autotests/kconfigtest.cpp new file mode 100644 index 00000000..1aed5151 --- /dev/null +++ b/tier1/kconfig/autotests/kconfigtest.cpp @@ -0,0 +1,1634 @@ +/* This file is part of the KDE libraries + Copyright (C) 1997 Matthias Kalle Dalheimer (kalle@kde.org) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +// Qt5 TODO: re-enable. No point in doing it before, it breaks on QString::fromUtf8(QByteArray), which exists in qt5. +#undef QT_NO_CAST_FROM_BYTEARRAY + +#include "kconfigtest.h" + +#include <QtTest/QtTest> +#include <qtemporarydir.h> +#include <QStandardPaths> +#include <kdesktopfile.h> + +#include <ksharedconfig.h> +#include <kconfiggroup.h> + +#ifdef Q_OS_UNIX +#include <utime.h> +#endif +#ifndef Q_OS_WIN +#include <unistd.h> // gethostname +#endif + +KCONFIGGROUP_DECLARE_ENUM_QOBJECT(KConfigTest,Testing) +KCONFIGGROUP_DECLARE_FLAGS_QOBJECT(KConfigTest,Flags) + +QTEST_MAIN( KConfigTest ) + +#define BOOLENTRY1 true +#define BOOLENTRY2 false +#define STRINGENTRY1 "hello" +#define STRINGENTRY2 " hello" +#define STRINGENTRY3 "hello " +#define STRINGENTRY4 " hello " +#define STRINGENTRY5 " " +#define STRINGENTRY6 "" +#define UTF8BITENTRY "Hello äöü" +#define TRANSLATEDSTRINGENTRY1 "bonjour" +#define BYTEARRAYENTRY QByteArray( "\x00\xff\x7f\x3c abc\x00\x00", 10 ) +#define ESCAPEKEY " []\0017[]==]" +#define ESCAPEENTRY "[]\170[]]=3=]\\] " +#define DOUBLEENTRY 123456.78912345 +#define FLOATENTRY 123.567f +#define POINTENTRY QPoint( 4351, 1235 ) +#define SIZEENTRY QSize( 10, 20 ) +#define RECTENTRY QRect( 10, 23, 5321, 13 ) +#define DATETIMEENTRY QDateTime( QDate( 2002, 06, 23 ), QTime( 12, 55, 40 ) ) +#define STRINGLISTENTRY (QStringList( "Hello," ) << " World") +#define STRINGLISTEMPTYENTRY QStringList() +#define STRINGLISTJUSTEMPTYELEMENT QStringList(QString()) +#define STRINGLISTEMPTYTRAINLINGELEMENT (QStringList( "Hi" ) << QString()) +#define STRINGLISTESCAPEODDENTRY (QStringList( "Hello\\\\\\" ) << "World") +#define STRINGLISTESCAPEEVENENTRY (QStringList( "Hello\\\\\\\\" ) << "World") +#define STRINGLISTESCAPECOMMAENTRY (QStringList( "Hel\\\\\\,\\\\,\\,\\\\\\\\,lo" ) << "World") +#define INTLISTENTRY1 QList<int>() << 1 << 2 << 3 << 4 +#define BYTEARRAYLISTENTRY1 QList<QByteArray>() << "" << "1,2" << "end" +#define VARIANTLISTENTRY (QVariantList() << true << false << QString("joe") << 10023) +#define VARIANTLISTENTRY2 (QVariantList() << POINTENTRY << SIZEENTRY) +#define HOMEPATH QString(QDir::homePath()+"/foo") +#define HOMEPATHESCAPE QString(QDir::homePath()+"/foo/$HOME") +#define DOLLARGROUP "$i" + +void KConfigTest::initTestCase() +{ + // ensure we don't use files in the real config directory + QStandardPaths::setTestModeEnabled(true); + QString testConfigDir = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation); + + // to make sure all files from a previous failed run are deleted + cleanupTestCase(); + + + KConfig sc( "kconfigtest" ); + + KConfigGroup cg(&sc, "AAA"); + cg.writeEntry("stringEntry1", STRINGENTRY1, + KConfig::Persistent|KConfig::Global); + cg.deleteEntry("stringEntry2", KConfig::Global); + + cg = KConfigGroup(&sc, "Hello"); + cg.writeEntry( "boolEntry1", BOOLENTRY1 ); + cg.writeEntry( "boolEntry2", BOOLENTRY2 ); + + QByteArray data( UTF8BITENTRY ); + QCOMPARE( data.size(), 12 ); // the source file is in utf8 + QCOMPARE( QString::fromUtf8(data).length(), 9 ); + cg.writeEntry ("Test", data); + cg.writeEntry( "bytearrayEntry", BYTEARRAYENTRY ); + cg.writeEntry( ESCAPEKEY, ESCAPEENTRY ); + cg.writeEntry( "emptyEntry", ""); + cg.writeEntry( "stringEntry1", STRINGENTRY1 ); + cg.writeEntry( "stringEntry2", STRINGENTRY2 ); + cg.writeEntry( "stringEntry3", STRINGENTRY3 ); + cg.writeEntry( "stringEntry4", STRINGENTRY4 ); + cg.writeEntry( "stringEntry5", STRINGENTRY5 ); + cg.writeEntry( "urlEntry1", QUrl("http://qt-project.org") ); + cg.writeEntry( "keywith=equalsign", STRINGENTRY1 ); + cg.deleteEntry( "stringEntry5" ); + cg.deleteEntry( "stringEntry6" ); // deleting a nonexistent entry + cg.writeEntry( "byteArrayEntry1", QByteArray( STRINGENTRY1 ), + KConfig::Global|KConfig::Persistent ); + cg.writeEntry( "doubleEntry1", DOUBLEENTRY ); + cg.writeEntry( "floatEntry1", FLOATENTRY ); + + sc.deleteGroup("deleteMe"); // deleting a nonexistent group + + cg = KConfigGroup(&sc, "Complex Types"); + cg.writeEntry( "rectEntry", RECTENTRY ); + cg.writeEntry( "pointEntry", POINTENTRY ); + cg.writeEntry( "sizeEntry", SIZEENTRY ); + cg.writeEntry( "dateTimeEntry", DATETIMEENTRY ); + cg.writeEntry( "dateEntry", DATETIMEENTRY.date() ); + + KConfigGroup ct = cg; + cg = KConfigGroup(&ct, "Nested Group 1"); + cg.writeEntry("stringentry1", STRINGENTRY1); + + cg = KConfigGroup(&ct, "Nested Group 2"); + cg.writeEntry( "stringEntry2", STRINGENTRY2 ); + + cg = KConfigGroup(&cg, "Nested Group 2.1"); + cg.writeEntry( "stringEntry3", STRINGENTRY3 ); + + cg = KConfigGroup(&ct, "Nested Group 3"); + cg.writeEntry( "stringEntry3", STRINGENTRY3 ); + + cg = KConfigGroup(&sc, "List Types" ); + cg.writeEntry( "listOfIntsEntry1", INTLISTENTRY1 ); + cg.writeEntry( "listOfByteArraysEntry1", BYTEARRAYLISTENTRY1 ); + cg.writeEntry( "stringListEntry", STRINGLISTENTRY ); + cg.writeEntry( "stringListEmptyEntry", STRINGLISTEMPTYENTRY ); + cg.writeEntry( "stringListJustEmptyElement", STRINGLISTJUSTEMPTYELEMENT ); + cg.writeEntry( "stringListEmptyTrailingElement", STRINGLISTEMPTYTRAINLINGELEMENT ); + cg.writeEntry( "stringListEscapeOddEntry", STRINGLISTESCAPEODDENTRY ); + cg.writeEntry( "stringListEscapeEvenEntry", STRINGLISTESCAPEEVENENTRY ); + cg.writeEntry( "stringListEscapeCommaEntry", STRINGLISTESCAPECOMMAENTRY ); + cg.writeEntry( "variantListEntry", VARIANTLISTENTRY ); + + cg = KConfigGroup(&sc, "Path Type" ); + cg.writePathEntry( "homepath", HOMEPATH ); + cg.writePathEntry( "homepathescape", HOMEPATHESCAPE ); + + cg = KConfigGroup(&sc, "Enum Types" ); + writeEntry( cg, "enum-10", Tens ); + writeEntry( cg, "enum-100", Hundreds ); + writeEntry( cg, "flags-bit0", Flags(bit0)); + writeEntry( cg, "flags-bit0-bit1", Flags(bit0|bit1) ); + + cg = KConfigGroup(&sc, "ParentGroup" ); + KConfigGroup cg1(&cg, "SubGroup1" ); + cg1.writeEntry( "somestring", "somevalue" ); + cg.writeEntry( "parentgrpstring", "somevalue" ); + KConfigGroup cg2(&cg, "SubGroup2" ); + cg2.writeEntry( "substring", "somevalue" ); + KConfigGroup cg3(&cg, "SubGroup/3"); + cg3.writeEntry( "sub3string", "somevalue" ); + + QVERIFY(sc.isDirty()); + QVERIFY(sc.sync()); + QVERIFY(!sc.isDirty()); + + QVERIFY2(QFile::exists(testConfigDir + QStringLiteral("/kconfigtest")), + qPrintable(testConfigDir + QStringLiteral("/kconfigtest must exist"))); + QVERIFY2(QFile::exists(testConfigDir + QStringLiteral("/kdeglobals")), + qPrintable(testConfigDir + QStringLiteral("/kdeglobals must exist"))); + + + KConfig sc1("kdebugrc", KConfig::SimpleConfig); + KConfigGroup sg0(&sc1, "0"); + sg0.writeEntry("AbortFatal", false); + sg0.writeEntry("WarnOutput", 0); + sg0.writeEntry("FatalOutput", 0); + QVERIFY(sc1.sync()); + + //Setup stuff to test KConfig::addConfigSources() + KConfig devcfg("specificrc"); + KConfigGroup devonlygrp(&devcfg, "Specific Only Group"); + devonlygrp.writeEntry("ExistingEntry", "DevValue"); + KConfigGroup devandbasegrp(&devcfg, "Shared Group"); + devandbasegrp.writeEntry("SomeSharedEntry", "DevValue"); + devandbasegrp.writeEntry("SomeSpecificOnlyEntry", "DevValue"); + QVERIFY(devcfg.sync()); + KConfig basecfg("baserc"); + KConfigGroup basegrp(&basecfg, "Base Only Group"); + basegrp.writeEntry("ExistingEntry", "BaseValue"); + KConfigGroup baseanddevgrp(&basecfg, "Shared Group"); + baseanddevgrp.writeEntry("SomeSharedEntry", "BaseValue"); + baseanddevgrp.writeEntry("SomeBaseOnlyEntry", "BaseValue"); + QVERIFY(basecfg.sync()); + + KConfig gecfg("groupescapetest", KConfig::SimpleConfig); + cg = KConfigGroup(&gecfg, DOLLARGROUP); + cg.writeEntry( "entry", "doesntmatter" ); + +} + +void KConfigTest::cleanupTestCase() +{ + //ensure we don't delete the real directory + QStandardPaths::setTestModeEnabled(true); + QDir localConfig(QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation)); + //qDebug() << "Erasing" << localConfig; + localConfig.removeRecursively(); + QVERIFY(!localConfig.exists()); +} + + +static QList<QByteArray> readLinesFrom(const QString& path) +{ + QFile file(path); + const bool opened = file.open(QIODevice::ReadOnly|QIODevice::Text); + Q_ASSERT(opened); + Q_UNUSED(opened); + QList<QByteArray> lines; + QByteArray line; + do { + line = file.readLine(); + if (!line.isEmpty()) + lines.append(line); + } while(!line.isEmpty()); + return lines; +} + +static QList<QByteArray> readLines(const char* fileName = "kconfigtest") +{ + const QString path = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + '/' + fileName; + Q_ASSERT(!path.isEmpty()); + return readLinesFrom(path); +} + +// see also testDefaults, which tests reverting with a defaults (global) file available +void KConfigTest::testDirtyAfterRevert() +{ + KConfig sc( "kconfigtest_revert" ); + + KConfigGroup cg(&sc, "Hello"); + cg.revertToDefault( "does_not_exist" ); + QVERIFY(!sc.isDirty()); + cg.writeEntry("Test", "Correct"); + QVERIFY(sc.isDirty()); + sc.sync(); + QVERIFY(!sc.isDirty()); + + cg.revertToDefault("Test"); + QVERIFY(sc.isDirty()); + QVERIFY(sc.sync()); + QVERIFY(!sc.isDirty()); + + cg.revertToDefault("Test"); + QVERIFY(!sc.isDirty()); +} + +void KConfigTest::testRevertAllEntries() +{ + // this tests the case were we revert (delete) all entries in a file, + // leaving a blank file + { + KConfig sc( "konfigtest2", KConfig::SimpleConfig ); + KConfigGroup cg( &sc, "Hello" ); + cg.writeEntry( "Test", "Correct" ); + } + + { + KConfig sc( "konfigtest2", KConfig::SimpleConfig ); + KConfigGroup cg( &sc, "Hello" ); + QCOMPARE( cg.readEntry( "Test", "Default" ), QString("Correct") ); + cg.revertToDefault( "Test" ); + } + + KConfig sc( "konfigtest2", KConfig::SimpleConfig ); + KConfigGroup cg( &sc, "Hello" ); + QCOMPARE( cg.readEntry( "Test", "Default" ), QString("Default") ); +} + +void KConfigTest::testSimple() +{ + // kdeglobals (which was created in initTestCase) must be found this way: + const QStringList kdeglobals = QStandardPaths::locateAll(QStandardPaths::GenericConfigLocation, QLatin1String("kdeglobals")); + QVERIFY(!kdeglobals.isEmpty()); + + KConfig sc2( "kconfigtest" ); + QCOMPARE(sc2.name(), QString("kconfigtest")); + + // make sure groupList() isn't returning something it shouldn't + Q_FOREACH(const QString& group, sc2.groupList()) { + QVERIFY(!group.isEmpty() && group != "<default>"); + QVERIFY(!group.contains(QChar(0x1d))); + } + + KConfigGroup sc3( &sc2, "AAA"); + + QVERIFY( sc3.hasKey( "stringEntry1" ) ); // from kdeglobals + QVERIFY( !sc3.isEntryImmutable("stringEntry1") ); + QCOMPARE( sc3.readEntry( "stringEntry1" ), QString( STRINGENTRY1 ) ); + + QVERIFY( !sc3.hasKey( "stringEntry2" ) ); + QCOMPARE( sc3.readEntry( "stringEntry2", QString("bla") ), QString( "bla" ) ); + + QVERIFY( !sc3.hasDefault( "stringEntry1" ) ); + + sc3 = KConfigGroup(&sc2, "Hello"); + QCOMPARE( sc3.readEntry( "Test", QByteArray() ), QByteArray( UTF8BITENTRY ) ); + QCOMPARE( sc3.readEntry( "bytearrayEntry", QByteArray() ), BYTEARRAYENTRY ); + QCOMPARE( sc3.readEntry( ESCAPEKEY ), QString( ESCAPEENTRY ) ); + QCOMPARE( sc3.readEntry( "Test", QString() ), QString::fromUtf8( UTF8BITENTRY ) ); + QCOMPARE( sc3.readEntry( "emptyEntry"/*, QString("Fietsbel")*/), QString("") ); + QCOMPARE( sc3.readEntry("emptyEntry", QString("Fietsbel")).isEmpty(), true ); + QCOMPARE( sc3.readEntry( "stringEntry1" ), QString( STRINGENTRY1 ) ); + QCOMPARE( sc3.readEntry( "stringEntry2" ), QString( STRINGENTRY2 ) ); + QCOMPARE( sc3.readEntry( "stringEntry3" ), QString( STRINGENTRY3 ) ); + QCOMPARE( sc3.readEntry( "stringEntry4" ), QString( STRINGENTRY4 ) ); + QVERIFY( !sc3.hasKey( "stringEntry5" ) ); + QCOMPARE( sc3.readEntry( "stringEntry5", QString("test") ), QString( "test" ) ); + QVERIFY( !sc3.hasKey( "stringEntry6" ) ); + QCOMPARE( sc3.readEntry( "stringEntry6", QString("foo") ), QString( "foo" ) ); + QCOMPARE( sc3.readEntry( "urlEntry1", QUrl() ), QUrl("http://qt-project.org") ); + QCOMPARE( sc3.readEntry( "boolEntry1", BOOLENTRY1 ), BOOLENTRY1 ); + QCOMPARE( sc3.readEntry( "boolEntry2", false ), BOOLENTRY2 ); + QCOMPARE( sc3.readEntry("keywith=equalsign", QString("wrong")), QString(STRINGENTRY1)); + QCOMPARE( sc3.readEntry( "byteArrayEntry1", QByteArray() ), + QByteArray( STRINGENTRY1 ) ); + QCOMPARE( sc3.readEntry( "doubleEntry1", 0.0 ), DOUBLEENTRY ); + QCOMPARE( sc3.readEntry( "floatEntry1", 0.0f ), FLOATENTRY ); +} + +void KConfigTest::testDefaults() +{ + KConfig config("defaulttest", KConfig::NoGlobals); + const QString defaultsFile = "defaulttest.defaults"; + KConfig defaults(defaultsFile, KConfig::SimpleConfig); + + const QString Default("Default"); + const QString NotDefault("Not Default"); + const QString Value1(STRINGENTRY1); + const QString Value2(STRINGENTRY2); + + KConfigGroup group = defaults.group("any group"); + group.writeEntry("entry1", Default); + QVERIFY(group.sync()); + + group = config.group("any group"); + group.writeEntry("entry1", Value1); + group.writeEntry("entry2", Value2); + QVERIFY(group.sync()); + + config.addConfigSources(QStringList() << QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + '/' + defaultsFile); + + config.setReadDefaults(true); + QCOMPARE(group.readEntry("entry1", QString()), Default); + QCOMPARE(group.readEntry("entry2", NotDefault), NotDefault); // no default for entry2 + + config.setReadDefaults(false); + QCOMPARE(group.readEntry("entry1", Default), Value1); + QCOMPARE(group.readEntry("entry2", NotDefault), Value2); + + group.revertToDefault("entry1"); + QCOMPARE(group.readEntry("entry1", QString()), Default); + group.revertToDefault("entry2"); + QCOMPARE(group.readEntry("entry2", QString()), QString()); + + // TODO test reverting localized entries + + Q_ASSERT(config.isDirty()); + group.sync(); + + // Check that everything is OK on disk, too + KConfig reader("defaulttest", KConfig::NoGlobals); + reader.addConfigSources(QStringList() << QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + '/' + defaultsFile); + KConfigGroup readerGroup = reader.group("any group"); + QCOMPARE(readerGroup.readEntry("entry1", QString()), Default); + QCOMPARE(readerGroup.readEntry("entry2", QString()), QString()); +} + +void KConfigTest::testLocale() +{ + KConfig config("kconfigtest.locales", KConfig::SimpleConfig); + const QString Translated(TRANSLATEDSTRINGENTRY1); + const QString Untranslated(STRINGENTRY1); + + KConfigGroup group = config.group("Hello"); + group.writeEntry("stringEntry1", Untranslated); + config.setLocale("fr"); + group.writeEntry("stringEntry1", Translated, KConfig::Localized|KConfig::Persistent); + QVERIFY(config.sync()); + + QCOMPARE(group.readEntry("stringEntry1", QString()), Translated); + QCOMPARE(group.readEntryUntranslated("stringEntry1"), Untranslated); + + config.setLocale("C"); // strings written in the "C" locale are written as nonlocalized + group.writeEntry("stringEntry1", Untranslated, KConfig::Localized|KConfig::Persistent); + QVERIFY(config.sync()); + + QCOMPARE(group.readEntry("stringEntry1", QString()), Untranslated); +} + +void KConfigTest::testEncoding() +{ + QString groupstr = QString::fromUtf8("UTF-8:\xc3\xb6l"); + + KConfig c( "kconfigtestencodings" ); + KConfigGroup cg(&c, groupstr); + cg.writeEntry("key", "value"); + QVERIFY(c.sync()); + + QList<QByteArray> lines = readLines("kconfigtestencodings"); + QCOMPARE(lines.count(), 2); + QCOMPARE(lines.first(), QByteArray("[UTF-8:\xc3\xb6l]\n")); + + KConfig c2( "kconfigtestencodings" ); + KConfigGroup cg2(&c2, groupstr); + QVERIFY(cg2.readEntry("key") == QByteArray("value")); + + QVERIFY(c2.groupList().contains(groupstr)); +} + +void KConfigTest::testLists() +{ + KConfig sc2( "kconfigtest" ); + KConfigGroup sc3(&sc2, "List Types"); + + QCOMPARE( sc3.readEntry( QString("stringListEntry"), QStringList()), + STRINGLISTENTRY ); + + QCOMPARE( sc3.readEntry( QString("stringListEmptyEntry"), QStringList("wrong") ), + STRINGLISTEMPTYENTRY ); + + QCOMPARE( sc3.readEntry( QString("stringListJustEmptyElement"), QStringList() ), + STRINGLISTJUSTEMPTYELEMENT ); + + QCOMPARE( sc3.readEntry( QString("stringListEmptyTrailingElement"), QStringList() ), + STRINGLISTEMPTYTRAINLINGELEMENT ); + + QCOMPARE( sc3.readEntry( QString("stringListEscapeOddEntry"), QStringList()), + STRINGLISTESCAPEODDENTRY ); + + QCOMPARE( sc3.readEntry( QString("stringListEscapeEvenEntry"), QStringList()), + STRINGLISTESCAPEEVENENTRY ); + + QCOMPARE( sc3.readEntry( QString("stringListEscapeCommaEntry"), QStringList()), + STRINGLISTESCAPECOMMAENTRY ); + + QCOMPARE( sc3.readEntry( "listOfIntsEntry1" ), QString::fromLatin1( "1,2,3,4" ) ); + QList<int> expectedIntList = INTLISTENTRY1; + QVERIFY( sc3.readEntry( "listOfIntsEntry1", QList<int>() ) == expectedIntList ); + + QCOMPARE( QVariant(sc3.readEntry( "variantListEntry", VARIANTLISTENTRY )).toStringList(), + QVariant(VARIANTLISTENTRY).toStringList() ); + + QCOMPARE( sc3.readEntry( "listOfByteArraysEntry1", QList<QByteArray>()), BYTEARRAYLISTENTRY1 ); +} + +void KConfigTest::testPath() +{ + KConfig sc2( "kconfigtest" ); + KConfigGroup sc3(&sc2, "Path Type"); + QCOMPARE( sc3.readPathEntry( "homepath", QString() ), HOMEPATH ); + QCOMPARE( sc3.readPathEntry( "homepathescape", QString() ), HOMEPATHESCAPE ); + QCOMPARE( sc3.entryMap()["homepath"], HOMEPATH ); + + { + QFile file(QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + "/pathtest"); + file.open(QIODevice::WriteOnly|QIODevice::Text); + QTextStream out(&file); + out.setCodec("UTF-8"); + out << "[Test Group]" << endl + << "homePath=$HOME/foo" << endl + << "homePath2=file://$HOME/foo" << endl + << "withBraces[$e]=file://${HOME}/foo" << endl + << "URL[$e]=file://${HOME}/foo" << endl + << "hostname[$e]=$(hostname)" << endl + << "noeol=foo"; // no EOL + } + KConfig cf2("pathtest"); + KConfigGroup group = cf2.group("Test Group"); + QVERIFY(group.hasKey("homePath")); + QCOMPARE(group.readPathEntry("homePath", QString()), HOMEPATH); + QVERIFY(group.hasKey("homePath2")); + QCOMPARE(group.readPathEntry("homePath2", QString()), QString("file://" + HOMEPATH) ); + QVERIFY(group.hasKey("withBraces")); + QCOMPARE(group.readPathEntry("withBraces", QString()), QString("file://" + HOMEPATH) ); + QVERIFY(group.hasKey("URL")); + QCOMPARE(group.readEntry("URL", QString()), QString("file://" + HOMEPATH) ); +#if !defined(Q_OS_WIN32) && !defined(Q_OS_MAC) + // I don't know if this will work on windows + // This test hangs on OS X + QVERIFY(group.hasKey("hostname")); + char hostname[256]; + QVERIFY(::gethostname(hostname, sizeof(hostname)) == 0); + QCOMPARE(group.readEntry("hostname", QString()), QString::fromLatin1(hostname)); +#endif + QVERIFY(group.hasKey("noeol")); + QCOMPARE(group.readEntry("noeol", QString()), QString("foo")); +} + +void KConfigTest::testPersistenceOfExpandFlagForPath() +{ + // This test checks that a path entry starting with $HOME is still flagged + // with the expand flag after the config was altered without rewriting the + // path entry. + + // 1st step: Open the config, add a new dummy entry and then sync the config + // back to the storage. + { + KConfig sc2( "kconfigtest" ); + KConfigGroup sc3(&sc2, "Path Type"); + sc3.writeEntry( "dummy", "dummy" ); + QVERIFY(sc2.sync()); + } + + // 2nd step: Call testPath() again. Rewriting the config must not break + // the testPath() test. + testPath(); +} + +void KConfigTest::testComplex() +{ + KConfig sc2( "kconfigtest" ); + KConfigGroup sc3(&sc2, "Complex Types"); + + QCOMPARE( sc3.readEntry( "pointEntry", QPoint() ), POINTENTRY ); + QCOMPARE( sc3.readEntry( "sizeEntry", SIZEENTRY ), SIZEENTRY); + QCOMPARE( sc3.readEntry( "rectEntry", QRect(1,2,3,4) ), RECTENTRY ); + QCOMPARE( sc3.readEntry( "dateTimeEntry", QDateTime() ).toString(Qt::ISODate), + DATETIMEENTRY.toString(Qt::ISODate) ); + QCOMPARE( sc3.readEntry( "dateEntry", QDate() ).toString(Qt::ISODate), + DATETIMEENTRY.date().toString(Qt::ISODate) ); + QCOMPARE( sc3.readEntry( "dateTimeEntry", QDate() ), DATETIMEENTRY.date() ); +} + +void KConfigTest::testEnums() +{ + KConfig sc("kconfigtest"); + KConfigGroup sc3(&sc, "Enum Types" ); + + QCOMPARE( sc3.readEntry( "enum-10" ), QString("Tens")); + QVERIFY( readEntry( sc3, "enum-100", Ones) != Ones); + QVERIFY( readEntry( sc3, "enum-100", Ones) != Tens); + + QCOMPARE( sc3.readEntry( "flags-bit0" ), QString("bit0")); + QVERIFY( readEntry( sc3, "flags-bit0", Flags() ) == bit0 ); + + int eid = staticMetaObject.indexOfEnumerator( "Flags" ); + QVERIFY( eid != -1 ); + QMetaEnum me = staticMetaObject.enumerator( eid ); + Flags bitfield = bit0|bit1; + + QCOMPARE( sc3.readEntry( "flags-bit0-bit1" ), QString( me.valueToKeys(bitfield) ) ); + QVERIFY( readEntry( sc3, "flags-bit0-bit1", Flags() ) == bitfield ); +} + +void KConfigTest::testEntryMap() +{ + KConfig sc("kconfigtest"); + KConfigGroup cg(&sc, "Hello"); + QMap<QString, QString> entryMap = cg.entryMap(); + qDebug() << entryMap.keys(); + QCOMPARE(entryMap.value("stringEntry1"), QString(STRINGENTRY1)); + QCOMPARE(entryMap.value("stringEntry2"), QString(STRINGENTRY2)); + QCOMPARE(entryMap.value("stringEntry3"), QString(STRINGENTRY3)); + QCOMPARE(entryMap.value("stringEntry4"), QString(STRINGENTRY4)); + QVERIFY(!entryMap.contains("stringEntry5")); + QVERIFY(!entryMap.contains("stringEntry6")); + QCOMPARE(entryMap.value("Test"), QString::fromUtf8(UTF8BITENTRY)); + QCOMPARE(entryMap.value("bytearrayEntry"), QString::fromUtf8(BYTEARRAYENTRY)); + QCOMPARE(entryMap.value("emptyEntry"), QString()); + QVERIFY(entryMap.contains("emptyEntry")); + QCOMPARE(entryMap.value("boolEntry1"), QString(BOOLENTRY1?"true":"false")); + QCOMPARE(entryMap.value("boolEntry2"), QString(BOOLENTRY2?"true":"false")); + QCOMPARE(entryMap.value("keywith=equalsign"), QString(STRINGENTRY1)); + QCOMPARE(entryMap.value("byteArrayEntry1"), QString(STRINGENTRY1)); + QCOMPARE(entryMap.value("doubleEntry1"), QString::number(DOUBLEENTRY, 'g', 15)); + QCOMPARE(entryMap.value("floatEntry1"), QString::number(FLOATENTRY, 'g', 8)); +} + +void KConfigTest::testInvalid() +{ + KConfig sc( "kconfigtest" ); + + // all of these should print a message to the kdebug.dbg file + KConfigGroup sc3(&sc, "Invalid Types" ); + sc3.writeEntry( "badList", VARIANTLISTENTRY2 ); + + QList<int> list; + + // 1 element list + list << 1; + sc3.writeEntry( QString("badList"), list); + + QVERIFY( sc3.readEntry( "badList", QPoint() ) == QPoint() ); + QVERIFY( sc3.readEntry( "badList", QRect() ) == QRect() ); + QVERIFY( sc3.readEntry( "badList", QSize() ) == QSize() ); + QVERIFY( sc3.readEntry( "badList", QDate() ) == QDate() ); + QVERIFY( sc3.readEntry( "badList", QDateTime() ) == QDateTime() ); + + // 2 element list + list << 2; + sc3.writeEntry( "badList", list); + + QVERIFY( sc3.readEntry( "badList", QRect() ) == QRect() ); + QVERIFY( sc3.readEntry( "badList", QDate() ) == QDate() ); + QVERIFY( sc3.readEntry( "badList", QDateTime() ) == QDateTime() ); + + // 3 element list + list << 303; + sc3.writeEntry( "badList", list); + + QVERIFY( sc3.readEntry( "badList", QPoint() ) == QPoint() ); + QVERIFY( sc3.readEntry( "badList", QRect() ) == QRect() ); + QVERIFY( sc3.readEntry( "badList", QSize() ) == QSize() ); + QVERIFY( sc3.readEntry( "badList", QDate() ) == QDate() ); // out of bounds + QVERIFY( sc3.readEntry( "badList", QDateTime() ) == QDateTime() ); + + // 4 element list + list << 4; + sc3.writeEntry( "badList", list ); + + QVERIFY( sc3.readEntry( "badList", QPoint() ) == QPoint() ); + QVERIFY( sc3.readEntry( "badList", QSize() ) == QSize() ); + QVERIFY( sc3.readEntry( "badList", QDate() ) == QDate() ); + QVERIFY( sc3.readEntry( "badList", QDateTime() ) == QDateTime() ); + + // 5 element list + list[2] = 3; + list << 5; + sc3.writeEntry( "badList", list); + + QVERIFY( sc3.readEntry( "badList", QPoint() ) == QPoint() ); + QVERIFY( sc3.readEntry( "badList", QRect() ) == QRect() ); + QVERIFY( sc3.readEntry( "badList", QSize() ) == QSize() ); + QVERIFY( sc3.readEntry( "badList", QDate() ) == QDate() ); + QVERIFY( sc3.readEntry( "badList", QDateTime() ) == QDateTime() ); + + // 6 element list + list << 6; + sc3.writeEntry( "badList", list); + + QVERIFY( sc3.readEntry( "badList", QPoint() ) == QPoint() ); + QVERIFY( sc3.readEntry( "badList", QRect() ) == QRect() ); + QVERIFY( sc3.readEntry( "badList", QSize() ) == QSize() ); +} + +void KConfigTest::testChangeGroup() +{ + KConfig sc( "kconfigtest" ); + KConfigGroup sc3(&sc, "Hello"); + QCOMPARE(sc3.name(), QString("Hello")); + KConfigGroup newGroup(sc3); +#ifndef KDE_NO_DEPRECATED + newGroup.changeGroup("FooBar"); // deprecated! + QCOMPARE(newGroup.name(), QString("FooBar")); + QCOMPARE(sc3.name(), QString("Hello")); // unchanged + + // Write into the "changed group" and check that it works + newGroup.writeEntry("InFooBar", "FB"); + QCOMPARE(KConfigGroup(&sc, "FooBar").entryMap().value("InFooBar"), QString("FB")); + QCOMPARE(KConfigGroup(&sc, "Hello").entryMap().value("InFooBar"), QString()); +#endif + + KConfigGroup rootGroup(sc.group("")); + QCOMPARE(rootGroup.name(), QString("<default>")); + KConfigGroup sc32(rootGroup.group("Hello")); + QCOMPARE(sc32.name(), QString("Hello")); + KConfigGroup newGroup2(sc32); +#ifndef KDE_NO_DEPRECATED + newGroup2.changeGroup("FooBar"); // deprecated! + QCOMPARE(newGroup2.name(), QString("FooBar")); + QCOMPARE(sc32.name(), QString("Hello")); // unchanged +#endif +} + +// Simple test for deleteEntry +void KConfigTest::testDeleteEntry() +{ + const char* configFile = "kconfigdeletetest"; + { + KConfig conf(configFile); + conf.group("Hello").writeEntry("DelKey", "ToBeDeleted"); + } + const QList<QByteArray> lines = readLines(configFile); + Q_ASSERT(lines.contains("[Hello]\n")); + Q_ASSERT(lines.contains("DelKey=ToBeDeleted\n")); + + KConfig sc(configFile); + KConfigGroup group(&sc, "Hello"); + + group.deleteEntry("DelKey"); + QCOMPARE( group.readEntry("DelKey", QString("Fietsbel")), QString("Fietsbel") ); + + QVERIFY(group.sync()); + Q_ASSERT(!readLines(configFile).contains("DelKey=ToBeDeleted\n")); + QCOMPARE( group.readEntry("DelKey", QString("still deleted")), QString("still deleted") ); +} + +void KConfigTest::testDelete() +{ + KConfig sc( "kconfigtest" ); + + KConfigGroup ct(&sc, "Complex Types"); + + // First delete a nested group + KConfigGroup delgr(&ct, "Nested Group 3"); + QVERIFY(delgr.exists()); + QVERIFY(ct.hasGroup("Nested Group 3")); + delgr.deleteGroup(); + QVERIFY(!delgr.exists()); + QVERIFY(!ct.hasGroup("Nested Group 3")); + QVERIFY(ct.groupList().contains("Nested Group 3")); + + KConfigGroup ng(&ct, "Nested Group 2"); + QVERIFY(sc.hasGroup("Complex Types")); + QVERIFY(!sc.hasGroup("Does not exist")); + sc.deleteGroup("Complex Types"); + QCOMPARE(sc.group("Complex Types").keyList().count(), 0); + QVERIFY(!sc.hasGroup("Complex Types")); // #192266 + QVERIFY(!sc.group("Complex Types").exists()); + QVERIFY(!ct.hasGroup("Nested Group 1")); + + QCOMPARE(ct.group("Nested Group 1").keyList().count(), 0); + QCOMPARE(ct.group("Nested Group 2").keyList().count(), 0); + QCOMPARE(ng.group("Nested Group 2.1").keyList().count(), 0); + + KConfigGroup cg(&sc , "AAA" ); + cg.deleteGroup(); + QVERIFY( sc.entryMap("Complex Types").isEmpty() ); + QVERIFY( sc.entryMap("AAA").isEmpty() ); + QVERIFY( !sc.entryMap("Hello").isEmpty() ); //not deleted group + QVERIFY( sc.entryMap("FooBar").isEmpty() ); //inexistant group + + QVERIFY(cg.sync()); + // Check what happens on disk + const QList<QByteArray> lines = readLines(); + //qDebug() << lines; + QVERIFY(!lines.contains("[Complex Types]\n")); + QVERIFY(!lines.contains("[Complex Types][Nested Group 1]\n")); + QVERIFY(!lines.contains("[Complex Types][Nested Group 2]\n")); + QVERIFY(!lines.contains("[Complex Types][Nested Group 2.1]\n")); + QVERIFY(!lines.contains("[AAA]\n")); + QVERIFY(lines.contains("[Hello]\n")); // a group that was not deleted + + // test for entries that are marked as deleted when there is no default + KConfig cf("kconfigtest", KConfig::SimpleConfig); // make sure there are no defaults + cg = cf.group("Portable Devices"); + cg.writeEntry("devices|manual|(null)", "whatever"); + cg.writeEntry("devices|manual|/mnt/ipod", "/mnt/ipod"); + QVERIFY(cf.sync()); + + int count=0; + Q_FOREACH(const QByteArray& item, readLines()) + if (item.startsWith("devices|")) // krazy:exclude=strings + count++; + QCOMPARE(count, 2); + cg.deleteEntry("devices|manual|/mnt/ipod"); + QVERIFY(cf.sync()); + Q_FOREACH(const QByteArray& item, readLines()) + QVERIFY(!item.contains("ipod")); +} + +void KConfigTest::testDefaultGroup() +{ + KConfig sc( "kconfigtest" ); + KConfigGroup defaultGroup(&sc, "<default>"); + QCOMPARE(defaultGroup.name(), QString("<default>")); + QVERIFY(!defaultGroup.exists()); + defaultGroup.writeEntry("TestKey", "defaultGroup"); + QVERIFY(defaultGroup.exists()); + QCOMPARE(defaultGroup.readEntry("TestKey", QString()), QString("defaultGroup")); + QVERIFY(sc.sync()); + + { + // Test reading it + KConfig sc2("kconfigtest"); + KConfigGroup defaultGroup2(&sc2, "<default>"); + QCOMPARE(defaultGroup2.name(), QString("<default>")); + QVERIFY(defaultGroup2.exists()); + QCOMPARE(defaultGroup2.readEntry("TestKey", QString()), QString("defaultGroup")); + } + { + // Test reading it + KConfig sc2("kconfigtest"); + KConfigGroup emptyGroup(&sc2, ""); + QCOMPARE(emptyGroup.name(), QString("<default>")); + QVERIFY(emptyGroup.exists()); + QCOMPARE(emptyGroup.readEntry("TestKey", QString()), QString("defaultGroup")); + } + + QList<QByteArray> lines = readLines(); + QVERIFY(!lines.contains("[]\n")); + QCOMPARE(lines.first(), QByteArray("TestKey=defaultGroup\n")); + + // Now that the group exists make sure it isn't returned from groupList() + Q_FOREACH(const QString& group, sc.groupList()) { + QVERIFY(!group.isEmpty() && group != "<default>"); + } + + defaultGroup.deleteGroup(); + QVERIFY(sc.sync()); + + // Test if deleteGroup worked + lines = readLines(); + QVERIFY(lines.first() != QByteArray("TestKey=defaultGroup\n")); +} + +void KConfigTest::testEmptyGroup() +{ + KConfig sc( "kconfigtest" ); + KConfigGroup emptyGroup(&sc, ""); + QCOMPARE(emptyGroup.name(), QString("<default>")); // confusing, heh? + QVERIFY(!emptyGroup.exists()); + emptyGroup.writeEntry("TestKey", "emptyGroup"); + QVERIFY(emptyGroup.exists()); + QCOMPARE(emptyGroup.readEntry("TestKey", QString()), QString("emptyGroup")); + QVERIFY(sc.sync()); + + { + // Test reading it + KConfig sc2("kconfigtest"); + KConfigGroup defaultGroup(&sc2, "<default>"); + QCOMPARE(defaultGroup.name(), QString("<default>")); + QVERIFY(defaultGroup.exists()); + QCOMPARE(defaultGroup.readEntry("TestKey", QString()), QString("emptyGroup")); + } + { + // Test reading it + KConfig sc2("kconfigtest"); + KConfigGroup emptyGroup2(&sc2, ""); + QCOMPARE(emptyGroup2.name(), QString("<default>")); + QVERIFY(emptyGroup2.exists()); + QCOMPARE(emptyGroup2.readEntry("TestKey", QString()), QString("emptyGroup")); + } + + QList<QByteArray> lines = readLines(); + QVERIFY(!lines.contains("[]\n")); // there's no support for the [] group, in fact. + QCOMPARE(lines.first(), QByteArray("TestKey=emptyGroup\n")); + + // Now that the group exists make sure it isn't returned from groupList() + Q_FOREACH(const QString& group, sc.groupList()) { + QVERIFY(!group.isEmpty() && group != "<default>"); + } + emptyGroup.deleteGroup(); + QVERIFY(sc.sync()); + + // Test if deleteGroup worked + lines = readLines(); + QVERIFY(lines.first() != QByteArray("TestKey=defaultGroup\n")); +} + +void KConfigTest::testCascadingWithLocale() +{ + // This test relies on XDG_CONFIG_DIRS, which only has effect on Unix. + // Cascading (more than two levels) isn't available at all on Windows. +#ifdef Q_OS_UNIX + QTemporaryDir middleDir; + QTemporaryDir globalDir; + qputenv("XDG_CONFIG_DIRS", qPrintable(middleDir.path() + QString(":") + globalDir.path())); + + const QString globalConfigDir = globalDir.path(); + QVERIFY(QDir().mkpath(globalConfigDir)); + QFile global(globalConfigDir + "/foo.desktop"); + QVERIFY(global.open(QIODevice::WriteOnly|QIODevice::Text)); + QTextStream globalOut(&global); + globalOut << "[Group]" << endl + << "FromGlobal=true" << endl + << "FromGlobal[fr]=vrai" << endl + << "Name=Testing" << endl + << "Name[fr]=FR" << endl + << "Other=Global" << endl + << "Other[fr]=Global_FR" << endl; + global.close(); + + const QString middleConfigDir = middleDir.path(); + QVERIFY(QDir().mkpath(middleConfigDir)); + QFile local(middleConfigDir + "/foo.desktop"); + QVERIFY(local.open(QIODevice::WriteOnly|QIODevice::Text)); + QTextStream out(&local); + out << "[Group]" << endl + << "FromLocal=true" << endl + << "FromLocal[fr]=vrai" << endl + << "Name=Local Testing" << endl + << "Name[fr]=FR" << endl + << "Other=English Only" << endl; + local.close(); + + KConfig config("foo.desktop"); + KConfigGroup group = config.group("Group"); + QCOMPARE(group.readEntry("FromGlobal"), QString("true")); + QCOMPARE(group.readEntry("FromLocal"), QString("true")); + QCOMPARE(group.readEntry("Name"), QString("Local Testing")); + config.setLocale("fr"); + QCOMPARE(group.readEntry("FromGlobal"), QString("vrai")); + QCOMPARE(group.readEntry("FromLocal"), QString("vrai")); + QCOMPARE(group.readEntry("Name"), QString("FR")); + QCOMPARE(group.readEntry("Other"), QString("English Only")); // Global_FR is locally overriden +#endif +} + +void KConfigTest::testMerge() +{ + KConfig config("mergetest", KConfig::SimpleConfig); + + KConfigGroup cg = config.group("some group"); + cg.writeEntry("entry", " random entry"); + cg.writeEntry("another entry", "blah blah blah"); + + { // simulate writing by another process + QFile file(QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + "/mergetest"); + file.open(QIODevice::WriteOnly|QIODevice::Text); + QTextStream out(&file); + out.setCodec("UTF-8"); + out << "[Merged Group]" << endl + << "entry1=Testing" << endl + << "entry2=More Testing" << endl + << "[some group]" << endl + << "entry[fr]=French" << endl + << "entry[es]=Spanish" << endl + << "entry[de]=German" << endl; + } + QVERIFY(config.sync()); + + { + QList<QByteArray> lines; + // this is what the file should look like + lines << "[Merged Group]\n" + << "entry1=Testing\n" + << "entry2=More Testing\n" + << "\n" + << "[some group]\n" + << "another entry=blah blah blah\n" + << "entry=\\srandom entry\n" + << "entry[de]=German\n" + << "entry[es]=Spanish\n" + << "entry[fr]=French\n"; + QFile file(QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + "/mergetest"); + file.open(QIODevice::ReadOnly|QIODevice::Text); + Q_FOREACH (const QByteArray& line, lines) { + QCOMPARE(line, file.readLine()); + } + } +} + +void KConfigTest::testImmutable() +{ + { + QFile file(QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + "/immutabletest"); + file.open(QIODevice::WriteOnly|QIODevice::Text); + QTextStream out(&file); + out.setCodec("UTF-8"); + out << "[$i]" << endl + << "entry1=Testing" << endl + << "[group][$i]" << endl + << "[group][subgroup][$i]" << endl; + } + + KConfig config("immutabletest", KConfig::SimpleConfig); + QVERIFY(config.isGroupImmutable(QByteArray())); + KConfigGroup cg = config.group(QByteArray()); + QVERIFY(cg.isEntryImmutable("entry1")); + KConfigGroup cg1 = config.group("group"); + QVERIFY(cg1.isImmutable()); + KConfigGroup cg1a = cg.group("group"); + QVERIFY(cg1a.isImmutable()); + KConfigGroup cg2 = cg1.group("subgroup"); + QVERIFY(cg2.isImmutable()); +} + +void KConfigTest::testOptionOrder() +{ + { + QFile file(QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + "/doubleattrtest"); + file.open(QIODevice::WriteOnly|QIODevice::Text); + QTextStream out(&file); + out.setCodec("UTF-8"); + out << "[group3]" << endl + << "entry2=unlocalized" << endl + << "entry2[$i][de_DE]=t2" << endl; + } + KConfig config("doubleattrtest", KConfig::SimpleConfig); + config.setLocale("de_DE"); + KConfigGroup cg3 = config.group("group3"); + QVERIFY(!cg3.isImmutable()); + QCOMPARE(cg3.readEntry("entry2",""), QString("t2")); + QVERIFY(cg3.isEntryImmutable("entry2")); + config.setLocale("C"); + QCOMPARE(cg3.readEntry("entry2",""), QString("unlocalized")); + QVERIFY(!cg3.isEntryImmutable("entry2")); + cg3.writeEntry("entry2","modified"); + QVERIFY(config.sync()); + + { + QList<QByteArray> lines; + // this is what the file should look like + lines << "[group3]\n" + << "entry2=modified\n" + << "entry2[de_DE][$i]=t2\n"; + + QFile file(QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + "/doubleattrtest"); + file.open(QIODevice::ReadOnly|QIODevice::Text); + Q_FOREACH (const QByteArray& line, lines) { + QCOMPARE(line, file.readLine()); + } + } +} + + +void KConfigTest::testGroupEscape() +{ + KConfig config("groupescapetest", KConfig::SimpleConfig); + QVERIFY( config.group(DOLLARGROUP).exists() ); +} + +void KConfigTest::testSubGroup() +{ + KConfig sc( "kconfigtest" ); + KConfigGroup cg( &sc, "ParentGroup" ); + QCOMPARE(cg.readEntry( "parentgrpstring", ""), QString("somevalue") ); + KConfigGroup subcg1( &cg, "SubGroup1"); + QCOMPARE(subcg1.name(), QString("SubGroup1")); + QCOMPARE(subcg1.readEntry( "somestring", ""), QString("somevalue") ); + KConfigGroup subcg2( &cg, "SubGroup2"); + QCOMPARE(subcg2.name(), QString("SubGroup2")); + QCOMPARE(subcg2.readEntry( "substring", ""), QString("somevalue") ); + KConfigGroup subcg3( &cg, "SubGroup/3"); + QCOMPARE(subcg3.readEntry( "sub3string", ""), QString("somevalue") ); + QCOMPARE(subcg3.name(), QString("SubGroup/3")); + KConfigGroup rcg( &sc, "" ); + KConfigGroup srcg( &rcg, "ParentGroup" ); + QCOMPARE(srcg.readEntry( "parentgrpstring", ""), QString("somevalue") ); + + QStringList groupList = cg.groupList(); + groupList.sort(); // comes from QSet, so order is undefined + QCOMPARE(groupList, (QStringList() << "SubGroup/3" << "SubGroup1" << "SubGroup2")); + + const QStringList expectedSubgroup3Keys = (QStringList() << "sub3string"); + QCOMPARE(subcg3.keyList(), expectedSubgroup3Keys); + const QStringList expectedParentGroupKeys(QStringList() << "parentgrpstring"); + + QCOMPARE(cg.keyList(), expectedParentGroupKeys); + + QCOMPARE(QStringList(cg.entryMap().keys()), expectedParentGroupKeys); + QCOMPARE(QStringList(subcg3.entryMap().keys()), expectedSubgroup3Keys); + + // Create A group containing only other groups. We want to make sure it + // shows up in groupList of sc + KConfigGroup neg(&sc, "NoEntryGroup"); + KConfigGroup negsub1(&neg, "NEG Child1"); + negsub1.writeEntry( "entry", "somevalue" ); + KConfigGroup negsub2(&neg, "NEG Child2"); + KConfigGroup negsub3(&neg, "NEG Child3"); + KConfigGroup negsub31(&negsub3, "NEG Child3-1"); + KConfigGroup negsub4(&neg, "NEG Child4"); + KConfigGroup negsub41(&negsub4, "NEG Child4-1"); + negsub41.writeEntry( "entry", "somevalue" ); + + // A group exists if it has content + QVERIFY(negsub1.exists()); + + // But it doesn't exist if it has no content + // Ossi and David say: this is how it's supposed to work. + // However you could add a dummy entry for now, or we could add a "Persist" feature to kconfig groups + // which would make it written out, much like "immutable" already makes them persistent. + QVERIFY(!negsub2.exists()); + + // A subgroup does not qualify as content if it is also empty + QVERIFY(!negsub3.exists()); + + // A subgroup with content is ok + QVERIFY(negsub4.exists()); + + // Only subgroups with content show up in groupList() + //QEXPECT_FAIL("", "Empty subgroups do not show up in groupList()", Continue); + //QCOMPARE(neg.groupList(), QStringList() << "NEG Child1" << "NEG Child2" << "NEG Child3" << "NEG Child4"); + // This is what happens + QStringList groups = neg.groupList(); + groups.sort(); // Qt5 made the ordering unreliable, due to QHash + QCOMPARE(groups, QStringList() << "NEG Child1" << "NEG Child4"); + + // make sure groupList() isn't returning something it shouldn't + Q_FOREACH(const QString& group, sc.groupList()) { + QVERIFY(!group.isEmpty() && group != "<default>"); + QVERIFY(!group.contains(QChar(0x1d))); + QVERIFY(!group.contains("subgroup")); + QVERIFY(!group.contains("SubGroup")); + } + + QVERIFY(sc.sync()); + + // Check that the empty groups are not written out. + const QList<QByteArray> lines = readLines(); + QVERIFY(lines.contains("[NoEntryGroup][NEG Child1]\n")); + QVERIFY(!lines.contains("[NoEntryGroup][NEG Child2]\n")); + QVERIFY(!lines.contains("[NoEntryGroup][NEG Child3]\n")); + QVERIFY(!lines.contains("[NoEntryGroup][NEG Child4]\n")); // implicit group, not written out + QVERIFY(lines.contains("[NoEntryGroup][NEG Child4][NEG Child4-1]\n")); +} + +void KConfigTest::testAddConfigSources() +{ + KConfig cf("specificrc"); + + cf.addConfigSources(QStringList() << QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + "/baserc"); + cf.reparseConfiguration(); + + KConfigGroup specificgrp(&cf, "Specific Only Group"); + QCOMPARE(specificgrp.readEntry("ExistingEntry", ""), QString("DevValue")); + + KConfigGroup sharedgrp(&cf, "Shared Group"); + QCOMPARE(sharedgrp.readEntry("SomeSpecificOnlyEntry",""), QString("DevValue")); + QCOMPARE(sharedgrp.readEntry("SomeBaseOnlyEntry",""), QString("BaseValue")); + QCOMPARE(sharedgrp.readEntry("SomeSharedEntry",""), QString("DevValue")); + + KConfigGroup basegrp(&cf, "Base Only Group"); + QCOMPARE(basegrp.readEntry("ExistingEntry", ""), QString("BaseValue")); + basegrp.writeEntry("New Entry Base Only", "SomeValue"); + + KConfigGroup newgrp(&cf, "New Group"); + newgrp.writeEntry("New Entry", "SomeValue"); + + QVERIFY(cf.sync()); + + KConfig plaincfg("specificrc"); + + KConfigGroup newgrp2(&plaincfg, "New Group"); + QCOMPARE(newgrp2.readEntry("New Entry", ""), QString("SomeValue")); + + KConfigGroup basegrp2(&plaincfg, "Base Only Group"); + QCOMPARE(basegrp2.readEntry("New Entry Base Only", ""), QString("SomeValue")); +} + +void KConfigTest::testGroupCopyTo() +{ + KConfig cf1("kconfigtest"); + KConfigGroup original = cf1.group("Enum Types"); + + KConfigGroup copy = cf1.group("Enum Types Copy"); + original.copyTo(©); // copy from one group to another + QCOMPARE(copy.entryMap(), original.entryMap()); + + KConfig cf2("copy_of_kconfigtest", KConfig::SimpleConfig); + QVERIFY(!cf2.hasGroup(original.name())); + QVERIFY(!cf2.hasGroup(copy.name())); + + KConfigGroup newGroup = cf2.group(original.name()); + original.copyTo(&newGroup); // copy from one file to another + QVERIFY(cf2.hasGroup(original.name())); + QVERIFY(!cf2.hasGroup(copy.name())); // make sure we didn't copy more than we wanted + QCOMPARE(newGroup.entryMap(), original.entryMap()); +} + +void KConfigTest::testConfigCopyToSync() +{ + KConfig cf1("kconfigtest"); + // Prepare source file + KConfigGroup group(&cf1, "CopyToTest"); + group.writeEntry("Type", "Test"); + QVERIFY(cf1.sync()); + + // Copy to "destination" + const QString destination = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + "/kconfigcopytotest"; + QFile::remove(destination); + + KConfig cf2("kconfigcopytotest"); + KConfigGroup group2(&cf2, "CopyToTest"); + + group.copyTo(&group2); + + QString testVal = group2.readEntry("Type"); + QCOMPARE(testVal, QString("Test")); + // should write to disk the copied data from group + QVERIFY(cf2.sync()); + QVERIFY(QFile::exists(destination)); +} + +void KConfigTest::testConfigCopyTo() +{ + KConfig cf1("kconfigtest"); + { + // Prepare source file + KConfigGroup group(&cf1, "CopyToTest"); + group.writeEntry("Type", "Test"); + QVERIFY(cf1.sync()); + } + + { + // Copy to "destination" + const QString destination = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + "/kconfigcopytotest"; + QFile::remove(destination); + KConfig cf2; + cf1.copyTo(destination, &cf2); + KConfigGroup group2(&cf2, "CopyToTest"); + QString testVal = group2.readEntry("Type"); + QCOMPARE(testVal, QString("Test")); + QVERIFY(cf2.sync()); + QVERIFY(QFile::exists(destination)); + } + + // Check copied config file on disk + KConfig cf3("kconfigcopytotest"); + KConfigGroup group3(&cf3, "CopyToTest"); + QString testVal = group3.readEntry("Type"); + QCOMPARE(testVal, QString("Test")); +} + +void KConfigTest::testReparent() +{ + KConfig cf("kconfigtest"); + const QString name("Enum Types"); + KConfigGroup group = cf.group(name); + const QMap<QString, QString> originalMap = group.entryMap(); + KConfigGroup parent = cf.group("Parent Group"); + + QVERIFY(!parent.hasGroup(name)); + + QVERIFY(group.entryMap() == originalMap); + + group.reparent(&parent); // see if it can be made a sub-group of another group + QVERIFY(parent.hasGroup(name)); + QCOMPARE(group.entryMap(), originalMap); + + group.reparent(&cf); // see if it can make it a top-level group again +// QVERIFY(!parent.hasGroup(name)); + QCOMPARE(group.entryMap(), originalMap); +} + +static void ageTimeStamp(const QString& path, int nsec) +{ +#ifdef Q_OS_UNIX + QDateTime mtime = QFileInfo(path).lastModified().addSecs(-nsec); + struct utimbuf utbuf; + utbuf.actime = mtime.toTime_t(); + utbuf.modtime = utbuf.actime; + utime(QFile::encodeName(path), &utbuf); +#else + QTest::qSleep(nsec * 1000); +#endif +} + +void KConfigTest::testWriteOnSync() +{ + QDateTime oldStamp, newStamp; + KConfig sc("kconfigtest", KConfig::IncludeGlobals); + + // Age the timestamp of global config file a few sec, and collect it. + QString globFile = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + "/kdeglobals"; + ageTimeStamp(globFile, 2); // age 2 sec + oldStamp = QFileInfo(globFile).lastModified(); + + // Add a local entry and sync the config. + // Should not rewrite the global config file. + KConfigGroup cgLocal(&sc, "Locals"); + cgLocal.writeEntry("someLocalString", "whatever"); + QVERIFY(sc.sync()); + + // Verify that the timestamp of global config file didn't change. + newStamp = QFileInfo(globFile).lastModified(); + QCOMPARE(newStamp, oldStamp); + + // Age the timestamp of local config file a few sec, and collect it. + QString locFile = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + "/kconfigtest"; + ageTimeStamp(locFile, 2); // age 2 sec + oldStamp = QFileInfo(locFile).lastModified(); + + // Add a global entry and sync the config. + // Should not rewrite the local config file. + KConfigGroup cgGlobal(&sc, "Globals"); + cgGlobal.writeEntry("someGlobalString", "whatever", + KConfig::Persistent|KConfig::Global); + QVERIFY(sc.sync()); + + // Verify that the timestamp of local config file didn't change. + newStamp = QFileInfo(locFile).lastModified(); + QCOMPARE(newStamp, oldStamp); +} + +void KConfigTest::testFailOnReadOnlyFileSync() +{ + KConfig sc("kconfigfailonreadonlytest"); + KConfigGroup cgLocal(&sc, "Locals"); + + cgLocal.writeEntry("someLocalString", "whatever"); + QVERIFY(cgLocal.sync()); + + QFile f(QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + '/' + sc.name()); + QVERIFY(f.exists()); + QVERIFY(f.setPermissions(QFileDevice::ReadOwner)); + + cgLocal.writeEntry("someLocalString", "whatever2"); + QVERIFY(!cgLocal.sync()); + + QVERIFY(f.setPermissions(QFileDevice::ReadOwner | QFileDevice::WriteOwner)); + QVERIFY(f.remove()); +} + +void KConfigTest::testDirtyOnEqual() +{ + QDateTime oldStamp, newStamp; + KConfig sc("kconfigtest"); + + // Initialize value + KConfigGroup cgLocal(&sc, "random"); + cgLocal.writeEntry("theKey", "whatever"); + QVERIFY(sc.sync()); + + // Age the timestamp of local config file a few sec, and collect it. + QString locFile = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + "/kconfigtest"; + ageTimeStamp(locFile, 2); // age 2 sec + oldStamp = QFileInfo(locFile).lastModified(); + + // Write exactly the same again + cgLocal.writeEntry("theKey", "whatever"); + // This should be a no-op + QVERIFY(sc.sync()); + + // Verify that the timestamp of local config file didn't change. + newStamp = QFileInfo(locFile).lastModified(); + QCOMPARE(newStamp, oldStamp); +} + +void KConfigTest::testDirtyOnEqualOverdo() +{ + QByteArray val1("\0""one", 4); + QByteArray val2("\0""two", 4); + QByteArray defvalr; + + KConfig sc("kconfigtest"); + KConfigGroup cgLocal(&sc, "random"); + cgLocal.writeEntry("someKey", val1); + QCOMPARE(cgLocal.readEntry("someKey", defvalr), val1); + cgLocal.writeEntry("someKey", val2); + QCOMPARE(cgLocal.readEntry("someKey", defvalr), val2); +} + + +void KConfigTest::testCreateDir() +{ + // Test auto-creating the parent directory when needed (KConfigIniBackend::createEnclosing) + QString kdehome = QDir::home().canonicalPath() + "/.kde-unit-test"; + QString subdir = kdehome + "/newsubdir"; + QString file = subdir + "/foo.desktop"; + QFile::remove(file); + QDir().rmdir(subdir); + QVERIFY(!QDir().exists(subdir)); + KDesktopFile desktopFile(file); + desktopFile.desktopGroup().writeEntry("key", "value"); + QVERIFY(desktopFile.sync()); + QVERIFY(QFile::exists(file)); + + // Cleanup + QFile::remove(file); + QDir().rmdir(subdir); +} + +void KConfigTest::testSyncOnExit() +{ + // Often, the KGlobalPrivate global static's destructor ends up calling ~KConfig -> + // KConfig::sync ... and if that code triggers KGlobal code again then things could crash. + // So here's a test for modifying KSharedConfig::openConfig() and not syncing, the process exit will sync. + KConfigGroup grp(KSharedConfig::openConfig(), "syncOnExit"); + grp.writeEntry("key", "value"); +} + +void KConfigTest::testSharedConfig() +{ + // Can I use a KConfigGroup even after the KSharedConfigPtr goes out of scope? + KConfigGroup myConfigGroup; + { + KSharedConfigPtr config = KSharedConfig::openConfig("kconfigtest"); + myConfigGroup = KConfigGroup(config, "Hello"); + } + QCOMPARE(myConfigGroup.readEntry("stringEntry1"), QString(STRINGENTRY1)); +} + +void KConfigTest::testLocaleConfig() +{ + // Initialize the testdata + QDir dir; + QString subdir = QDir::home().canonicalPath() + "/.kde-unit-test/"; + dir.mkpath(subdir); + QString file = subdir + "/localized.test"; + QFile::remove(file); + QFile f(file); + QVERIFY(f.open(QIODevice::WriteOnly)); + QTextStream ts(&f); + ts << "[Test_Wrong]\n"; + ts << "foo[ca]=5\n"; + ts << "foostring[ca]=nice\n"; + ts << "foobool[ca]=true\n"; + ts << "[Test_Right]\n"; + ts << "foo=5\n"; + ts << "foo[ca]=5\n"; + ts << "foostring=primary\n"; + ts << "foostring[ca]=nice\n"; + ts << "foobool=primary\n"; + ts << "foobool[ca]=true\n"; + f.close(); + + // Load the testdata + QVERIFY(QFile::exists(file)); + KConfig config(file); + config.setLocale("ca"); + + // This group has only localized values. That is not supported. The values + // should be dropped on loading. + KConfigGroup cg(&config, "Test_Wrong"); + QEXPECT_FAIL("", "The localized values are not dropped", Continue); + QVERIFY(!cg.hasKey("foo")); + QEXPECT_FAIL("", "The localized values are not dropped", Continue); + QVERIFY(!cg.hasKey("foostring")); + QEXPECT_FAIL("", "The localized values are not dropped", Continue); + QVERIFY(!cg.hasKey("foobool")); + + // Now check the correct config group + KConfigGroup cg2(&config, "Test_Right"); + QCOMPARE(cg2.readEntry("foo"), QString("5")); + QCOMPARE(cg2.readEntry("foo", 3), 5); + QCOMPARE(cg2.readEntry("foostring"), QString("nice")); + QCOMPARE(cg2.readEntry("foostring", "ugly"), QString("nice")); + QCOMPARE(cg2.readEntry("foobool"), QString("true")); + QCOMPARE(cg2.readEntry("foobool", false), true); + + // Clean up after the testcase + QFile::remove(file); +} + + +void KConfigTest::testDeleteWhenLocalized() +{ + // Initialize the testdata + QDir dir; + QString subdir = QDir::home().canonicalPath() + "/.kde-unit-test/"; + dir.mkpath(subdir); + QString file = subdir + "/localized_delete.test"; + QFile::remove(file); + QFile f(file); + QVERIFY(f.open(QIODevice::WriteOnly)); + QTextStream ts(&f); + ts << "[Test4711]\n"; + ts << "foo=3\n"; + ts << "foo[ca]=5\n"; + ts << "foo[de]=7\n"; + ts << "foostring=ugly\n"; + ts << "foostring[ca]=nice\n"; + ts << "foostring[de]=schoen\n"; + ts << "foobool=false\n"; + ts << "foobool[ca]=true\n"; + ts << "foobool[de]=true\n"; + f.close(); + + // Load the testdata. We start in locale "ca". + QVERIFY(QFile::exists(file)); + KConfig config(file); + config.setLocale("ca"); + KConfigGroup cg(&config, "Test4711"); + + // Delete a value. Once with localized, once with Normal + cg.deleteEntry("foostring", KConfigBase::Persistent | KConfigBase::Localized); + cg.deleteEntry("foobool"); + QVERIFY(config.sync()); + + // The value is now gone. The others are still there. Everything correct + // here. + QVERIFY(!cg.hasKey("foostring")); + QVERIFY(!cg.hasKey("foobool")); + QVERIFY(cg.hasKey("foo")); + + // The current state is: (Just return before this comment.) + // [...] + // foobool[ca]=true + // foobool[de]=wahr + // foostring=ugly + // foostring[de]=schoen + + // Now switch the locale to "de" and repeat the checks. Results should be + // the same. But they currently are not. The localized value are + // independent of each other. All values are still there in "de". + config.setLocale("de"); + QEXPECT_FAIL("", "Currently localized values are not deleted correctly", Continue); + QVERIFY(!cg.hasKey("foostring")); + QEXPECT_FAIL("", "Currently localized values are not deleted correctly", Continue); + QVERIFY(!cg.hasKey("foobool")); + QVERIFY(cg.hasKey("foo")); + // Check where the wrong values come from. + // We get the "de" value. + QCOMPARE(cg.readEntry("foostring", "nothing"), QString("schoen")); + // We get the "de" value. + QCOMPARE(cg.readEntry("foobool", false), true); + + // Now switch the locale back "ca" and repeat the checks. Results are + // again different. + config.setLocale("ca"); + // This line worked above. But now it fails. + QEXPECT_FAIL("", "Currently localized values are not deleted correctly", Continue); + QVERIFY(!cg.hasKey("foostring")); + // This line worked above too. + QEXPECT_FAIL("", "Currently localized values are not deleted correctly", Continue); + QVERIFY(!cg.hasKey("foobool")); + QVERIFY(cg.hasKey("foo")); + // Check where the wrong values come from. + // We get the primary value because the "ca" value was deleted. + QCOMPARE(cg.readEntry("foostring", "nothing"), QString("ugly")); + // We get the "ca" value. + QCOMPARE(cg.readEntry("foobool", false), true); + + // Now test the deletion of a group. + cg.deleteGroup(); + QVERIFY(config.sync()); + + // Current state: [ca] and [de] entries left... oops. + //qDebug() << readLinesFrom(file); + + // Bug: The group still exists [because of the localized entries]... + QVERIFY(cg.exists()); + QVERIFY(!cg.hasKey("foo")); + QVERIFY(!cg.hasKey("foostring")); + QEXPECT_FAIL("", "Currently localized values are not deleted correctly", Continue); + QVERIFY(!cg.hasKey("foobool")); + + // Now switch the locale to "de" and repeat the checks. All values + // still here because only the primary values are deleted. + config.setLocale("de"); + QEXPECT_FAIL("", "Currently localized values are not deleted correctly", Continue); + QVERIFY(!cg.hasKey("foo")); + QEXPECT_FAIL("", "Currently localized values are not deleted correctly", Continue); + QVERIFY(!cg.hasKey("foostring")); + QEXPECT_FAIL("", "Currently localized values are not deleted correctly", Continue); + QVERIFY(!cg.hasKey("foobool")); + // Check where the wrong values come from. + // We get the "de" value. + QCOMPARE(cg.readEntry("foostring", "nothing"), QString("schoen")); + // We get the "de" value. + QCOMPARE(cg.readEntry("foobool", false), true); + // We get the "de" value. + QCOMPARE(cg.readEntry("foo", 0), 7); + + // Now switch the locale to "ca" and repeat the checks + // "foostring" is now really gone because both the primary value and the + // "ca" value are deleted. + config.setLocale("ca"); + QEXPECT_FAIL("", "Currently localized values are not deleted correctly", Continue); + QVERIFY(!cg.hasKey("foo")); + QVERIFY(!cg.hasKey("foostring")); + QEXPECT_FAIL("", "Currently localized values are not deleted correctly", Continue); + QVERIFY(!cg.hasKey("foobool")); + // Check where the wrong values come from. + // We get the "ca" value. + QCOMPARE(cg.readEntry("foobool", false), true); + // We get the "ca" value. + QCOMPARE(cg.readEntry("foo", 0), 5); + + // Cleanup + QFile::remove(file); +} + + +void KConfigTest::testKdeGlobals() +{ + { + KConfig glob("kdeglobals"); + KConfigGroup general(&glob, "General"); + general.writeEntry("testKG", "1"); + QVERIFY(glob.sync()); + } + + KConfig globRead("kdeglobals"); + const KConfigGroup general(&globRead, "General"); + QCOMPARE(general.readEntry("testKG"), QString("1")); + + // Check we wrote into kdeglobals + const QList<QByteArray> lines = readLines("kdeglobals"); + QVERIFY(lines.contains("[General]\n")); + QVERIFY(lines.contains("testKG=1\n")); + + // Writing using NoGlobals + { + KConfig glob("kdeglobals", KConfig::NoGlobals); + KConfigGroup general(&glob, "General"); + general.writeEntry("testKG", "2"); + QVERIFY(glob.sync()); + } + globRead.reparseConfiguration(); + QCOMPARE(general.readEntry("testKG"), QString("2")); + + // Reading using NoGlobals + { + KConfig globReadNoGlob("kdeglobals", KConfig::NoGlobals); + const KConfigGroup generalNoGlob(&globReadNoGlob, "General"); + QCOMPARE(generalNoGlob.readEntry("testKG"), QString("2")); + } + + // TODO now use kconfigtest and writeEntry(,Global) -> should go into kdeglobals +} + +void KConfigTest::testAnonymousConfig() +{ + KConfig anonConfig(QString(), KConfig::SimpleConfig); + KConfigGroup general(&anonConfig, "General"); + QCOMPARE(general.readEntry("testKG"), QString()); // no kdeglobals merging + general.writeEntry("Foo", "Bar"); + QCOMPARE(general.readEntry("Foo"), QString("Bar")); +} + +#include <QThreadPool> +#include <qtconcurrentrun.h> + +// To find multithreading bugs: valgrind --tool=helgrind --track-lockorders=no ./kconfigtest testThreads +void KConfigTest::testThreads() +{ + QThreadPool::globalInstance()->setMaxThreadCount(6); + QList<QFuture<void> > futures; + // Run in parallel some tests that work on different config files, + // otherwise unexpected things might indeed happen. + futures << QtConcurrent::run(this, &KConfigTest::testAddConfigSources); + futures << QtConcurrent::run(this, &KConfigTest::testSimple); + futures << QtConcurrent::run(this, &KConfigTest::testDefaults); + // QEXPECT_FAIL triggers race conditions, it should be fixed to use QThreadStorage... + //futures << QtConcurrent::run(this, &KConfigTest::testDeleteWhenLocalized); + //futures << QtConcurrent::run(this, &KConfigTest::testEntryMap); + Q_FOREACH(QFuture<void> f, futures) // krazy:exclude=foreach + f.waitForFinished(); +} diff --git a/tier1/kconfig/autotests/kconfigtest.h b/tier1/kconfig/autotests/kconfigtest.h new file mode 100644 index 00000000..ba929086 --- /dev/null +++ b/tier1/kconfig/autotests/kconfigtest.h @@ -0,0 +1,86 @@ +/* This file is part of the KDE libraries + Copyright (C) 1997 Matthias Kalle Dalheimer (kalle@kde.org) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ +#ifndef KCONFIGTEST_H +#define KCONFIGTEST_H + +#include <QtCore/QObject> + +class KConfigTest : public QObject +{ + Q_OBJECT + Q_ENUMS(Testing) + Q_FLAGS(Flags) + +public: + enum Testing { Ones=1, Tens=10, Hundreds=100}; + enum bits { bit0=1, bit1=2, bit2=4, bit3=8 }; + Q_DECLARE_FLAGS(Flags, bits) + +private Q_SLOTS: + void initTestCase(); + void cleanupTestCase(); + void testSimple(); + void testDefaults(); + void testLists(); + void testLocale(); + void testEncoding(); + void testPath(); + void testPersistenceOfExpandFlagForPath(); + void testComplex(); + void testEnums(); + void testEntryMap(); + void testInvalid(); + void testDeleteEntry(); + void testDelete(); + void testDeleteWhenLocalized(); + void testDefaultGroup(); + void testEmptyGroup(); + void testCascadingWithLocale(); + void testMerge(); + void testImmutable(); + void testGroupEscape(); + void testRevertAllEntries(); + void testChangeGroup(); + void testGroupCopyTo(); + void testConfigCopyTo(); + void testConfigCopyToSync(); + void testReparent(); + void testAnonymousConfig(); + + void testSubGroup(); + void testAddConfigSources(); + void testWriteOnSync(); + void testFailOnReadOnlyFileSync(); + void testDirtyOnEqual(); + void testDirtyOnEqualOverdo(); + void testCreateDir(); + void testSharedConfig(); + void testOptionOrder(); + void testLocaleConfig(); + void testDirtyAfterRevert(); + void testKdeGlobals(); + + void testThreads(); + + // should be last + void testSyncOnExit(); +}; +Q_DECLARE_OPERATORS_FOR_FLAGS(KConfigTest::Flags) + +#endif /* KCONFIGTEST_H */ diff --git a/tier1/kconfig/autotests/kdesktopfiletest.cpp b/tier1/kconfig/autotests/kdesktopfiletest.cpp new file mode 100644 index 00000000..d77e3a50 --- /dev/null +++ b/tier1/kconfig/autotests/kdesktopfiletest.cpp @@ -0,0 +1,138 @@ +/* + * Copyright (C) 2006 David Faure <faure@kde.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License version 2 as published by the Free Software Foundation; + * + * 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#include "kdesktopfiletest.h" +#include <kconfiggroup.h> +#include <qtemporaryfile.h> + +#include "kdesktopfile.h" + +#include <QtTest> + +QTEST_MAIN( KDesktopFileTest ) + +void KDesktopFileTest::testRead() +{ + QTemporaryFile file("testReadXXXXXX.desktop"); + QVERIFY( file.open() ); + const QString fileName = file.fileName(); + QTextStream ts( &file ); + ts << + "[Desktop Entry]\n" + "Type=Application\n" + "Name=My Application\n" + "Icon=foo\n" + "\n"; + file.close(); + QVERIFY(QFile::exists(fileName)); + QVERIFY(KDesktopFile::isDesktopFile(fileName)); + KDesktopFile df(fileName); + QCOMPARE(df.readType(), QString::fromLatin1("Application")); + QVERIFY(df.hasApplicationType()); + QCOMPARE(df.readName(), QString::fromLatin1("My Application")); + QCOMPARE(df.readIcon(), QString::fromLatin1("foo")); + QVERIFY(!df.hasLinkType()); + QCOMPARE(df.fileName(), QFileInfo(fileName).canonicalFilePath()); +} + +void KDesktopFileTest::testSuccessfulTryExec() +{ + QTemporaryFile file; + QVERIFY( file.open() ); + const QString fileName = file.fileName(); + QTextStream ts( &file ); + ts << + "[Desktop Entry]\n" + "TryExec=whoami\n" + "\n"; + file.close(); + QVERIFY(QFile::exists(fileName)); + KDesktopFile df(fileName); + QCOMPARE(df.tryExec(), true); +} + +void KDesktopFileTest::testUnsuccessfulTryExec() +{ + QTemporaryFile file; + QVERIFY( file.open() ); + const QString fileName = file.fileName(); + QTextStream ts( &file ); + ts << + "[Desktop Entry]\n" + "TryExec=/does/not/exist\n" + "\n"; + file.close(); + QVERIFY(QFile::exists(fileName)); + KDesktopFile df(fileName); + QCOMPARE(df.tryExec(), false); +} + +void KDesktopFileTest::testActionGroup() +{ + QTemporaryFile file; + QVERIFY( file.open() ); + const QString fileName = file.fileName(); + QTextStream ts( &file ); + ts << + "[Desktop Entry]\n" + "Actions=encrypt;\n" + "[Desktop Action encrypt]\n" + "Name=Encrypt file\n" + "\n"; + file.close(); + QVERIFY(QFile::exists(fileName)); + KDesktopFile df(fileName); + QCOMPARE(df.readType(), QString()); + QCOMPARE(df.fileName(), fileName); + QCOMPARE(df.readActions(), QStringList() << "encrypt"); + QCOMPARE(df.hasActionGroup("encrypt"), true); + QCOMPARE(df.hasActionGroup("doesnotexist"), false); + KConfigGroup cg = df.actionGroup("encrypt"); + QVERIFY(cg.hasKey("Name")); + QCOMPARE(cg.readEntry("Name"), QString("Encrypt file")); +} + +void KDesktopFileTest::testIsAuthorizedDesktopFile() +{ + QTemporaryFile file("testAuthXXXXXX.desktop"); + QVERIFY( file.open() ); + const QString fileName = file.fileName(); + QTextStream ts( &file ); + ts << + "[Desktop Entry]\n" + "Type=Application\n" + "Name=My Application\n" + "Exec=kfoo\n" + "\n"; + file.close(); + QVERIFY(QFile::exists(fileName)); + QVERIFY(!KDesktopFile::isAuthorizedDesktopFile(fileName)); + + const QString installedFile = QStandardPaths::locate(QStandardPaths::GenericDataLocation, QLatin1String("/kde5/services/") + "http_cache_cleaner.desktop"); + if (!installedFile.isEmpty()) { + QVERIFY(KDesktopFile::isAuthorizedDesktopFile(installedFile)); + } else { + qWarning("Skipping test for http_cache_cleaner.desktop, not found. kio not installed?"); + } + + const QString autostartFile = QStandardPaths::locate(QStandardPaths::GenericConfigLocation, QLatin1String("autostart/") + "plasma-desktop.desktop"); + if (!autostartFile.isEmpty()) { + QVERIFY(KDesktopFile::isAuthorizedDesktopFile(autostartFile)); + } else { + qWarning("Skipping test for plasma-desktop.desktop, not found. kde-workspace not installed?"); + } +} diff --git a/tier1/kconfig/autotests/kdesktopfiletest.h b/tier1/kconfig/autotests/kdesktopfiletest.h new file mode 100644 index 00000000..d57351fd --- /dev/null +++ b/tier1/kconfig/autotests/kdesktopfiletest.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2006 David Faure <faure@kde.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License version 2 as published by the Free Software Foundation; + * + * 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef KDESKTOPFILETEST_H +#define KDESKTOPFILETEST_H + +#include <QtCore/QObject> + +class KDesktopFileTest : public QObject +{ + Q_OBJECT +private Q_SLOTS: + void testRead(); + void testUnsuccessfulTryExec(); + void testSuccessfulTryExec(); + void testActionGroup(); + void testIsAuthorizedDesktopFile(); + +}; + +#endif /* KDESKTOPFILETEST_H */ diff --git a/tier1/kconfig/autotests/kentrymaptest.cpp b/tier1/kconfig/autotests/kentrymaptest.cpp new file mode 100644 index 00000000..9e926d65 --- /dev/null +++ b/tier1/kconfig/autotests/kentrymaptest.cpp @@ -0,0 +1,202 @@ +/* This file is part of the KDE libraries + Copyright (C) 2007 Thomas Braxton (kde.braxton@gmail.com) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "kentrymaptest.h" + +#include <QtTest> +#include "kconfigdata.h" + + +const QByteArray group1("A Group"); +const QByteArray key1("A Key"); +const QByteArray key2("Another Key"); +const QByteArray value1("A value"); +const QByteArray value2("A different value"); + +QTEST_MAIN( KEntryMapTest ) + +void KEntryMapTest::testKeyOrder() +{ + const KEntryKey groupMarker(group1); + const KEntryKey entry(group1, key1); + const KEntryKey localized(group1, key1, true, false); + const KEntryKey localizedDefault(group1, key1, true, true); + const KEntryKey defaultEntry(group1, key1, false, true); + + // group marker should come before all entries + QVERIFY(groupMarker < entry); + QVERIFY(groupMarker < defaultEntry); + QVERIFY(groupMarker < localized); + QVERIFY(groupMarker < localizedDefault); + + // localized should come before entry + QVERIFY(localized < entry); + + // localized-default should come after localized entry + QVERIFY(localized < localizedDefault); + + // localized-default should come before non-localized entry + QVERIFY(localizedDefault < entry); + + // default should come after entry + QVERIFY(entry < defaultEntry); +} + +void KEntryMapTest::testSimple() +{ + KEntryMap map; + + map.setEntry(group1, key1, value1, EntryOptions()); + QCOMPARE(map.size(), 2); // the group marker & 1 key + map.setEntry(group1, key2, value2, EntryOptions()); + QCOMPARE(map.size(), 3); // the group marker & 2 keys + + QVERIFY(map.findEntry(group1) != map.end()); + QVERIFY(map.findEntry(group1.toLower()) == map.end()); + + QVERIFY(map.findEntry(group1, key1) != map.end()); + QVERIFY(map.findEntry(group1, key1.toLower()) == map.end()); + QVERIFY(map.findEntry(group1, key2) != map.end()); + QVERIFY(map.findEntry(group1, key2.toUpper()) == map.end()); + + QByteArray found = map.findEntry(group1, key1)->mValue; + QVERIFY(found == value1); + QVERIFY(found != value2); + + found = map.findEntry(group1, key2)->mValue; + QVERIFY(found != value1); + QVERIFY(found == value2); +} + +void KEntryMapTest::testDirty() +{ + KEntryMap map; + bool ret = map.setEntry(group1, key1, value1, EntryDefault); + QCOMPARE(ret, true); + ret = map.setEntry(group1, key1, value1, EntryDefault); + QCOMPARE(ret, false); + ret = map.setEntry(group1, key2, value2, EntryOptions()); + QCOMPARE(ret, true); + ret = map.setEntry(group1, key2, value2, EntryOptions()); + QCOMPARE(ret, false); +} + +void KEntryMapTest::testDefault() +{ + KEntryMap map; + + map.setEntry(group1, key1, value1, EntryDefault); + QCOMPARE(map.size(), 3); // group marker, default, entry + map.setEntry(group1, key2, value2, EntryOptions()); + QCOMPARE(map.size(), 4); // group marker, default1, entry1, entry2 + + const KEntryMap::ConstIterator defaultEntry(map.findEntry(group1, key1, SearchDefaults)); + const KEntryMap::ConstIterator entry1(map.findEntry(group1, key1)); + const KEntryMap::ConstIterator entry2(map.findEntry(group1, key2)); + + // default set for entry1 + QVERIFY(defaultEntry != map.constEnd()); + QCOMPARE(defaultEntry->mValue, entry1->mValue); + + // no default set for entry2 + QVERIFY(map.findEntry(group1, key2, SearchDefaults) == map.end()); + + // change from default + map.setEntry(group1, key1, value2, EntryOptions()); + QVERIFY(defaultEntry->mValue != entry1->mValue); + QVERIFY(entry1 != entry2); + QCOMPARE(entry1->mValue, entry2->mValue); + + // revert entry1 + map.revertEntry(group1, key1); + QCOMPARE(defaultEntry->mValue, entry1->mValue); + + // revert entry2, no default --> should be marked as deleted + map.revertEntry(group1, key2); + QCOMPARE(entry2->mValue, QByteArray()); + QVERIFY(entry2->bDirty); + QVERIFY(entry2->bReverted); +} + +void KEntryMapTest::testDelete() +{ + KEntryMap map; + + map.setEntry(group1, key1, value1, EntryDefault); + map.setEntry(group1, key2, value2, EntryDefault); + QCOMPARE(map.size(), 5); + + map.setEntry(group1, key2, QByteArray(), EntryDeleted|EntryDirty); + QCOMPARE(map.size(), 5); // entry should still be in map, so it can override merged entries later + QCOMPARE(map.findEntry(group1, key2)->mValue, QByteArray()); +} + +void KEntryMapTest::testGlobal() +{ + KEntryMap map; + + map.setEntry(group1, key1, value1, EntryGlobal); + QCOMPARE(map.findEntry(group1, key1)->bGlobal, true); + + // this should create a new key that is not "global" + map.setEntry(group1, key1, value2, EntryOptions()); + QVERIFY(!map.findEntry(group1, key1)->bGlobal); +} + +void KEntryMapTest::testImmutable() +{ + KEntryMap map; + + map.setEntry(group1, key1, value1, EntryImmutable); + QCOMPARE(map.findEntry(group1, key1)->bImmutable, true); // verify the immutable bit was set + + map.setEntry(group1, key1, value2, EntryOptions()); + QCOMPARE(map.findEntry(group1, key1)->mValue, value1); // verify the value didn't change + + map.clear(); + + map.setEntry(group1, QByteArray(), QByteArray(), EntryImmutable); + QCOMPARE(map.findEntry(group1)->bImmutable, true); // verify the group is immutable + + map.setEntry(group1, key1, value1, EntryOptions()); // should be ignored since the group is immutable + QVERIFY(map.findEntry(group1, key1) == map.end()); +} + +void KEntryMapTest::testLocale() +{ + const QByteArray translatedDefault("hola"); + const QByteArray translated("bonjour"); + const QByteArray untranslated("hello"); + KEntryMap map; + + map.setEntry(group1, key1, untranslated, EntryDefault); + QCOMPARE(map.findEntry(group1, key1)->mValue, untranslated); + QCOMPARE(map.findEntry(group1, key1, SearchLocalized)->mValue, untranslated); // no localized value yet + + map.setEntry(group1, key1, translated, EntryLocalized); + + QCOMPARE(map.findEntry(group1, key1, SearchLocalized)->mValue, translated); // has localized value now + QVERIFY(map.findEntry(group1, key1, SearchLocalized)->mValue != map.findEntry(group1, key1)->mValue); + QCOMPARE(map.findEntry(group1, key1, SearchDefaults|SearchLocalized)->mValue, untranslated); // default should still be untranslated + + map.setEntry(group1, key1, translatedDefault, EntryDefault|EntryLocalized); + QCOMPARE(map.findEntry(group1, key1, SearchLocalized)->mValue, translatedDefault); + map.setEntry(group1, key1, translated, EntryLocalized); // set the translated entry to a different locale + QCOMPARE(map.findEntry(group1, key1, SearchLocalized)->mValue, translated); +} diff --git a/tier1/kconfig/autotests/kentrymaptest.h b/tier1/kconfig/autotests/kentrymaptest.h new file mode 100644 index 00000000..2855b5c4 --- /dev/null +++ b/tier1/kconfig/autotests/kentrymaptest.h @@ -0,0 +1,57 @@ +/* This file is part of the KDE libraries + Copyright (C) 2007 Thomas Braxton (kde.braxton@gmail.com) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef KENTRYMAPTEST_H +#define KENTRYMAPTEST_H + +#include <QtCore/QObject> +#include "kconfigdata.h" + +class KEntryMapTest : public QObject +{ + Q_OBJECT + +public: + typedef KEntryMap::EntryOptions EntryOptions; + typedef KEntryMap::SearchFlags SearchFlags; + + typedef KEntryMap::SearchFlag SearchFlag; + static const SearchFlag SearchLocalized=KEntryMap::SearchLocalized; + static const SearchFlag SearchDefaults=KEntryMap::SearchDefaults; + + typedef KEntryMap::EntryOption EntryOption; + static const EntryOption EntryDirty=KEntryMap::EntryDirty; + static const EntryOption EntryGlobal=KEntryMap::EntryGlobal; + static const EntryOption EntryImmutable=KEntryMap::EntryImmutable; + static const EntryOption EntryDeleted=KEntryMap::EntryDeleted; + static const EntryOption EntryExpansion=KEntryMap::EntryExpansion; + static const EntryOption EntryDefault=KEntryMap::EntryDefault; + static const EntryOption EntryLocalized=KEntryMap::EntryLocalized; +private Q_SLOTS: + void testKeyOrder(); + void testSimple(); + void testDirty(); + void testDefault(); + void testDelete(); + void testGlobal(); + void testImmutable(); + void testLocale(); +}; + +#endif // KENTRYMAPTEST_H diff --git a/tier1/kconfig/autotests/ksharedconfigtest.cpp b/tier1/kconfig/autotests/ksharedconfigtest.cpp new file mode 100644 index 00000000..165322a3 --- /dev/null +++ b/tier1/kconfig/autotests/ksharedconfigtest.cpp @@ -0,0 +1,83 @@ +/* + This file is part of the KDE libraries + Copyright (c) 2012 David Faure <faure@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include <QtTest> +#include <ksharedconfig.h> +#include <kconfiggroup.h> + +class KSharedConfigTest : public QObject +{ + Q_OBJECT +private Q_SLOTS: + void initTestCase(); + void testUnicity(); + void testReadWrite(); + void testReadWriteSync(); +private: + QString m_path; +}; + +void KSharedConfigTest::initTestCase() +{ + QStandardPaths::enableTestMode(true); + + m_path = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + "/ksharedconfigtestrc"; + QFile::remove(m_path); +} + +void KSharedConfigTest::testUnicity() +{ + KSharedConfig::Ptr cfg1 = KSharedConfig::openConfig(); + KSharedConfig::Ptr cfg2 = KSharedConfig::openConfig(); + QCOMPARE(cfg1.data(), cfg2.data()); +} + +void KSharedConfigTest::testReadWrite() +{ + const int value = 1; + { + KConfigGroup cg(KSharedConfig::openConfig(), "KSharedConfigTest"); + cg.writeEntry("NumKey", value); + } + { + KConfigGroup cg(KSharedConfig::openConfig(), "KSharedConfigTest"); + QCOMPARE(cg.readEntry("NumKey", 0), 1); + } +} + +void KSharedConfigTest::testReadWriteSync() +{ + const int value = 1; + { + KConfigGroup cg(KSharedConfig::openConfig(), "KSharedConfigTest"); + cg.writeEntry("NumKey", value); + } + QVERIFY(!QFile::exists(m_path)); + QVERIFY(KSharedConfig::openConfig()->sync()); + QVERIFY(QFile::exists(m_path)); + { + KConfigGroup cg(KSharedConfig::openConfig(), "KSharedConfigTest"); + QCOMPARE(cg.readEntry("NumKey", 0), 1); + } +} + +QTEST_MAIN(KSharedConfigTest) + +#include "ksharedconfigtest.moc" diff --git a/tier1/kconfig/autotests/kstandardshortcuttest.cpp b/tier1/kconfig/autotests/kstandardshortcuttest.cpp new file mode 100644 index 00000000..847cd074 --- /dev/null +++ b/tier1/kconfig/autotests/kstandardshortcuttest.cpp @@ -0,0 +1,59 @@ +/* This file is part of the KDE libraries + Copyright (c) 2005 David Faure <faure@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include <QtTest/QtTest> +#include "kstandardshortcuttest.h" + +QTEST_MAIN( KStandardShortcutTest) // GUI needed by KAccel + +#include <kstandardshortcut.h> + +void KStandardShortcutTest::testShortcutDefault() +{ + QCOMPARE( QKeySequence::listToString(KStandardShortcut::hardcodedDefaultShortcut( KStandardShortcut::FullScreen )), QLatin1String( "Ctrl+Shift+F" ) ); + QCOMPARE( QKeySequence::listToString(KStandardShortcut::hardcodedDefaultShortcut( KStandardShortcut::BeginningOfLine )), QLatin1String( "Home" ) ); + QCOMPARE( QKeySequence::listToString(KStandardShortcut::hardcodedDefaultShortcut( KStandardShortcut::EndOfLine )), QLatin1String( "End" ) ); + QCOMPARE( QKeySequence::listToString(KStandardShortcut::hardcodedDefaultShortcut( KStandardShortcut::Home )), QLatin1String( "Alt+Home; Home Page" ) ); +} + +void KStandardShortcutTest::testName() +{ + QCOMPARE( KStandardShortcut::name( KStandardShortcut::BeginningOfLine ), QLatin1String( "BeginningOfLine" ) ); + QCOMPARE( KStandardShortcut::name( KStandardShortcut::EndOfLine ), QLatin1String( "EndOfLine" ) ); + QCOMPARE( KStandardShortcut::name( KStandardShortcut::Home ), QLatin1String( "Home" ) ); +} + +void KStandardShortcutTest::testLabel() +{ + // Tests run in English, right? + QCOMPARE( KStandardShortcut::label( KStandardShortcut::FindNext ), QLatin1String( "Find Next" ) ); + QCOMPARE( KStandardShortcut::label( KStandardShortcut::Home ), QLatin1String( "Home" ) ); +} + +void KStandardShortcutTest::testShortcut() +{ + QCOMPARE( QKeySequence::listToString(KStandardShortcut::shortcut( KStandardShortcut::ZoomIn )), QKeySequence::listToString(KStandardShortcut::zoomIn()) ); +} + +void KStandardShortcutTest::testFindStdAccel() +{ + QCOMPARE( KStandardShortcut::find( QString( "Ctrl+F" ) ), KStandardShortcut::Find ); + QCOMPARE( KStandardShortcut::find( QString( "Ctrl+Shift+Alt+G" ) ), KStandardShortcut::AccelNone ); +} + diff --git a/tier1/kconfig/autotests/kstandardshortcuttest.h b/tier1/kconfig/autotests/kstandardshortcuttest.h new file mode 100644 index 00000000..91be854b --- /dev/null +++ b/tier1/kconfig/autotests/kstandardshortcuttest.h @@ -0,0 +1,38 @@ +/* This file is part of the KDE libraries + Copyright (c) 2005 David Faure <faure@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef KSTDACCELTEST_H +#define KSTDACCELTEST_H + +#include <QtCore/QObject> + +class KStandardShortcutTest : public QObject +{ + Q_OBJECT +private Q_SLOTS: + // KStandardShortcut tests + void testShortcutDefault(); + void testName(); + void testLabel(); + void testShortcut(); + void testFindStdAccel(); +}; + + +#endif diff --git a/tier1/kconfig/autotests/test_kconf_update.cpp b/tier1/kconfig/autotests/test_kconf_update.cpp new file mode 100644 index 00000000..8fae1c74 --- /dev/null +++ b/tier1/kconfig/autotests/test_kconf_update.cpp @@ -0,0 +1,553 @@ +/* This file is part of the KDE libraries + Copyright 2010 Canonical Ltd + Author: Aurélien Gâteau <aurelien.gateau@canonical.com> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License (LGPL) as published by the Free Software Foundation; + either version 2 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ +#include "test_kconf_update.h" + +// Qt +#include <QFile> +#include <QDir> +#include <QSharedPointer> +#include <QtCore/QProcess> +#include <qtemporaryfile.h> +#include <qstandardpaths.h> +#include "config-kconf.h" + +#include <qtest.h> + +// QT5 TODO QTEST_GUILESS_MAIN(TestKConfUpdate) +QTEST_MAIN(TestKConfUpdate) + +static void writeFile(const QString &path, const QString &content) +{ + QFile file(path); + bool ok = file.open(QIODevice::WriteOnly); + Q_UNUSED(ok) // silence warnings + Q_ASSERT(ok); + file.write(content.toUtf8()); +} + +static QString readFile(const QString &path) +{ + QFile file(path); + bool ok = file.open(QIODevice::ReadOnly); + Q_UNUSED(ok) // silence warnings + Q_ASSERT(ok); + return QString::fromUtf8(file.readAll()); +} + +static QTemporaryFile* writeUpdFile(const QString &content) +{ + QTemporaryFile* file = new QTemporaryFile(QDir::tempPath() + QLatin1String("/test_kconf_update_XXXXXX.upd")); + bool ok = file->open(); + Q_UNUSED(ok) // silence warnings + Q_ASSERT(ok); + file->write(content.toUtf8()); + file->flush(); + return file; +} + +static void runKConfUpdate(const QString &updPath) +{ + QString exePath = KCONF_UPDATE_BINARY_DIR "/kconf_update"; + QVERIFY(QFile::exists(exePath)); + QProcess::execute(exePath, QStringList() << "--debug" << updPath); +} + +void TestKConfUpdate::test_data() +{ + QTest::addColumn<QString>("updContent"); + QTest::addColumn<QString>("oldConfName"); + QTest::addColumn<QString>("oldConfContent"); + QTest::addColumn<QString>("newConfName"); + QTest::addColumn<QString>("expectedNewConfContent"); + QTest::addColumn<QString>("expectedOldConfContent"); + + QTest::newRow("moveKeysSameFile") + << + "File=testrc\n" + "Group=group\n" + "Key=old,new\n" + "Options=overwrite\n" + << + "testrc" + << + "[group]\n" + "old=value\n" + << + "testrc" + << + "[$Version]\n" + "update_info=%1\n" + "\n" + "[group]\n" + "new=value\n" + << + "" + ; + QTest::newRow("moveKeysOtherFile") + << + "File=oldrc,newrc\n" + "Group=group1,group2\n" + "Key=old,new\n" + "Options=overwrite\n" + << + "oldrc" + << + "[group1]\n" + "old=value\n" + "[stay]\n" + "foo=bar\n" + << + "newrc" + << + "[$Version]\n" + "update_info=%1\n" + "\n" + "[group2]\n" + "new=value\n" + << + "[$Version]\n" + "update_info=%1\n" + "\n" + "[stay]\n" + "foo=bar\n" + ; + QTest::newRow("allKeys") + << + "File=testrc\n" + "Group=group1,group2\n" + "AllKeys\n" + << + "testrc" + << + "[group1]\n" + "key1=value1\n" + "key2=value2\n" + "\n" + "[stay]\n" + "foo=bar\n" + << + "testrc" + << + "[$Version]\n" + "update_info=%1\n" + "\n" + "[group2]\n" + "key1=value1\n" + "key2=value2\n" + "\n" + "[stay]\n" + "foo=bar\n" + << + "" + ; + QTest::newRow("allKeysSubGroup") + << + "File=testrc\n" + "Group=[group][sub1],[group][sub2]\n" + "AllKeys\n" + << + "testrc" + << + "[group][sub1]\n" + "key1=value1\n" + "key2=value2\n" + "\n" + "[group][sub1][subsub]\n" + "key3=value3\n" + "key4=value4\n" + "\n" + "[stay]\n" + "foo=bar\n" + << + "testrc" + << + "[$Version]\n" + "update_info=%1\n" + "\n" + "[group][sub2]\n" + "key1=value1\n" + "key2=value2\n" + "\n" + "[group][sub2][subsub]\n" + "key3=value3\n" + "key4=value4\n" + "\n" + "[stay]\n" + "foo=bar\n" + << + "" + ; + QTest::newRow("removeGroup") + << + "File=testrc\n" + "RemoveGroup=remove\n" + << + "testrc" + << + "[keep]\n" + "key=value\n" + "" + "[remove]\n" + "key=value\n" + << + "testrc" + << + "[$Version]\n" + "update_info=%1\n" + "\n" + "[keep]\n" + "key=value\n" + << + "" + ; + QTest::newRow("moveKeysSameFileDontExist") + << + "File=testrc\n" + "Group=group,group2\n" + "Key=key1\n" + "Key=key2\n" + << + "testrc" + << + "[group]\n" + "key1=value1\n" + "key3=value3\n" + << + "testrc" + << + "[$Version]\n" + "update_info=%1\n" + "\n" + "[group]\n" + "key3=value3\n" + "\n" + "[group2]\n" + "key1=value1\n" + << + "" + ; +} + +void TestKConfUpdate::test() +{ + QFETCH(QString, updContent); + QFETCH(QString, oldConfName); + QFETCH(QString, oldConfContent); + QFETCH(QString, newConfName); + QFETCH(QString, expectedNewConfContent); + QFETCH(QString, expectedOldConfContent); + + // Prepend the Id= field to the upd content + updContent = QString("Id=%1\n").arg(QTest::currentDataTag()) + updContent; + + QString oldConfPath = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + QLatin1Char('/') + oldConfName; + QString newConfPath = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + QLatin1Char('/') + newConfName; + + QFile::remove(oldConfPath); + QFile::remove(newConfPath); + + writeFile(oldConfPath, oldConfContent); + QSharedPointer<QTemporaryFile> updFile(writeUpdFile(updContent)); + runKConfUpdate(updFile->fileName()); + + QString updateInfo = QString("%1:%2") + .arg(updFile->fileName().section('/', -1)) + .arg(QTest::currentDataTag()); + + QString newConfContentAfter = readFile(newConfPath); + expectedNewConfContent = expectedNewConfContent.arg(updateInfo); + QCOMPARE(newConfContentAfter, expectedNewConfContent); + + if (oldConfName != newConfName) { + QString oldConfContentAfter = readFile(oldConfPath); + expectedOldConfContent = expectedOldConfContent.arg(updateInfo); + QCOMPARE(oldConfContentAfter, expectedOldConfContent); + } +} + +void TestKConfUpdate::testScript_data() +{ + QTest::addColumn<QString>("updContent"); + QTest::addColumn<QString>("updScript"); + QTest::addColumn<QString>("oldConfContent"); + QTest::addColumn<QString>("expectedNewConfContent"); + + QTest::newRow("delete-key") + << + "File=testrc\n" + "Group=group\n" + "Script=test.sh,sh\n" + << + "echo '# DELETE deprecated'\n" + << + "[group]\n" + "deprecated=foo\n" + "valid=bar\n" + << + "[$Version]\n" + "update_info=%1\n" + "\n" + "[group]\n" + "valid=bar\n" + ; + + QTest::newRow("delete-key2") + << + "File=testrc\n" + "Script=test.sh,sh\n" + << + "echo '# DELETE [group]deprecated'\n" + "echo '# DELETE [group][sub]deprecated2'\n" + << + "[group]\n" + "deprecated=foo\n" + "valid=bar\n" + "\n" + "[group][sub]\n" + "deprecated2=foo\n" + "valid2=bar\n" + << + "[$Version]\n" + "update_info=%1\n" + "\n" + "[group]\n" + "valid=bar\n" + "\n" + "[group][sub]\n" + "valid2=bar\n" + ; + + QTest::newRow("delete-group") + << + "File=testrc\n" + "Script=test.sh,sh\n" + << + "echo '# DELETEGROUP [group1]'\n" + "echo '# DELETEGROUP [group2][sub]'\n" + << + "[group1]\n" + "key=value\n" + "\n" + "[group2]\n" + "valid=bar\n" + "\n" + "[group2][sub]\n" + "key=value\n" + << + "[$Version]\n" + "update_info=%1\n" + "\n" + "[group2]\n" + "valid=bar\n" + ; + + QTest::newRow("delete-group2") + << + "File=testrc\n" + "Group=group\n" + "Script=test.sh,sh\n" + << + "echo '# DELETEGROUP'\n" + << + "[group]\n" + "key=value\n" + "\n" + "[group2]\n" + "valid=bar\n" + << + "[$Version]\n" + "update_info=%1\n" + "\n" + "[group2]\n" + "valid=bar\n" + ; + + QTest::newRow("new-key") + << + "File=testrc\n" + "Script=test.sh,sh\n" + << + "echo '[group]'\n" + "echo 'new=value'\n" + << + "[group]\n" + "valid=bar\n" + << + "[$Version]\n" + "update_info=%1\n" + "\n" + "[group]\n" + "new=value\n" + "valid=bar\n" + ; + + QTest::newRow("modify-key-no-overwrite") + << + "File=testrc\n" + "Script=test.sh,sh\n" + << + "echo '[group]'\n" + "echo 'existing=new'\n" + << + "[group]\n" + "existing=old\n" + << + "[$Version]\n" + "update_info=%1\n" + "\n" + "[group]\n" + "existing=old\n" + ; + + QTest::newRow("modify-key-overwrite") + << + "File=testrc\n" + "Options=overwrite\n" + "Script=test.sh,sh\n" + << + "echo '[group]'\n" + "echo 'existing=new'\n" + << + "[group]\n" + "existing=old\n" + << + "[$Version]\n" + "update_info=%1\n" + "\n" + "[group]\n" + "existing=new\n" + ; + + QTest::newRow("new-key-in-subgroup") + << + "File=testrc\n" + "Script=test.sh,sh\n" + << + "echo '[group][sub]'\n" + "echo 'new=value2'\n" + << + "[group][sub]\n" + "existing=foo\n" + << + "[$Version]\n" + "update_info=%1\n" + "\n" + "[group][sub]\n" + "existing=foo\n" + "new=value2\n" + ; + + QTest::newRow("new-key-in-subgroup2") + << + "File=testrc\n" + "Script=test.sh,sh\n" + << + "echo '[group][sub]'\n" + "echo 'new=value3'\n" + << + "[group][sub]\n" + "existing=foo\n" + << + "[$Version]\n" + "update_info=%1\n" + "\n" + "[group][sub]\n" + "existing=foo\n" + "new=value3\n" + ; + + QTest::newRow("filter") + << + "File=testrc\n" + "Script=test.sh,sh\n" + << + "echo '# DELETE [group]changed'\n" + "sed s/value/VALUE/\n" + << + "[group]\n" + "changed=value\n" + "unchanged=value\n" + << + "[$Version]\n" + "update_info=%1\n" + "\n" + "[group]\n" + "changed=VALUE\n" + "unchanged=value\n" + ; + + QTest::newRow("filter-subgroup") + << + "File=testrc\n" + "Script=test.sh,sh\n" + << + "echo '# DELETE [group][sub]changed'\n" + "sed s/value/VALUE/\n" + << + "[group]\n" + "unchanged=value\n" + "\n" + "[group][sub]\n" + "changed=value\n" + "unchanged=value\n" + << + "[$Version]\n" + "update_info=%1\n" + "\n" + "[group]\n" + "unchanged=value\n" + "\n" + "[group][sub]\n" + "changed=VALUE\n" + "unchanged=value\n" + ; +} + +void TestKConfUpdate::testScript() +{ + QFETCH(QString, updContent); + QFETCH(QString, updScript); + QFETCH(QString, oldConfContent); + QFETCH(QString, expectedNewConfContent); + + // Prepend the Id= field to the upd content + updContent = QString("Id=%1\n").arg(QTest::currentDataTag()) + updContent; + + QSharedPointer<QTemporaryFile> updFile(writeUpdFile(updContent)); + + const QString scriptDir = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + "/kconf_update"; + QVERIFY(QDir().mkpath(scriptDir)); + QString scriptPath = scriptDir + "/test.sh"; + writeFile(scriptPath, updScript); + + QString confPath = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + QLatin1Char('/') + "testrc"; + writeFile(confPath, oldConfContent); + + runKConfUpdate(updFile->fileName()); + + QString updateInfo = QString("%1:%2") + .arg(updFile->fileName().section('/', -1)) + .arg(QTest::currentDataTag()); + QString newConfContent = readFile(confPath); + expectedNewConfContent = expectedNewConfContent.arg(updateInfo); + QCOMPARE(newConfContent, expectedNewConfContent); +} + diff --git a/tier1/kconfig/autotests/test_kconf_update.h b/tier1/kconfig/autotests/test_kconf_update.h new file mode 100644 index 00000000..1b3151f1 --- /dev/null +++ b/tier1/kconfig/autotests/test_kconf_update.h @@ -0,0 +1,36 @@ +/* This file is part of the KDE libraries + Copyright 2010 Canonical Ltd + Author: Aurélien Gâteau <aurelien.gateau@canonical.com> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License (LGPL) as published by the Free Software Foundation; + either version 2 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ +#ifndef TEST_KCONF_UPDATE_H +#define TEST_KCONF_UPDATE_H + +#include <QObject> + +class TestKConfUpdate : public QObject +{ + Q_OBJECT +private Q_SLOTS: + void test_data(); + void test(); + void testScript_data(); + void testScript(); +}; + +#endif /* TEST_KCONF_UPDATE_H */ diff --git a/tier1/kconfig/autotests/test_kconfigutils.cpp b/tier1/kconfig/autotests/test_kconfigutils.cpp new file mode 100644 index 00000000..176d771f --- /dev/null +++ b/tier1/kconfig/autotests/test_kconfigutils.cpp @@ -0,0 +1,149 @@ +/* This file is part of the KDE libraries + Copyright 2010 Canonical Ltd + Author: Aurélien Gâteau <aurelien.gateau@canonical.com> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License (LGPL) as published by the Free Software Foundation; + either version 2 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ +#include "test_kconfigutils.h" + +#include <qdebug.h> +#include <qtest.h> + +// Local +#include "kconfigutils.h" + +// QT5 TODO QTEST_GUILESS_MAIN(TestKConfigUtils) +QTEST_MAIN(TestKConfigUtils) + +void TestKConfigUtils::testParseGroupString_data() +{ + QTest::addColumn<QString>("input"); + QTest::addColumn<QStringList>("expected"); + QTest::addColumn<bool>("expectedOk"); + + QTest::newRow("simple-group") + << " group " + << (QStringList() << "group") + << true + ; + + QTest::newRow("sub-group") + << "[group][sub]" + << (QStringList() << "group" << "sub") + << true + ; + + QTest::newRow("crazy-sub-group") + << "[a\\ttab\\x5d[and some hex esc\\x61pe]" + << (QStringList() << "a\ttab" << "and some hex escape") + << true + ; + + QTest::newRow("missing-closing-brace") + << "[group][sub" + << QStringList() + << false + ; +} + +void TestKConfigUtils::testParseGroupString() +{ + QFETCH(QString, input); + QFETCH(QStringList, expected); + QFETCH(bool, expectedOk); + + bool ok; + QString error; + QStringList output = KConfigUtils::parseGroupString(input, &ok, &error); + QCOMPARE(output, expected); + QCOMPARE(ok, expectedOk); + if (ok) { + QVERIFY(error.isEmpty()); + } else { + QVERIFY(!error.isEmpty()); + qDebug() << error; + } +} + +void TestKConfigUtils::testUnescapeString_data() +{ + QTest::addColumn<QString>("input"); + QTest::addColumn<QString>("expected"); + QTest::addColumn<bool>("expectedOk"); + + QTest::newRow("plain") + << "Some text" + << "Some text" + << true + ; + + QTest::newRow("single-char-escapes") + << "01\\s23\\t45\\n67\\r89\\\\" + << "01 23\t45\n67\r89\\" + << true + ; + + QTest::newRow("hex-escapes") + << "kd\\x65" + << "kde" + << true + ; + + QTest::newRow("unfinished-hex-escape") + << "kd\\x6" + << "" + << false + ; + + QTest::newRow("invalid-hex-escape") + << "kd\\xzz" + << "" + << false + ; + + QTest::newRow("invalid-escape-sequence") + << "Foo\\a" + << "" + << false + ; + + QTest::newRow("unfinished-escape-sequence") + << "Foo\\" + << "" + << false + ; +} + +void TestKConfigUtils::testUnescapeString() +{ + QFETCH(QString, input); + QFETCH(QString, expected); + QFETCH(bool, expectedOk); + + bool ok; + QString error; + QString output = KConfigUtils::unescapeString(input, &ok, &error); + QCOMPARE(output, expected); + QCOMPARE(ok, expectedOk); + if (ok) { + QVERIFY(error.isEmpty()); + } else { + QVERIFY(!error.isEmpty()); + qDebug() << error; + } +} + diff --git a/tier1/kconfig/autotests/test_kconfigutils.h b/tier1/kconfig/autotests/test_kconfigutils.h new file mode 100644 index 00000000..2b8c5762 --- /dev/null +++ b/tier1/kconfig/autotests/test_kconfigutils.h @@ -0,0 +1,36 @@ +/* This file is part of the KDE libraries + Copyright 2010 Canonical Ltd + Author: Aurélien Gâteau <aurelien.gateau@canonical.com> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License (LGPL) as published by the Free Software Foundation; + either version 2 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ +#ifndef TEST_KCONFIGUTILS_H +#define TEST_KCONFIGUTILS_H + +#include <QObject> + +class TestKConfigUtils : public QObject +{ + Q_OBJECT +private Q_SLOTS: + void testParseGroupString_data(); + void testParseGroupString(); + void testUnescapeString_data(); + void testUnescapeString(); +}; + +#endif /* TEST_KCONFIGUTILS_H */ diff --git a/tier1/kconfig/docs/DESIGN.kconfig b/tier1/kconfig/docs/DESIGN.kconfig new file mode 100644 index 00000000..1aa0a3f8 --- /dev/null +++ b/tier1/kconfig/docs/DESIGN.kconfig @@ -0,0 +1,224 @@ +kconfigdata.h contains definitions of the data formats used by kconfig. + +Configuration entries are stored as "KEntry". They are indexed with "KEntryKey". +The primary store is a "KEntryMap" which is defined as a QMap from "KEntryKey" +to "KEntry" + +KEntry's are stored in order in the KEntryMap. The most significant sort +criteria is mGroup. This means that all entries who belong in the same group, +are grouped in the QMap as well. + +The start of a group is indicated with a KEntryKey with an empty mKey and a +dummy KEntry. This allows us to search for the start of the group and then to +iterate until we end up in another group. That way we will find all entries +of a certain group. + +Entries that are localised with the _current_ locale are stored with bLocal +set to true. Entries that are localised with another locale are either not +stored at all (default), or with the localization as part of the key (when +reading a file in order to merge it). +[WABA: Does it make sense to keep both localized and non-localised around? +Can't we just let the localised version override the non-localised version?] + +Currently the localization bit is the least significant sort criteria, that +means that the localised version always follows the non-localised version +immediately. + +<Changed for KDE 3.0> +Entries that are being read from a location other than the location to +which is written back are marked as "default" and will be added both as +normal entry as well as an entry with the key marked as default. + +When entries are written to disk, it is checked whether the entry to write +is equal to the default, if so the entry will not be written. The default +entry always follows directly after the normal entry, due to the sorting. +(After that the localised version follows) + +When entries are written to disk, it is checked whether the entry to write +is equal to the default, if so the entry will not be written. +</Changed> + +Open question: +Should unmodified entries that are written back be compared with the default +too? This seems to be mostly a transition issue. + +<Changed during KDE 3.0 / 3.2> +Extra functions: + +bool isEntryImmutable(key); // Can entry be modified? +bool hasDefault(key); // Is there a system wide default set for the entry? +void revertToDefault(key); // Restore to default +void deleteEntry(key); // Remove entry + +Note that there is a subtle difference between revertToDefault() and deleteEntry(). +revertToDefault() will change the entry to the default value set by the system +administrator (Via e.g. $KDEDIR/share/config) or, if no such default was set, +non-existant. +deleteEntry() will make the entry non-existant. + +Entries are marked "immutable" if the key is followed by [$i]. This means +that a user can not override these entries. + +Entries can be marked as deleted if they are followed by [$d]. This +is needed if the system administrator has specified a default value but the +entry was deleted (made 'non-existant'). In that case we can't just leave +the entry out since that would mean we get the default from the system +administrator back the next time we read the file. +</changed> + +When an entry is read with readEntry(key, defaultValue), non-existing +entries will return "defaultValue" while hasKey(key) will return "false" +for such entries. + +Currently all entries are stored in memory. When KConfig is "sync()'ed" +it reads the file that it is about to overwrite (for the second time), it +then merges in the entries it has in memory and writes the result back to +the file. It does NOT update its map of entries in memory with the entries +(re)read from disk. It only updates the entries in memory when +"reparseConfiguration()" is called. + + +Open Question: The standard writeEntry() function returns the original value, +is this needed? Nobody seems to use it. + +Open Question: The bPersistent flag doesn't seem to be used... could it be removed? + +Open Question: Is the bNLS flag needed? Localised entries seem to be mostly +useful for default files, are they ever created by the user itself? + +Open Question: Would it be worthwhile to lock a user option that is equal to the +default so that it doesn't change when the default changes? + + +KDE3.0 Changes +============== + +*) writeEntry now returns void instead of QString. +*) deleteEntry functions added + + +------------------------------------------------------------------------------ + +KConfig XT +========== + +My buzzword picker offered KConfig XT ("eXtended Technology") and KConfig NG +("Next Generation"). Since the planned changes are ment to be evolutionary +rather than revolutionary, KConfig NG was dropped. + +Goals +===== + +* Have the default value for config entries defined in 1 place. Currently it is +not uncommon to have them defined in three places: + 1) In the application that reads the setting in order to use it + 2) In the settings dialog when reading the setting + 3) In the settings dialog when selecting "Use defaults". + +* Provide type-information about config entries to facilate "KConfEdit" like +tools. Ideally type-information also includes range-information; this is even +mandatory if enums become an explicit type. + +* Facilitate the documentation of config entries. + + +Instead of relying on the defaults that are hard-coded in the application, +rely on default configuration files being installed in $KDEDIR. The technical +changes required for this are very minimal, it is mostly a change in policy. + +Type information can be provide by preceding every entry with a formalized +comment. + +Work to be done: +* KConfig needs to be extended to provide access to the default values provided +by the default config files. KConfig already stores this information internally. +(DONE) +* A formal comment structure needs to be designed that can convey type-information. +Preferably in such a way that it is easily parsable by both machine and user. +* KConfig needs to be extended, or another class created, that is able to parse +the formalized comments. +* A tool needs to be developed that can assist developers with the generation +and verification of default configuration files including type-information. + +Drawbacks: +* We rely on default configuration files being properly installed. +* The user can break applications by making improper modifications to these +files. +* It is not possible to store defaults settings in a config file that are +of a dynamic nature. Examples are settings derived from other settings, +e.g. a color setting could be derived from the current color theme, or +e.g. the default high score user name which is determined by the user +currently logged in. + + +Some random ideas: +* The format of the entries would be something like this: + +[Mail Settings] +#!Type=string +#!Description=SMTP server to use for sending mail +#!Description[nl]=SMTP server voor het versturen van mail +Host=wantelbos.zogje.fr + +- the type could be subclassed more, e.g. strings can be "email", "hostname", + "url", etc. + +- having translations in these files is very arguable. external po's would be + better. + + + +Class overview + + KConfigBase + | + v + KConfigBackend <-----> KConfig <------> KConfigSkeleton /--< myapp.kcfg + | | | / + v v |*---------------< +KConfigINIBackend KSimpleConfig |kconfig_compiler \ + | \--< myconfig.kcfg-codegen + v + MyConfig <-----KConfigDialogManager----> MyConfigWidget *---< myconfigwidget.ui + uic + +KConfigBase: defines API for generic config class + +KConfig: functional generic config class that supports merging of cascaded + configuration files + +KSimpleConfig: functional generic config class without support for cascading + configuration files. + +KConfigBackend: defines API for config backend, t.i. the actual handling + of the storage method and storage format. + +KConfigINIBackend: the standard (and only one so far) class that implements + the config backend using the file-based .INI format + for configuration files + +KConfigSkeleton: base class for deriving classes that store application + specific options providing type-safety and single-point + defaults. + +MyConfig: An application specific class that offers configuration options + to the applications via variables or accessor functions and that + handles type-safety and defaults. MyConfig is just an example + name, the application developer choses the actual name. + +myapp.kcfg: File describing the configuration options used by a specific + application. myapp.kcfg is just an example name, the application + developer choses the actual name. + +myconfig.kcfg-codegen: Implementation specific code generation instructions + for the MyConfig class. myconfig.kcfg-codegen is + just an example name, the application developer + choses the actual name. + +KConfigDialogManager: Class that links widgets in a dialog up with their + corresponding confguration options in a configuration + object derived from KConfigSkeleton. + +MyConfigWidget: Dialog generated from a .ui description file. Widget names + in the dialog that start with "kcfg_" refer to configuration + options. diff --git a/tier1/kconfig/docs/README.kiosk b/tier1/kconfig/docs/README.kiosk new file mode 100644 index 00000000..4974acef --- /dev/null +++ b/tier1/kconfig/docs/README.kiosk @@ -0,0 +1,817 @@ +In KDE-3 a kiosk-framework has been introduced. + +One of the driving forces behind KDE is to put the user in control and +give him or her a large amount of possibilities to adjust KDE to his or her +liking. However, in some situations it is required to reduce the possibilities +of KDE, e.g. because the system is to be used for one or more specific +dedicated tasks only. + +The kiosk-framework provides an easy way to disable certain features within +KDE to create a more controlled environment. + +KDE's kiosk-framework builds on KDE's configuration framework and adds a +simple application API that applications can query to get authorisation +for certain operations. + +The KDE kiosk-framework should be used IN ADDITION to the standard UNIX +security measures. + +The configuration framework in KDE +================================== + +Since the very beginning KDE makes use of file-hierarchy to store resources +for its applications. Resources range from icons, wallpapers, fonts to +sounds, menu-descriptions and configuration files. + +In KDE1 there were two locations were resources could be located: The +resources provided by the system were located under $KDEDIR and user- +specific resources were located under $HOME/.kde. + +In KDE2 resource management has been largely abstracted by the introduction +of the KStandardDirs class and has become much more flexible. The user / +administrator can now specify a variable number of locations where resources +can be found. A list of locations can either be specified via $KDEDIRS +(notice the extra 'S'), via /etc/kde4rc and even via the kdeglobals config +file. The location where user-specific resources can be found can be +set with $KDEHOME (The default is $HOME/.kde). Changes made by the user +are always written back to $KDEHOME. + +Both KDE1 and KDE2 feature so called "cascading configuration files": There +can be multiple configuration files with the same name in the various +locations for (config) resources, when that is the case, the information of +all these configuration files is combined on a key by key basis. If the same +key (within a certain group) is defined in more than one place, the value +of the key for the config file that was read last will override any previously +read values. Configuration files under $KDEHOME are always read last. This +ensures that after a configuration entry is written, the same value wil be +read back. + +In KDE3 two important changes have been made: + +* Default values are no longer written. +When a configuration file in a location other than $KDEHOME defines a value +for a key and the application subsequently writes out a new configuration file +to $KDEHOME, that configuration file will only contain an entry for the key +if its value differs from the value read from the other file. + +This counters the problem that changing default configuration files under +$KDEDIR would not take effect for users, since these users would most likely +have their own copy of these settings under $KDEHOME. KDE will make sure +not to copy these settings so changes made under $KDEDIR will affect all users +that haven't explicitly changed the affected settings to something else. + +* Configuration entries can be marked "immutable". +Starting with KDE-3, configuration entries can be marked "immutable". When a +configuration entry is immutable it means that configuration files that are +read later will not be able to override its value. Immutable entries cannot +be changed via KConfig and if the entry is present under $KDEHOME it will +be ignored. + +Entries can be marked immutable on 4 different levels: + +- On an entry by entry basis by appending "[$i]" after the key. + +Example: +[MyGroup] +someKey[$i]=42 + +- On a group by group basis by appending "[$i]" after the group. All entries +specified in the group will be marked immutable and no new entries can be +added to the group. + +Example: +[MyGroup][$i] +someKey=42 + +- On a file by file basis by starting the file with [$i]. + +Example: +[$i] +[MyGroup] +someKey=42 +[MyOtherGroup] +someOtherKey=11 + +- On a directory basis. [Not yet implemented] + +- The filesystem can also be used to mark files immutable. If KDE does not +have write-access to the user's version of a configuration file, the file +will be automatically considered immutable. + +To make the configuration file of Dolphin immutable one could for +example use the commands below. + +Example: +chown root.root /home/user/.kde/share/config/dolphinrc +chmod 644 /home/user/.kde/share/config/dolphinrc + +If you do this, the user will be warned that the configuration file is not +writable. Since you will normally not want that, you can add the following +two lines to the application's configuration file (or to kdeglobals to +disable the warning for all applications): + +[KDE Action Restrictions] +warn_unwritable_config=true + +Note that the above example is not fool-proof, the user can potentially still +rename either the root-owned dolphinrc file or any of the directories in +the path to another name and create a new dolphinrc _with_ write-access. + +KDE Action Restrictions +======================= + +Most functionality within KDE is coupled to so called actions. For example when a user +selects the File->Open option in the menubar of a KDE application, the "file_open" +action is activated. Likewise, toolbar icons are usually also coupled to actions. KDE +makes it possible to disable functionality by restricting specific actions. By restricting the +"file_open" action for example, the corresponding entry in the menubar and the corresponding icon on +the toolbar, if any, will disappear. + +To restrict access to function the kdeglobals file should contain the +group "[KDE Action Restrictions]", each action can then be restricted by +adding "<action>=false". E.g. to disable the action "shell_access" one +would add: +[KDE Action Restrictions][$i] +shell_access=false + +Actions that refer to menu and toolbar actions are prefixed with 'action/'. +The following standard actions are defined: + +action/file_new +action/file_open +action/file_open_recent +action/file_save +action/file_save_as +action/file_revert +action/file_close +action/file_print +action/file_print_preview +action/file_mail +action/file_quit +action/edit_undo +action/edit_redo +action/edit_cut +action/edit_copy +action/edit_paste +action/edit_select_all +action/edit_deselect +action/edit_find +action/edit_find_next +action/edit_find_last +action/edit_replace +action/view_actual_size +action/view_fit_to_page +action/view_fit_to_width +action/view_fit_to_height +action/view_zoom_in +action/view_zoom_out +action/view_zoom +action/view_redisplay +action/go_up +action/go_back +action/go_forward +action/go_home +action/go_previous +action/go_next +action/go_goto +action/go_goto_page +action/go_goto_line +action/go_first +action/go_last +action/bookmarks // See note below +action/bookmark_add +action/bookmark_edit +action/tools_spelling +action/options_show_menubar +action/options_show_toolbar // See note below +action/options_show_statusbar +action/options_save_options +action/options_configure +action/options_configure_keybinding +action/options_configure_toolbars +action/options_configure_notifications +action/help // See note below +action/help_contents +action/help_whats_this +action/help_report_bug +action/help_about_app +action/help_about_kde +action/fullscreen + +Actions in the KDE File Dialog: +action/home // Go to home directory +action/up // Go to parent directory +action/back // Go to previous directory +action/forward // Go to next directory +action/reload // Reload directory +action/mkdir // Create new directory +action/toggleSpeedbar // Show/hide sidebar +action/sorting menu // Sorting options +action/short view // Select short view +action/detailed view // Select detailed view +action/show hidden // Show/hide hidden files +action/preview // Show/hide preview +action/separate dirs // Show/hide separate directories + + +Konqueror & KDesktop related: +action/editfiletype +action/properties +action/openwith +action/openintab +action/kdesktop_rmb // RMB menu, see note below +action/iconview_preview +action/sharefile // File sharing, see note below +action/sendURL // Send Link Address +action/sendPage // Send File +action/devnew // Create New -> Device +action/incIconSize // Increase icon size +action/decIconSize // Decrease icon size +action/go // Entire go menu +action/configdesktop // Configure desktop in RMB menu, see also Control Module Restrictions +action/executeshellcommand // In Konqueror Tools menu, see also shell_access +action/show_dot // Show Hidden Files, see note below + + +Kicker related: +action/kicker_rmb // RMB menu +action/menuedit + + +KWin related: +action/kwin_rmb // RMB window context menu + +Konsole related: +action/konsole_rmb // RMB context menu + +action/settings // Entire settings menu +action/show_menubar +action/show_toolbar +action/scrollbar +action/fullscreen +action/bell +action/font +action/keyboard +action/schema +action/size +action/history +action/save_default +action/save_sessions_profile +action/options_configure_notifications +action/options_configure_keybinding +action/options_configure + +action/send_signal +action/bookmarks +action/add_bookmark +action/edit_bookmarks +action/clear_terminal +action/reset_clear_terminal +action/find_history +action/find_next +action/find_previous +action/save_history +action/clear_history +action/clear_all_histories +action/detach_session +action/rename_session +action/zmodem_upload +action/monitor_activity +action/monitor_silence +action/send_input_to_all_sessions +action/close_session +action/new_session +action/activate_menu +action/list_sessions +action/move_session_left +action/move_session_right +action/previous_session +action/next_session +action/switch_to_session_1 +action/switch_to_session_2 +action/switch_to_session_3 +action/switch_to_session_4 +action/switch_to_session_5 +action/switch_to_session_6 +action/switch_to_session_7 +action/switch_to_session_8 +action/switch_to_session_9 +action/switch_to_session_10 +action/switch_to_session_11 +action/switch_to_session_12 +action/bigger_font +action/smaller_font +action/toggle_bidi + + + +Notes: +* action/options_show_toolbar will also disable the "Toolbars" submenu + if present. +* action/bookmarks also disables action/bookmark_add and action/bookmark_edit +* action/help is not yet fully implemented +* action/kdesktop_rmb disables the RMB menu but some actions may still be accesible + via keyboard shortcuts: cut/copy/rename/trash/delete +* action/iconview_preview disables the option to toggle previews on or off + in icon mode but the actual preview settings remains unaffected. + To disable previews you also need to add the following lines to + konqiconviewrc: + [Settings] + PreviewsEnabled[$i]=false +* action/show_dot disables the option to toggle showing hidden files, the actual + setting remains unaffected. + To disable showing hidden files, add the following lines to konqiconviewrc: + [Settings] + ShowDotFiles[$i]=false +* action/sharefile disables file sharing from the UI, but you may also want + to disable filesharing altogether. + + +Applications may use additional actions that they defined themselves. +You can get a list of the actions used by a certain applications by using the +following qdbus command: + +qdbus org.kde.myapp-id | grep actions | cut -d '/' -f 4,5 + +Actions that refer to applications that need to be run as a different user +are prefixed by user/ and identified by the username. For example: + +user/root=false + +will disable all application entries that require root access. + + +Printing related action restrictions: + +print/system + - disables the option to select the printing system (backend). It is + recommended to disable this option once the correct printing + system has been configured. + +print/properties + - disables the button to change printer properties or to add a new printer. + +print/options + - disables the button to select additional print options. + +print/copies + - disables the panel that allows users to make more than one copy. + +print/selection + - disables the options that allows selecting a (pseudo) printer or + change any of the printer properties. Make sure that a proper + default printer has been selected before disabling this option. + Disabling this option also disables print/system, print/options + and print/properties. + +print/dialog + - disables the complete print dialog. Selecting the print option will + immediately print the selected document using default settings. + Make sure that a system wide default printer has been selected. + No application specific settings are honored. + +Other defined actions: + +shell_access + - defines whether a shell suitable for entering random commands + may be started. This also determines whether the "Run Command" + option (Alt-F2) can be used to run shell-commands and arbitrary + executables. Likewise, executables placed in the user's + Autostart folder will no longer be executed. Applications can + still be autostarted by placing .desktop files in the $KDEHOME/Autostart + or $KDEDIR/share/autostart directory. + See also run_desktop_files. + +custom_config + - defines whether the --config command line option should be honored. + The --config command line option can be used to circumvent + locked-down configuration files. + +logout + - defines whether the user will be able to logout from KDE. + +lock_screen + - defines whether the user will be able to lock the screen. + +run_command + - defines whether the "Run Command" (Alt-F2) option is available. + +movable_toolbars + - define whether toolbars may be moved around by the user. + See also action/options_show_toolbar. + +editable_desktop_icons + - define whether icons on the desktop can be moved, renamed, + deleted or added. You might want to set the path for + the Desktop to some read-only directory as well. + (Instead of $HOME/Desktop) + +run_desktop_files + - defines whether users may execute desktop files that are not + part of the default desktop, KDE menu, registered services and + autostarting services. + * The default desktop includes the files under + $KDEDIR/share/kdesktop/Desktop but _NOT_ the files under + $HOME/Desktop. + * The KDE menu includes all files under $KDEDIR/share/applnk and + $XDGDIR/applications + * Registered services includes all files under $KDEDIR/share/services. + * Autostarting services include all files under $KDEDIR/share/autostart + but _NOT_ the files under $KDEHOME/Autostart + + You probably also want to activate the following resource + restictions: + "appdata_kdesktop" - To restrict the default desktop. + "apps" - To restrict the KDE menu. + "xdgdata-apps" - To restrict the KDE menu. + "services" - To restrict registered services. + "autostart" - To restrict autostarting services. + Otherwise users can still execute .desktop files by placing them + in e.g. $KDEHOME/share/kdesktop/Desktop + +lineedit_text_completion + - defines whether input lines should have the potential to remember + any previously entered data and make suggestions based on this + when typing. When a single account is shared by multiple people you + may wish to disable this out of privacy concerns. + +start_new_session + - defines whether the user may start a second X session. + See also the kdm configuration. + +switch_user + - defines whether user switching via kdm is allowed + +skip_drm + - defines if the user may omit DRM checking. + Currently only used by kpdf + +Screensaver related: +opengl_screensavers + - defines whether OpenGL screensavers are allowed to be used. + +manipulatescreen_screensavers + - defines whether screensavers that manipulate an image of the screen + (e.g. moving chunks of the screen around) are allowed to be used. + +When configuration files are marked immutable in whole or in part the user will no +longer be able to make permanent changes to the settings that have been marked +immutable. Ideally the application will recognize this and will no longer offer the +user the possibility to change these settings. Unfortunately not all applications +support this at the moment. It's therefor possible that the user will still be +presented with an option in the user interface to change a setting that is +immutable, changes made this way will not be saved though. In some cases the +user may be able to use the changed setting till the application terminates, in +other cases the changed setting will simply be ignored and the application will +continue to work with the immutable setting. + +The following applications currently detect when their configuration files have been +marked immutable and adjust their user interface accordingly: + +* kicker - By marking the kickerrc config file as immutable, the panel will be +"locked down" and it will not be possible to make any changes to it. + +* kdesktop - By marking the kdesktoprc config file as immutable, the desktop +will be "locked down" and it will no longer be possible to select +"Configure Desktop" from its menus. + +* kcalc - By marking the kcalcrc config file as immutable, the "Configure" button +will not be shown + +Application .desktop files can have an additional field "X-KDE-AuthorizeAction". +If this field is present the .desktop file is only considered if the action(s) +mentioned in this field has been authorized. If multiple actions are listed +they should be separated by commas (','). So if the .desktop file of an application +lists one or more actions this way and the user has no authorization for one +of these actions then the application will not appear in the KDE menu and will not +be used by KDE for opening files. + +IMPORTANT NOTE: +Changing restrictions may influence the data that is cached in the ksycoca +database. Since changes to .../share/config/kdeglobals do not trigger an +automatic ksycoca update you need to force an update manually. +To force an update of the ksycoca database touch the file +.../share/services/update_ksycoca. This will force a user's sycoca database +to be rebuild the next time the user logs in. + +KDE URL Restrictions +==================== + +It is also possible to restrict URL related actions. The restriction framework +can disable URL actions based on the action, the URL in question and in some cases +the referring URL. URLs can be matched based on protocol, host and path. + +The syntax for adding URL action restrictions to kdeglobals is as follows: + +[KDE URL Restrictions] +rule_count=<N> +rule_1=<action>,<referingURL_protocol>,<referingURL_host>,<referingURL_path>,<URL_protocol>,<URL_host>,<URL_path>,<enabled> +... +rule_N=<action>,<referingURL_protocol>,<referingURL_host>,<referingURL_path>,<URL_protocol>,<URL_host>,<URL_path>,<enabled> + +The following actions are supported: +redirect - e.g. a html-page obtained via HTTP could redirect itself to file:/path/some-file. This + is disabled by default but could be explicitly enabled for a specific HTTP host. + This also applies to links contained in html documents. + Example: rule_1=redirect,http,myhost.acme.com,,file,,,true + +list - This controls which directories can be browsed with KDE's file-dialogs. If a user + should only be able to browse files under home directory one could use: + rule_1=list,,,,file,,,false + rule_2=list,,,,file,,$HOME,true + The first rule disables browing any directories on the local filesystem. The second rule + then enables browsing the users home directory. + +open - This controls which files can be opened by the user in applications. It also + affects where users can save files. To only allow a user to open the files + in his own home directory one could use: + rule_1=open,,,,file,,,false + rule_2=open,,,,file,,$HOME,true + rule_3=open,,,,file,,$TMP,true + Note that with the above, users would still be able to open files from + the internet. Note that the user is also given access to $TMP in order to + ensure correct operation of KDE applications. $TMP is replaced with the + temporary directory that KDE uses for this user. + +Some remarks: +* empty entries match everything +* host names may start with a wildcard, e.g. "*.acme.com" +* a protocol also matches similar protocols that start with the same name, + e.g. "http" matches both http and https. You can use "http!" if you only want to + match http (and not https) +* specifying a path matches all URLs that start with the same path. For better results + you should not include a trailing slash. If you want to specify one specific path, you can + add an exclamation mark. E.g. "/srv" matches both "/srv" and "/srv/www" but "/srv!" only + matches "/srv" and not "/srv/www". + + +KDE Resource Restrictions +========================== +Most KDE applications make use of additional resource files that are typically +located in directories under $KDEDIR/share. By default KDE allows users to +override any of these resources by placing files in the same location +under $KDEHOME/share. For example, Konsole stores profiles under +$KDEDIR/share/konsole and users can add additional profiles by +installing files in $KDEHOME/share/konsole. + +KDE Resource Restrictions make it possible to restrict the lookup of files +to directories outside of $KDEHOME only. + +The following resources are defined: + +autostart - share/autostart +data - share +html - share/doc/HTML +icon - share/icon +config - share/config +pixmap - share/pixmaps +apps - share/applnk +xdgdata-apps - share/applications +sound - share/sounds +locale - share/locale +services - share/services +servicetypes - share/servicetypes +mime - share/mimelnk +wallpaper - share/wallpapers +templates - share/templates +exe - bin +lib - lib + +See http://api.kde.org/4.x-api/kdelibs-apidocs/kdecore/html/classKStandardDirs.html +for a more up-to-date list of resources. + +For the purpose of resource restrictions there are two special resources: +all - covers all resources +data_<appname> - covers the sub section for <appname> in the data resource. + +To restrict resources the kdeglobals file should contain the +group "[KDE Resource Restrictions]", each resource can then be restricted by +adding "<resource>=false". E.g. to restrict the "wallpaper" resource to +$KDEDIR/share/wallpapers one would add: +[KDE Resource Restrictions][$i] +wallpaper=false + +And to prevent a user from adding additional konsole profiles, one would add: +[KDE Resource Restrictions][$i] +data_konsole=false + + +Control Module Restrictions +=========================== + +It is possible to restrict access to particular control modules. +Although it is possible to remove control modules from the Control +Center by editing the menu structure, such modules will then still +be available to applications. A better way is to use the control +module restrictions offered by KIOSK: + +[KDE Control Module Restrictions][$i] +<menu-id>=false + +Some example menu-ids are: + +kde-display.desktop +kde-proxy.desktop +kde-screensaver.desktop + +See also kcmshell --list for a list of all the base names. + +Expansion of environment variables in KDE config files. +======================================================= + +Since KDE-3.1, arbitrary entries in configuration files can contain environment +variables. In order to use this the entry must be marked with [$e]. + +Example: +Name[$e]=$USER + +When the "Name" entry is read $USER will be replaced with the value of the +$USER environment variable. Note that the application will replace $USER +with the value of the environment variable after saving. To prevent this +combine the $e option with $i (immmutable) option. + +Example: +Name[$ei]=$USER + +The above will make that the "Name" entry will always return the value of +the $USER environment variable. The user will not be able to change this entry. + +The following syntax is also supported: +Name[$ei]=${USER} + + +Shell Commands in KDE config files. +=================================== + +Since KDE-3.1 arbitrary entries in configuration files can contain shell +commands. This way the value of a configuration entry can be determined +dynamically at runtime. In order to use this the entry must be marked +with [$e]. + +Example: +Host[$e]=$(hostname) + + +KDE Kiosk Application API +========================== + +Three new methods have been added to KApplication: + +- bool authorize(QString action); // Generic actions +- bool authorizeKAction(QString action); // For KActions exclusively +- bool authorizeURLAction(QString, referringURL, destinationURL) // URL Handling + +Automatic Logout +================ + +Since KDE 3.4 it is possible to automatically logout users that have been idle +for a certain period of time. + +WARNING: Be careful with this option, logging out a user may result in dataloss! + +In kdesktoprc you can use the following entry to enable automatic logout: + +[ScreenSaver] +AutoLogout=true +AutoLogoutTimeout=600 + +The AutoLogoutTimeout is the time in seconds that the user has to be idle before +his session is logged out. + + +Users can be associated with Profile(s) +======================================= + +A user can be associated with one or more profiles. A profile indicates a +configuration set that applies to a group of users. Each profile has a name +to identify it. If a user is associated with more than one profile then the +order of the two profiles is important. Settings associated with one profile +could override the settings in the other profile, depending on the order. + + +Mapping profiles to users +========================= + +A mapping file determines which profile(s) should be used for which user. +The mapping file can be configured in /etc/kde4rc in the [Directories] group: + + [Directories] + userProfileMapFile=/etc/kde-user-profile + +Profiles can be mapped to individual users based on username, or profiles can +be mapped to groups of users based on the UNIX group(s) the users are part of. +(See man 1 groups) + + +Mapping profiles to individual users +==================================== + +The mapping file can contain a [Users] section for mapping profiles to +an individual user. The [Users] section contains the user's account name +followed by one or more profiles as follow: + + [Users] + bastian=developer + adrians=developer,packager + +The above example assigns to user "bastian" the profile "developer". To user +"adrians" it assigns the two profiles "developer" and "packager". The order +in which the profiles are listed makes a difference, settings in earlier +profiles overrule settings in profiles that are listed after it. In the above +case of user "adrians", wherever the "developer" and "packager" profiles contain +conflicting settings, the settings of the "developer" profile will take precedent. + +If a user has an entry under the [Users] section, this entry will determine all +profiles that are applicable to the user. The user will not be assigned any +additional profiles based on the groups the user is part of. + +Mapping profiles to user groups +=============================== + +If a user has no entry under the [Users] section in the mapping file, the profiles +that are applicable to the user will be based on the UNIX group(s) the user is +part of. + +The groups and the order in which the groups are considered is determined by +the following entry in the [General] section of the mapping file: + + [General] + groups=pkgs,devel,bofh + +Each of these groups should have an entry under the [Groups] section that defines +which profile(s) belongs to that group. This looks as follows: + + [Groups] + pkgs=packager + devel=developer + bofh=admin,packager,developer + +For each group that a user is part of, the corresponding profile(s) are used. The +order in which the groups are listed in the "groups" entry, determines the resulting +order of all the applicable profiles. If multiple profiles are applicable to a +particular user and a profile contains settings that conflict with settings in +another profile then the settings in the earlier listed profile take precedent. + +So if, based on the example above, a user is part of the "pkgs" group then the +"packager" profile will be used for that user. If the user is part of the "devel" +group then the "developer" profile will be used. Users that are part of the "bofh" +group will use the "admin", "packager" as well as the "developer" profile. In case +of conflict, settings in the "admin" profile will take precedent over settings +in the "packager" or "developer" profiles. + +If the user is part of both the "pkgs" and "devel" groups, then both the "packager" +and "developer" profiles will be used. In case of conflicting settings between the +two profiles, the "packager" profile will take precedent because the "pkgs" group +associated with the profile was listed before the "devel" group. + +The "groups" command can be used to see to which groups a user belongs: + + > groups coolo + coolo : users uucp dialout audio video cdrecording devel + +Note that in general only a few groups will have profiles associated with them. +In the example above only the "devel" group has a profile associated with it, +the other groups do not and will be ignored. + +If there is no profile defined for any of the groups that the user is in, the +user will be assigned the "default" profile. + + +The Profile determines the directory prefixes +============================================= + +The global KDE configuration file (e.g. kdeglobals or /etc/kde4rc) can +contain config-groups that are associated with a certain user profile. +Such a config-group is treated similar as the [Directories] config-group. + +The name of a such config-group is [Directories-<ProfileName>] + + +Integration with KIOSK Admin Tool +================================= + +The KIOSK Admin Tool uses /etc/kde4rc as source for all its profile +information. For this it uses the following keys in the +[Directories-<ProfileName>] config-group: + + # Short text describing this profile + ProfileDescription= + + # Files will be installed with the uid of this user + ProfileInstallUser= + +The KIOSK Admin Tool uses the first directory from the prefixes= entry +as default installation directory for this profile. + + +Default setting as example +========================== + +The following snipped could be added to /etc/kde4rc to define a "default" profile: + + [Directories-default] + ProfileDescription=Default profile + ProfileDescription[de]=Defaultprofiel + ProfileInstallUser=root + prefixes=/var/run/kde-profile/default + diff --git a/tier1/kconfig/src/CMakeLists.txt b/tier1/kconfig/src/CMakeLists.txt new file mode 100644 index 00000000..caa7a43d --- /dev/null +++ b/tier1/kconfig/src/CMakeLists.txt @@ -0,0 +1,4 @@ +add_subdirectory(core) +add_subdirectory(gui) +add_subdirectory(kconfig_compiler) +add_subdirectory(kconf_update) diff --git a/tier1/kconfig/src/core/CMakeLists.txt b/tier1/kconfig/src/core/CMakeLists.txt new file mode 100644 index 00000000..ea272d31 --- /dev/null +++ b/tier1/kconfig/src/core/CMakeLists.txt @@ -0,0 +1,53 @@ + +find_package(Qt5Core 5.2.0 REQUIRED NO_MODULE) + +set(libkconfigcore_SRCS + kconfig.cpp + kconfigbase.cpp + kconfigdata.cpp + kconfiggroup.cpp + kconfigbackend.cpp + kconfigini.cpp + kdesktopfile.cpp + ksharedconfig.cpp + kcoreconfigskeleton.cpp + kauthorized.cpp + kemailsettings.cpp +) + +add_library(KF5ConfigCore ${libkconfigcore_SRCS}) +generate_export_header(KF5ConfigCore BASE_NAME KConfigCore) +add_library(KF5::ConfigCore ALIAS KF5ConfigCore) + +target_link_libraries(KF5ConfigCore PUBLIC Qt5::Core) +if(WIN32) + target_link_libraries(KF5ConfigCore PRIVATE ${KDEWIN_LIBRARIES}) +endif() + +if(IS_ABSOLUTE "${INCLUDE_INSTALL_DIR}") + target_include_directories(KF5ConfigCore INTERFACE "$<INSTALL_INTERFACE:${INCLUDE_INSTALL_DIR}>" ) +else() + target_include_directories(KF5ConfigCore INTERFACE "$<INSTALL_INTERFACE:${CMAKE_INSTALL_PREFIX}/${INCLUDE_INSTALL_DIR}>" ) +endif() + +set_target_properties(KF5ConfigCore PROPERTIES VERSION ${KCONFIG_VERSION_STRING} + SOVERSION ${KCONFIG_SOVERSION} + EXPORT_NAME ConfigCore +) + +install(TARGETS KF5ConfigCore EXPORT KF5ConfigTargets ${INSTALL_TARGETS_DEFAULT_ARGS}) + +install( FILES + ${CMAKE_CURRENT_BINARY_DIR}/kconfigcore_export.h + conversion_check.h + kconfig.h + #kconfigbackend.h re-enable post-API review and implementation (4.2?) + kconfigbase.h + kconfiggroup.h + kdesktopfile.h + ksharedconfig.h + kcoreconfigskeleton.h + kauthorized.h + kemailsettings.h + DESTINATION ${INCLUDE_INSTALL_DIR} COMPONENT Devel +) diff --git a/tier1/kconfig/src/core/bufferfragment_p.h b/tier1/kconfig/src/core/bufferfragment_p.h new file mode 100644 index 00000000..5a753ad4 --- /dev/null +++ b/tier1/kconfig/src/core/bufferfragment_p.h @@ -0,0 +1,181 @@ +/* + This file is part of the KDE libraries + Copyright (c) 2008 Jakub Stachowski <qbast@go2.pl> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef BUFFERFRAGMENT_H +#define BUFFERFRAGMENT_H + +#define bf_isspace(str) ((str == ' ') || (str == '\t') || (str == '\r')) + +// This class provides wrapper around fragment of existing buffer (array of bytes). +// If underlying buffer gets deleted, all BufferFragment objects referencing it become invalid. +// Use toByteArray() to make deep copy of the buffer fragment. +// +// API is designed to subset of QByteArray methods with some changes: +// - trim() is like QByteArray.trimmed(), but it modifies current object +// - truncateLeft() provides way to cut off beginning of the buffer +// - split() works more like strtok_r than QByteArray.split() +// - truncateLeft() and mid() require position argument to be valid + +class KConfigIniBackend::BufferFragment +{ + +public: + + BufferFragment() : d(0), len(0) + { + } + + BufferFragment(char* buf, int size) : d(buf), len(size) + { + } + + int length() const + { + return len; + } + + char at(unsigned int i) const + { + Q_ASSERT(i < len); + return d[i]; + } + + void clear() + { + len = 0; + } + + const char* constData() const + { + return d; + } + + char* data() const + { + return d; + } + + void trim() + { + while (bf_isspace(*d) && len > 0) { + d++; + len--; + } + while (len > 0 && bf_isspace(d[len - 1])) + len--; + } + + // similar to strtok_r . On first call variable pointed by start should be set to 0. + // Each call will update *start to new starting position. + BufferFragment split(char c, unsigned int* start) + { + while (*start < len) { + int end = indexOf(c, *start); + if (end == -1) end = len; + BufferFragment line(d + (*start), end - (*start)); + *start = end + 1; + return line; + } + return BufferFragment(); + } + + bool isEmpty() const + { + return (len == 0); + } + + BufferFragment left(unsigned int size) const + { + return BufferFragment(d, qMin(size,len)); + } + + void truncateLeft(unsigned int size) + { + Q_ASSERT(size <= len); + d += size; + len -= size; + } + + void truncate(unsigned int pos) + { + if (pos < len) len = pos; + } + + bool isNull() const + { + return (d == 0); + } + + BufferFragment mid(unsigned int pos, int length=-1) const + { + Q_ASSERT(pos < len); + int size = length; + if (length == -1 || (pos + length) > len) + size = len - pos; + return BufferFragment(d + pos, size); + } + + bool operator==(const QByteArray& other) const + { + return (other.size() == (int)len && memcmp(d,other.constData(),len) == 0); + } + + bool operator!=(const QByteArray& other) const + { + return (other.size() != (int)len || memcmp(d,other.constData(),len) != 0); + } + + int indexOf(char c, unsigned int from = 0) const + { + const char* cursor = d + from - 1; + const char* end = d + len; + while ( ++cursor < end) + if (*cursor ==c ) + return cursor - d; + return -1; + } + + int lastIndexOf(char c) const + { + int from = len - 1; + while (from >= 0) + if (d[from] == c) + return from; + else + from--; + return -1; + } + + QByteArray toByteArray() const { + return QByteArray(d,len); + } + + // this is faster than toByteArray, but returned QByteArray becomes invalid + // when buffer for this BufferFragment disappears + QByteArray toVolatileByteArray() const { + return QByteArray::fromRawData(d, len); + } + +private: + char* d; + unsigned int len; +}; + +#endif diff --git a/tier1/kconfig/src/core/conversion_check.h b/tier1/kconfig/src/core/conversion_check.h new file mode 100644 index 00000000..23bdcf04 --- /dev/null +++ b/tier1/kconfig/src/core/conversion_check.h @@ -0,0 +1,120 @@ +/* + This file is part of the KDE libraries + Copyright (c) 2006 Thomas Braxton <brax108@cox.net> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + + +#ifndef CONVERSION_CHECK_H +#define CONVERSION_CHECK_H + +#include <QtCore/QString> +#include <QtCore/QDate> +#include <QtCore/QPoint> +#include <QtCore/QSize> +#include <QtCore/QRect> +#include <QtCore/QVariant> + +class QColor; +class QFont; + +namespace ConversionCheck { + +// used to distinguish between supported/unsupported types +struct supported { }; +struct unsupported { }; + +// traits type class to define support for constraints +template <typename T> +struct QVconvertible +{ + typedef unsupported toQString; + typedef unsupported toQVariant; +}; + +// constraint classes +template <typename T> +struct type_toQString +{ + void constraint() { supported x = y; Q_UNUSED(x); } + typename QVconvertible<T>::toQString y; +}; + +template <typename T> +struct type_toQVariant +{ + void constraint() { supported x = y; Q_UNUSED(x); } + typename QVconvertible<T>::toQVariant y; +}; + + +// check if T is convertible to QString thru QVariant +// if not supported can't be used in QList<T> functions +template <typename T> +inline void to_QString() +{ + void (type_toQString<T>::*x)() = &type_toQString<T>::constraint; + Q_UNUSED(x); +} + +// check if T is convertible to QVariant & supported in readEntry/writeEntry +template <typename T> +inline void to_QVariant() +{ + void (type_toQVariant<T>::*x)() = &type_toQVariant<T>::constraint; + Q_UNUSED(x); +} + +// define for all types handled in readEntry/writeEntry +// string_support - is supported by QVariant(type).toString(), +// can be used in QList<T> functions +// variant_support - has a QVariant constructor +#define QVConversions(type, string_support, variant_support) \ +template <> struct QVconvertible<type> {\ + typedef string_support toQString;\ + typedef variant_support toQVariant;\ +} + +// The only types needed here are the types handled in readEntry/writeEntry +// the default QVconvertible will take care of the rest. +QVConversions(bool, supported, supported); +QVConversions(int, supported, supported); +QVConversions(unsigned int, supported, supported); +QVConversions(long long, supported, supported); +QVConversions(unsigned long long, supported, supported); +QVConversions(float, supported, supported); +QVConversions(double, supported, supported); +QVConversions(QString, supported, supported); +QVConversions(QColor, unsupported, supported); +QVConversions(QFont, supported, supported); +QVConversions(QDateTime, unsupported, supported); +QVConversions(QDate, unsupported, supported); +QVConversions(QSize, unsupported, supported); +QVConversions(QRect, unsupported, supported); +QVConversions(QPoint, unsupported, supported); +QVConversions(QSizeF, unsupported, supported); +QVConversions(QRectF, unsupported, supported); +QVConversions(QPointF, unsupported, supported); +QVConversions(QByteArray, supported, supported); +QVConversions(QStringList, unsupported, supported); +QVConversions(QVariantList, unsupported, supported); +QVConversions(QUrl, supported, supported); +QVConversions(QList<QUrl>, unsupported, supported); +} + +#endif + diff --git a/tier1/kconfig/src/core/kauthorized.cpp b/tier1/kconfig/src/core/kauthorized.cpp new file mode 100644 index 00000000..abf479ca --- /dev/null +++ b/tier1/kconfig/src/core/kauthorized.cpp @@ -0,0 +1,393 @@ +/* This file is part of the KDE libraries + Copyright (C) 1997 Matthias Kalle Dalheimer (kalle@kde.org) + Copyright (C) 1998, 1999, 2000 Waldo Bastian <bastian@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "kauthorized.h" + +#include <QtCore/QDir> +#include <QtCore/QRegExp> +#include <QList> +#include <QUrl> + +#include <QCoreApplication> +#include <ksharedconfig.h> +#include <stdlib.h> // srand(), rand() +#ifndef Q_OS_WIN +#include <unistd.h> +#include <netdb.h> +#endif + +#include <kconfiggroup.h> + +#include <QMutex> +#include <QMutexLocker> + +extern bool kde_kiosk_exception; + + +class URLActionRule +{ + public: +#define checkExactMatch(s, b) \ + if (s.isEmpty()) b = true; \ + else if (s[s.length()-1] == QLatin1Char('!')) \ + { b = false; s.truncate(s.length()-1); } \ + else b = true; +#define checkStartWildCard(s, b) \ + if (s.isEmpty()) b = true; \ + else if (s[0] == QLatin1Char('*')) \ + { b = true; s = s.mid(1); } \ + else b = false; +#define checkEqual(s, b) \ + b = (s == QString::fromLatin1("=")); + + URLActionRule(const QByteArray &act, + const QString &bProt, const QString &bHost, const QString &bPath, + const QString &dProt, const QString &dHost, const QString &dPath, + bool perm) + : action(act), + baseProt(bProt), baseHost(bHost), basePath(bPath), + destProt(dProt), destHost(dHost), destPath(dPath), + permission(perm) + { + checkExactMatch(baseProt, baseProtWildCard); + checkStartWildCard(baseHost, baseHostWildCard); + checkExactMatch(basePath, basePathWildCard); + checkExactMatch(destProt, destProtWildCard); + checkStartWildCard(destHost, destHostWildCard); + checkExactMatch(destPath, destPathWildCard); + checkEqual(destProt, destProtEqual); + checkEqual(destHost, destHostEqual); + } + + bool baseMatch(const QUrl &url, const QString &protClass) const + { + if (baseProtWildCard) + { + if ( !baseProt.isEmpty() && !url.scheme().startsWith(baseProt) && + (protClass.isEmpty() || (protClass != baseProt)) ) + return false; + } + else + { + if ( (url.scheme() != baseProt) && + (protClass.isEmpty() || (protClass != baseProt)) ) + return false; + } + if (baseHostWildCard) + { + if (!baseHost.isEmpty() && !url.host().endsWith(baseHost)) + return false; + } + else + { + if (url.host() != baseHost) + return false; + } + if (basePathWildCard) + { + if (!basePath.isEmpty() && !url.path().startsWith(basePath)) + return false; + } + else + { + if (url.path() != basePath) + return false; + } + return true; + } + + bool destMatch(const QUrl &url, const QString &protClass, const QUrl &base, const QString &baseClass) const + { + if (destProtEqual) + { + if ( (url.scheme() != base.scheme()) && + (protClass.isEmpty() || baseClass.isEmpty() || protClass != baseClass) ) + return false; + } + else if (destProtWildCard) + { + if ( !destProt.isEmpty() && !url.scheme().startsWith(destProt) && + (protClass.isEmpty() || (protClass != destProt)) ) + return false; + } + else + { + if ( (url.scheme() != destProt) && + (protClass.isEmpty() || (protClass != destProt)) ) + return false; + } + if (destHostWildCard) + { + if (!destHost.isEmpty() && !url.host().endsWith(destHost)) + return false; + } + else if (destHostEqual) + { + if (url.host() != base.host()) + return false; + } + else + { + if (url.host() != destHost) + return false; + } + if (destPathWildCard) + { + if (!destPath.isEmpty() && !url.path().startsWith(destPath)) + return false; + } + else + { + if (url.path() != destPath) + return false; + } + return true; + } + + QByteArray action; + QString baseProt; + QString baseHost; + QString basePath; + QString destProt; + QString destHost; + QString destPath; + bool baseProtWildCard : 1; + bool baseHostWildCard : 1; + bool basePathWildCard : 1; + bool destProtWildCard : 1; + bool destHostWildCard : 1; + bool destPathWildCard : 1; + bool destProtEqual : 1; + bool destHostEqual : 1; + bool permission; +}; + +class KAuthorizedPrivate { +public: + KAuthorizedPrivate() + : actionRestrictions( false ), blockEverything(false),mutex(QMutex::Recursive) + { + Q_ASSERT_X(QCoreApplication::instance(),"KAuthorizedPrivate()","There has to be an existing QCoreApplication::instance() pointer"); + + KSharedConfig::Ptr config = KSharedConfig::openConfig(); + + Q_ASSERT_X(config,"KAuthorizedPrivate()","There has to be an existing KSharedConfig::openConfig() pointer"); + if (!config) { + blockEverything=true; + return; + } + actionRestrictions = config->hasGroup("KDE Action Restrictions" ) && !kde_kiosk_exception; + } + + ~KAuthorizedPrivate() + { + } + + bool actionRestrictions : 1; + bool blockEverything : 1; + QList<URLActionRule> urlActionRestrictions; + QMutex mutex; +}; + +Q_GLOBAL_STATIC(KAuthorizedPrivate,authPrivate) +#define MY_D KAuthorizedPrivate *d=authPrivate(); + + +bool KAuthorized::authorize(const QString &genericAction) +{ + MY_D + if (d->blockEverything) return false; + + if (!d->actionRestrictions) + return true; + + KConfigGroup cg(KSharedConfig::openConfig(), "KDE Action Restrictions"); + return cg.readEntry(genericAction, true); +} + +bool KAuthorized::authorizeKAction(const QString& action) +{ + MY_D + if (d->blockEverything) return false; + if (!d->actionRestrictions || action.isEmpty()) + return true; + + return authorize(QLatin1String("action/") + action); +} + +bool KAuthorized::authorizeControlModule(const QString &menuId) +{ + if (menuId.isEmpty() || kde_kiosk_exception) + return true; + KConfigGroup cg(KSharedConfig::openConfig(), "KDE Control Module Restrictions"); + return cg.readEntry(menuId, true); +} + +QStringList KAuthorized::authorizeControlModules(const QStringList &menuIds) +{ + KConfigGroup cg(KSharedConfig::openConfig(), "KDE Control Module Restrictions"); + QStringList result; + for(QStringList::ConstIterator it = menuIds.begin(); + it != menuIds.end(); ++it) + { + if (cg.readEntry(*it, true)) + result.append(*it); + } + return result; +} + +static void initUrlActionRestrictions() +{ + MY_D + const QString Any; + + d->urlActionRestrictions.clear(); + d->urlActionRestrictions.append( + URLActionRule("open", Any, Any, Any, Any, Any, Any, true)); + d->urlActionRestrictions.append( + URLActionRule("list", Any, Any, Any, Any, Any, Any, true)); +// TEST: +// d->urlActionRestrictions.append( +// URLActionRule("list", Any, Any, Any, Any, Any, Any, false)); +// d->urlActionRestrictions.append( +// URLActionRule("list", Any, Any, Any, "file", Any, QDir::homePath(), true)); + d->urlActionRestrictions.append( + URLActionRule("link", Any, Any, Any, QLatin1String(":internet"), Any, Any, true)); + d->urlActionRestrictions.append( + URLActionRule("redirect", Any, Any, Any, QLatin1String(":internet"), Any, Any, true)); + + // We allow redirections to file: but not from internet protocols, redirecting to file: + // is very popular among io-slaves and we don't want to break them + d->urlActionRestrictions.append( + URLActionRule("redirect", Any, Any, Any, QLatin1String("file"), Any, Any, true)); + d->urlActionRestrictions.append( + URLActionRule("redirect", QLatin1String(":internet"), Any, Any, QLatin1String("file"), Any, Any, false)); + + // local protocols may redirect everywhere + d->urlActionRestrictions.append( + URLActionRule("redirect", QLatin1String(":local"), Any, Any, Any, Any, Any, true)); + + // Anyone may redirect to about: + d->urlActionRestrictions.append( + URLActionRule("redirect", Any, Any, Any, QLatin1String("about"), Any, Any, true)); + + // Anyone may redirect to mailto: + d->urlActionRestrictions.append( + URLActionRule("redirect", Any, Any, Any, QLatin1String("mailto"), Any, Any, true)); + + // Anyone may redirect to itself, cq. within it's own group + d->urlActionRestrictions.append( + URLActionRule("redirect", Any, Any, Any, QLatin1String("="), Any, Any, true)); + + d->urlActionRestrictions.append( + URLActionRule("redirect", QLatin1String("about"), Any, Any, Any, Any, Any, true)); + + + KConfigGroup cg(KSharedConfig::openConfig(), "KDE URL Restrictions"); + int count = cg.readEntry("rule_count", 0); + QString keyFormat = QString::fromLatin1("rule_%1"); + for(int i = 1; i <= count; i++) + { + QString key = keyFormat.arg(i); + const QStringList rule = cg.readEntry(key, QStringList()); + if (rule.count() != 8) + continue; + const QByteArray action = rule[0].toLatin1(); + QString refProt = rule[1]; + QString refHost = rule[2]; + QString refPath = rule[3]; + QString urlProt = rule[4]; + QString urlHost = rule[5]; + QString urlPath = rule[6]; + bool bEnabled = (rule[7].toLower() == QLatin1String("true")); + + if (refPath.startsWith(QLatin1String("$HOME"))) + refPath.replace(0, 5, QDir::homePath()); + else if (refPath.startsWith(QLatin1Char('~'))) + refPath.replace(0, 1, QDir::homePath()); + if (urlPath.startsWith(QLatin1String("$HOME"))) + urlPath.replace(0, 5, QDir::homePath()); + else if (urlPath.startsWith(QLatin1Char('~'))) + urlPath.replace(0, 1, QDir::homePath()); + + if (refPath.startsWith(QLatin1String("$TMP"))) + refPath.replace(0, 4, QDir::tempPath()); + if (urlPath.startsWith(QLatin1String("$TMP"))) + urlPath.replace(0, 4, QDir::tempPath()); + + d->urlActionRestrictions.append( + URLActionRule( action, refProt, refHost, refPath, urlProt, urlHost, urlPath, bEnabled)); + } +} + +namespace KAuthorized +{ +// Called by KAuthorized::allowUrlAction in KIO +KCONFIGCORE_EXPORT void allowUrlActionInternal(const QString &action, const QUrl &_baseURL, const QUrl &_destURL) +{ + MY_D + QMutexLocker locker((&d->mutex)); + +#if QT_VERSION >= QT_VERSION_CHECK(5, 3, 0) + const QString basePath = _baseURL.adjusted(QUrl::StripTrailingSlash).path(); + const QString destPath = _destURL.adjusted(QUrl::StripTrailingSlash).path(); +#else + const QString basePath = QUrl(_baseURL.toString(QUrl::StripTrailingSlash)).path(); + const QString destPath = QUrl(_destURL.toString(QUrl::StripTrailingSlash)).path(); +#endif + + d->urlActionRestrictions.append( URLActionRule + ( action.toLatin1(), _baseURL.scheme(), _baseURL.host(), basePath, + _destURL.scheme(), _destURL.host(), destPath, true)); +} + +// Called by KAuthorized::authorizeUrlAction in KIO +KCONFIGCORE_EXPORT bool authorizeUrlActionInternal(const QString& action, const QUrl &_baseURL, const QUrl &_destURL, const QString& baseClass, const QString& destClass) +{ + MY_D + QMutexLocker locker(&(d->mutex)); + if (d->blockEverything) return false; + + if (_destURL.isEmpty()) + return true; + + bool result = false; + if (d->urlActionRestrictions.isEmpty()) + initUrlActionRestrictions(); + + QUrl baseURL(_baseURL); + baseURL.setPath(QDir::cleanPath(baseURL.path())); + + QUrl destURL(_destURL); + destURL.setPath(QDir::cleanPath(destURL.path())); + + Q_FOREACH(const URLActionRule &rule, d->urlActionRestrictions) { + if ((result != rule.permission) && // No need to check if it doesn't make a difference + (action == QLatin1String(rule.action.constData())) && + rule.baseMatch(baseURL, baseClass) && + rule.destMatch(destURL, destClass, baseURL, baseClass)) + { + result = rule.permission; + } + } + return result; +} + +} // namespace diff --git a/tier1/kconfig/src/core/kauthorized.h b/tier1/kconfig/src/core/kauthorized.h new file mode 100644 index 00000000..a16368a8 --- /dev/null +++ b/tier1/kconfig/src/core/kauthorized.h @@ -0,0 +1,73 @@ +/* This file is part of the KDE libraries + Copyright (C) 1997 Matthias Kalle Dalheimer (kalle@kde.org) + Copyright (c) 1998, 1999 Waldo Bastian <bastian@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef KAUTHORIZED_H +#define KAUTHORIZED_H + +#include <kconfigcore_export.h> + +class QUrl; +class QString; +class QStringList; + +/** +* Kiosk authorization framework +* +* Core functionality, see kauthorized.h for authorizeUrlAction. +*/ +namespace KAuthorized +{ + /** + * Returns whether a certain action is authorized + * @param genericAction The name of a generic action + * @return true if the action is authorized + * @todo what are the generic actions? + */ + KCONFIGCORE_EXPORT bool authorize(const QString& genericAction); + + /** + * Returns whether a certain KAction is authorized. + * + * @param action The name of a KAction action. The name is prepended + * with "action/" before being passed to authorize() + * @return true if the KAction is authorized + */ + KCONFIGCORE_EXPORT bool authorizeKAction(const QString& action); + + /** + * Returns whether access to a certain control module is authorized. + * + * @param menuId identifying the control module, e.g. kde-mouse.desktop + * @return true if access to the module is authorized, false otherwise. + */ + KCONFIGCORE_EXPORT bool authorizeControlModule(const QString& menuId); + + /** + * Returns which control modules from a given list are authorized for access. + * + * @param menuIds list of menu-ids of control modules; + * an example of a menu-id is kde-mouse.desktop. + * @return Those control modules for which access has been authorized. + */ + KCONFIGCORE_EXPORT QStringList authorizeControlModules(const QStringList& menuIds); + +} + +#endif diff --git a/tier1/kconfig/src/core/kconfig.cpp b/tier1/kconfig/src/core/kconfig.cpp new file mode 100644 index 00000000..b311a366 --- /dev/null +++ b/tier1/kconfig/src/core/kconfig.cpp @@ -0,0 +1,931 @@ +/* + This file is part of the KDE libraries + Copyright (c) 2006, 2007 Thomas Braxton <kde.braxton@gmail.com> + Copyright (c) 1999 Preston Brown <pbrown@kde.org> + Copyright (c) 1997-1999 Matthias Kalle Dalheimer <kalle@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +// Qt5 TODO: re-enable. No point in doing it before, it breaks on QString::fromUtf8(QByteArray), which exists in qt5. +#undef QT_NO_CAST_FROM_BYTEARRAY + +#include "kconfig.h" +#include "kconfig_p.h" + +#include <cstdlib> +#include <fcntl.h> + +#ifdef Q_OS_WIN +static inline FILE* popen(const char *cmd, const char *mode) { return _popen(cmd, mode); } +static inline int pclose(FILE* stream) { return _pclose(stream); } +#else +#include <unistd.h> +#endif + +#include "kconfigbackend.h" +#include "kconfiggroup.h" + +#include <qcoreapplication.h> +#include <qprocess.h> +#include <qstandardpaths.h> +#include <qbytearray.h> +#include <qfile.h> +#include <qlocale.h> +#include <qdir.h> +#include <QtCore/QProcess> +#include <QtCore/QSet> + +bool KConfigPrivate::mappingsRegistered=false; + +KConfigPrivate::KConfigPrivate(KConfig::OpenFlags flags, + QStandardPaths::StandardLocation resourceType) + : openFlags(flags), resourceType(resourceType), mBackend(0), + bDynamicBackend(true), bDirty(false), bReadDefaults(false), + bFileImmutable(false), bForceGlobal(false), bSuppressGlobal(false), + configState(KConfigBase::NoAccess) +{ + sGlobalFileName = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + QLatin1String("/kdeglobals"); + + static int use_etc_kderc = -1; + if (use_etc_kderc < 0) + use_etc_kderc = !qEnvironmentVariableIsSet("KDE_SKIP_KDERC"); // for unit tests + if (use_etc_kderc) { + + etc_kderc = +#ifdef Q_OS_WIN + QFile::decodeName( qgetenv("WINDIR") + "/kde4rc" ); +#else + QLatin1String("/etc/kde4rc"); +#endif + if (!QFileInfo(etc_kderc).isReadable()) { + etc_kderc.clear(); + } + } + +// if (!mappingsRegistered) { +// KEntryMap tmp; +// if (!etc_kderc.isEmpty()) { +// QExplicitlySharedDataPointer<KConfigBackend> backend = KConfigBackend::create(etc_kderc, QLatin1String("INI")); +// backend->parseConfig( "en_US", tmp, KConfigBackend::ParseDefaults); +// } +// const QString kde4rc(QDir::home().filePath(".kde4rc")); +// if (KStandardDirs::checkAccess(kde4rc, R_OK)) { +// QExplicitlySharedDataPointer<KConfigBackend> backend = KConfigBackend::create(kde4rc, QLatin1String("INI")); +// backend->parseConfig( "en_US", tmp, KConfigBackend::ParseOptions()); +// } +// KConfigBackend::registerMappings(tmp); +// mappingsRegistered = true; +// } + +#if 0 // KDE4 code + setLocale(KLocale::global()->language()); +#else + setLocale(QLocale::system().name()); +#endif +} + + +bool KConfigPrivate::lockLocal() +{ + if (mBackend) { + return mBackend->lock(); + } + // anonymous object - pretend we locked it + return true; +} + +void KConfigPrivate::copyGroup(const QByteArray& source, const QByteArray& destination, + KConfigGroup *otherGroup, KConfigBase::WriteConfigFlags flags) const +{ + KEntryMap& otherMap = otherGroup->config()->d_ptr->entryMap; + const int len = source.length(); + const bool sameName = (destination == source); + + // we keep this bool outside the foreach loop so that if + // the group is empty, we don't end up marking the other config + // as dirty erroneously + bool dirtied = false; + + for (KEntryMap::ConstIterator entryMapIt( entryMap.constBegin() ); entryMapIt != entryMap.constEnd(); ++entryMapIt) { + const QByteArray& group = entryMapIt.key().mGroup; + + if (!group.startsWith(source)) // nothing to do + continue; + + // don't copy groups that start with the same prefix, but are not sub-groups + if (group.length() > len && group[len] != '\x1d') + continue; + + KEntryKey newKey = entryMapIt.key(); + + if (flags & KConfigBase::Localized) { + newKey.bLocal = true; + } + + if (!sameName) + newKey.mGroup.replace(0, len, destination); + + KEntry entry = entryMap[ entryMapIt.key() ]; + dirtied = entry.bDirty = flags & KConfigBase::Persistent; + + if (flags & KConfigBase::Global) { + entry.bGlobal = true; + } + + otherMap[newKey] = entry; + } + + if (dirtied) { + otherGroup->config()->d_ptr->bDirty = true; + } +} + +QString KConfigPrivate::expandString(const QString& value) +{ + QString aValue = value; + + // check for environment variables and make necessary translations + int nDollarPos = aValue.indexOf( QLatin1Char('$') ); + while( nDollarPos != -1 && nDollarPos+1 < aValue.length()) { + // there is at least one $ + if( aValue[nDollarPos+1] == QLatin1Char('(') ) { + int nEndPos = nDollarPos+1; + // the next character is not $ + while ( (nEndPos <= aValue.length()) && (aValue[nEndPos]!=QLatin1Char(')')) ) + nEndPos++; + nEndPos++; + QString cmd = aValue.mid( nDollarPos+2, nEndPos-nDollarPos-3 ); + + QString result; +#if 0 // Removed in KDE Frameworks 5. No such concept anymore. Just set your PATH. + QByteArray oldpath = qgetenv( "PATH" ); + QByteArray newpath; + if (KComponentData::hasMainComponent()) { + newpath = QFile::encodeName(KGlobal::dirs()->resourceDirs("exe").join(QChar::fromLatin1(KPATH_SEPARATOR))); + if (!newpath.isEmpty() && !oldpath.isEmpty()) + newpath += KPATH_SEPARATOR; + } + newpath += oldpath; + qputenv( "PATH", newpath); +#endif + +// FIXME: wince does not have pipes +#ifndef _WIN32_WCE + FILE *fs = popen(QFile::encodeName(cmd).data(), "r"); + if (fs) { + QTextStream ts(fs, QIODevice::ReadOnly); + result = ts.readAll().trimmed(); + pclose(fs); + } +#endif +#if 0 // Removed in KDE Frameworks 5, see above. + qputenv( "PATH", oldpath); +#endif + aValue.replace( nDollarPos, nEndPos-nDollarPos, result ); + nDollarPos += result.length(); + } else if( aValue[nDollarPos+1] != QLatin1Char('$') ) { + int nEndPos = nDollarPos+1; + // the next character is not $ + QString aVarName; + if ( aValue[nEndPos] == QLatin1Char('{') ) { + while ( (nEndPos <= aValue.length()) && (aValue[nEndPos] != QLatin1Char('}')) ) + nEndPos++; + nEndPos++; + aVarName = aValue.mid( nDollarPos+2, nEndPos-nDollarPos-3 ); + } else { + while ( nEndPos <= aValue.length() && + (aValue[nEndPos].isNumber() || + aValue[nEndPos].isLetter() || + aValue[nEndPos] == QLatin1Char('_') ) ) + nEndPos++; + aVarName = aValue.mid( nDollarPos+1, nEndPos-nDollarPos-1 ); + } + QString env; + if (!aVarName.isEmpty()) { +#ifdef Q_OS_WIN + if (aVarName == QLatin1String("HOME")) + env = QDir::homePath(); + else +#endif + { + QByteArray pEnv = qgetenv(aVarName.toLatin1().constData()); + if( !pEnv.isEmpty() ) + env = QString::fromLocal8Bit(pEnv.constData()); + } + aValue.replace(nDollarPos, nEndPos-nDollarPos, env); + nDollarPos += env.length(); + } else + aValue.remove( nDollarPos, nEndPos-nDollarPos ); + } else { + // remove one of the dollar signs + aValue.remove( nDollarPos, 1 ); + nDollarPos++; + } + nDollarPos = aValue.indexOf( QLatin1Char('$'), nDollarPos ); + } + + return aValue; +} + + +KConfig::KConfig(const QString& file, OpenFlags mode, + QStandardPaths::StandardLocation resourceType) + : d_ptr(new KConfigPrivate(mode, resourceType)) +{ + d_ptr->changeFileName(file); // set the local file name + + // read initial information off disk + reparseConfiguration(); +} + +KConfig::KConfig(const QString& file, const QString& backend, QStandardPaths::StandardLocation resourceType) + : d_ptr(new KConfigPrivate(SimpleConfig, resourceType)) +{ + d_ptr->mBackend = KConfigBackend::create(file, backend); + d_ptr->bDynamicBackend = false; + d_ptr->changeFileName(file); // set the local file name + + // read initial information off disk + reparseConfiguration(); +} + +KConfig::KConfig(KConfigPrivate &d) + : d_ptr(&d) +{ +} + +KConfig::~KConfig() +{ + Q_D(KConfig); + if (d->bDirty && (d->mBackend && d->mBackend->ref.load() == 1)) + sync(); + delete d; +} + +QStringList KConfig::groupList() const +{ + Q_D(const KConfig); + QSet<QString> groups; + + for (KEntryMap::ConstIterator entryMapIt( d->entryMap.constBegin() ); entryMapIt != d->entryMap.constEnd(); ++entryMapIt) { + const KEntryKey& key = entryMapIt.key(); + const QByteArray group = key.mGroup; + if (key.mKey.isNull() && !group.isEmpty() && group != "<default>" && group != "$Version") { + const QString groupname = QString::fromUtf8(group); + groups << groupname.left(groupname.indexOf(QLatin1Char('\x1d'))); + } + } + + return groups.toList(); +} + +QStringList KConfigPrivate::groupList(const QByteArray& group) const +{ + QByteArray theGroup = group + '\x1d'; + QSet<QString> groups; + + for (KEntryMap::ConstIterator entryMapIt( entryMap.constBegin() ); entryMapIt != entryMap.constEnd(); ++entryMapIt) { + const KEntryKey& key = entryMapIt.key(); + if (key.mKey.isNull() && key.mGroup.startsWith(theGroup)) { + const QString groupname = QString::fromUtf8(key.mGroup.mid(theGroup.length())); + groups << groupname.left(groupname.indexOf(QLatin1Char('\x1d'))); + } + } + + return groups.toList(); +} + +// List all sub groups, including subsubgroups +QSet<QByteArray> KConfigPrivate::allSubGroups(const QByteArray& parentGroup) const +{ + QSet<QByteArray> groups; + QByteArray theGroup = parentGroup + '\x1d'; + groups << parentGroup; + + for (KEntryMap::const_iterator entryMapIt = entryMap.begin(); entryMapIt != entryMap.end(); ++entryMapIt) { + const KEntryKey& key = entryMapIt.key(); + if (key.mKey.isNull() && key.mGroup.startsWith(theGroup)) { + groups << key.mGroup; + } + } + return groups; +} + +bool KConfigPrivate::hasNonDeletedEntries(const QByteArray& group) const +{ + const QSet<QByteArray> allGroups = allSubGroups(group); + + Q_FOREACH(const QByteArray& aGroup, allGroups) { + // Could be optimized, let's use the slow way for now + // Check for any non-deleted entry + if (!keyListImpl(aGroup).isEmpty()) + return true; + } + return false; +} + + +QStringList KConfigPrivate::keyListImpl(const QByteArray& theGroup) const +{ + QStringList keys; + + const KEntryMapConstIterator theEnd = entryMap.constEnd(); + KEntryMapConstIterator it = entryMap.findEntry(theGroup); + if (it != theEnd) { + ++it; // advance past the special group entry marker + + QSet<QString> tmp; + for (; it != theEnd && it.key().mGroup == theGroup; ++it) { + const KEntryKey& key = it.key(); + if (key.mGroup == theGroup && !key.mKey.isNull() && !it->bDeleted) + tmp << QString::fromUtf8(key.mKey); + } + keys = tmp.toList(); + } + + return keys; +} + +QStringList KConfig::keyList(const QString& aGroup) const +{ + Q_D(const KConfig); + const QByteArray theGroup(aGroup.isEmpty() ? "<default>" : aGroup.toUtf8()); + return d->keyListImpl(theGroup); +} + +QMap<QString,QString> KConfig::entryMap(const QString& aGroup) const +{ + Q_D(const KConfig); + QMap<QString, QString> theMap; + const QByteArray theGroup(aGroup.isEmpty() ? "<default>" : aGroup.toUtf8()); + + const KEntryMapConstIterator theEnd = d->entryMap.constEnd(); + KEntryMapConstIterator it = d->entryMap.findEntry(theGroup, 0, 0); + if (it != theEnd) { + ++it; // advance past the special group entry marker + + for (; it != theEnd && it.key().mGroup == theGroup; ++it) { + // leave the default values and deleted entries out + if (!it->bDeleted && !it.key().bDefault) { + const QString key = QString::fromUtf8(it.key().mKey.constData()); + // the localized entry should come first, so don't overwrite it + // with the non-localized entry + if (!theMap.contains(key)) { + if (it->bExpand) { + theMap.insert(key,KConfigPrivate::expandString(QString::fromUtf8(it->mValue.constData()))); + } else { + theMap.insert(key,QString::fromUtf8(it->mValue.constData())); + } + } + } + } + } + + return theMap; +} + +bool KConfig::sync() +{ + Q_D(KConfig); + + if (isImmutable() || name().isEmpty()) { + // can't write to an immutable or anonymous file. + return false; + } + + if (d->bDirty && d->mBackend) { + const QByteArray utf8Locale(locale().toUtf8()); + + // Create the containing dir, maybe it wasn't there + d->mBackend->createEnclosing(); + + // lock the local file + if (d->configState == ReadWrite && !d->lockLocal()) { + qWarning() << "couldn't lock local file"; + return false; + } + + // Rewrite global/local config only if there is a dirty entry in it. + bool writeGlobals = false; + bool writeLocals = false; + Q_FOREACH (const KEntry& e, d->entryMap) { + if (e.bDirty) { + if (e.bGlobal) { + writeGlobals = true; + } else { + writeLocals = true; + } + + if (writeGlobals && writeLocals) { + break; + } + } + } + + d->bDirty = false; // will revert to true if a config write fails + + if (d->wantGlobals() && writeGlobals) { + QExplicitlySharedDataPointer<KConfigBackend> tmp = KConfigBackend::create(d->sGlobalFileName); + if (d->configState == ReadWrite && !tmp->lock()) { + qWarning() << "couldn't lock global file"; + d->bDirty = true; + return false; + } + if (!tmp->writeConfig(utf8Locale, d->entryMap, KConfigBackend::WriteGlobal)) { + d->bDirty = true; + } + if (tmp->isLocked()) { + tmp->unlock(); + } + } + + if (writeLocals) { + if (!d->mBackend->writeConfig(utf8Locale, d->entryMap, KConfigBackend::WriteOptions())) { + d->bDirty = true; + } + } + if (d->mBackend->isLocked()) { + d->mBackend->unlock(); + } + } + return !d->bDirty; +} + +void KConfig::markAsClean() +{ + Q_D(KConfig); + d->bDirty = false; + + // clear any dirty flags that entries might have set + const KEntryMapIterator theEnd = d->entryMap.end(); + for (KEntryMapIterator it = d->entryMap.begin(); it != theEnd; ++it) + it->bDirty = false; +} + +bool KConfig::isDirty() const +{ + Q_D(const KConfig); + return d->bDirty; +} + +void KConfig::checkUpdate(const QString &id, const QString &updateFile) +{ + const KConfigGroup cg(this, "$Version"); + const QString cfg_id = updateFile+QLatin1Char(':')+id; + const QStringList ids = cg.readEntry("update_info", QStringList()); + if (!ids.contains(cfg_id)) { +#if 0 + KToolInvocation::kdeinitExecWait(QString::fromLatin1("kconf_update"), QStringList() << QString::fromLatin1("--check") << updateFile); +#else + QProcess::execute(QString::fromLatin1("kconf_update"), QStringList() << QString::fromLatin1("--check") << updateFile); +#endif + reparseConfiguration(); + } +} + +KConfig* KConfig::copyTo(const QString &file, KConfig *config) const +{ + Q_D(const KConfig); + if (!config) + config = new KConfig(QString(), SimpleConfig, d->resourceType); + config->d_func()->changeFileName(file); + config->d_func()->entryMap = d->entryMap; + config->d_func()->bFileImmutable = false; + + const KEntryMapIterator theEnd = config->d_func()->entryMap.end(); + for (KEntryMapIterator it = config->d_func()->entryMap.begin(); it != theEnd; ++it) + it->bDirty = true; + config->d_ptr->bDirty = true; + + return config; +} + +QString KConfig::name() const +{ + Q_D(const KConfig); + return d->fileName; +} + +Q_GLOBAL_STATIC(QString, globalMainConfigName) + +void KConfig::setMainConfigName(const QString& str) +{ + *globalMainConfigName() = str; +} + +QString KConfig::mainConfigName() +{ + // --config on the command line overrides everything else + const QStringList args = QCoreApplication::arguments(); + for (int i = 1; i < args.count() ; ++i) { + if (args.at(i) == QLatin1String("--config") && i < args.count()-1) { + return args.at(i+1); + } + } + const QString globalName = *globalMainConfigName(); + if (!globalName.isEmpty()) + return globalName; + + QString appName = QCoreApplication::applicationName(); + return appName + QLatin1String("rc"); +} + +void KConfigPrivate::changeFileName(const QString& name) +{ + fileName = name; + + QString file; + if (name.isEmpty()) { + if (wantDefaults()) { // accessing default app-specific config "appnamerc" + fileName = KConfig::mainConfigName(); + file = QStandardPaths::writableLocation(resourceType) + QLatin1Char('/') + fileName; + } else if (wantGlobals()) { // accessing "kdeglobals" - XXX used anywhere? + resourceType = QStandardPaths::GenericConfigLocation; + fileName = QLatin1String("kdeglobals"); + file = sGlobalFileName; + } else { + // anonymous config + openFlags = KConfig::SimpleConfig; + return; + } + } else if (QDir::isAbsolutePath(fileName)) { + fileName = QFileInfo(fileName).canonicalFilePath(); + if (fileName.isEmpty()) // file doesn't exist (yet) + fileName = name; + file = fileName; + } else { + file = QStandardPaths::writableLocation(resourceType) + QLatin1Char('/') + fileName; + } + + Q_ASSERT(!file.isEmpty()); + +#ifndef Q_OS_WIN + bSuppressGlobal = (file == sGlobalFileName); +#else + bSuppressGlobal = (file.compare(sGlobalFileName, Qt::CaseInsensitive) == 0); +#endif + + if (bDynamicBackend || !mBackend) // allow dynamic changing of backend + mBackend = KConfigBackend::create(file); + else + mBackend->setFilePath(file); + + configState = mBackend->accessMode(); +} + +void KConfig::reparseConfiguration() +{ + Q_D(KConfig); + if (d->fileName.isEmpty()) { + return; + } + + // Don't lose pending changes + if (!d->isReadOnly() && d->bDirty) + sync(); + + d->entryMap.clear(); + + d->bFileImmutable = false; + + // Parse all desired files from the least to the most specific. + if (d->wantGlobals()) + d->parseGlobalFiles(); + + d->parseConfigFiles(); +} + + +QStringList KConfigPrivate::getGlobalFiles() const +{ + QStringList globalFiles; + Q_FOREACH (const QString& dir1, QStandardPaths::locateAll(QStandardPaths::GenericConfigLocation, QLatin1String("kdeglobals"))) + globalFiles.push_front(dir1); + Q_FOREACH (const QString& dir2, QStandardPaths::locateAll(QStandardPaths::GenericConfigLocation, QLatin1String("system.kdeglobals"))) + globalFiles.push_front(dir2); + if (!etc_kderc.isEmpty()) + globalFiles.push_front(etc_kderc); + return globalFiles; +} + +void KConfigPrivate::parseGlobalFiles() +{ + const QStringList globalFiles = getGlobalFiles(); +// qDebug() << "parsing global files" << globalFiles; + + // TODO: can we cache the values in etc_kderc / other global files + // on a per-application basis? + const QByteArray utf8Locale = locale.toUtf8(); + Q_FOREACH(const QString& file, globalFiles) { + KConfigBackend::ParseOptions parseOpts = KConfigBackend::ParseGlobal|KConfigBackend::ParseExpansions; +#ifndef Q_OS_WIN + if (file != sGlobalFileName) +#else + if (file.compare(sGlobalFileName, Qt::CaseInsensitive) != 0) +#endif + parseOpts |= KConfigBackend::ParseDefaults; + + QExplicitlySharedDataPointer<KConfigBackend> backend = KConfigBackend::create(file); + if ( backend->parseConfig( utf8Locale, entryMap, parseOpts) == KConfigBackend::ParseImmutable) + break; + } +} + +void KConfigPrivate::parseConfigFiles() +{ + // can only read the file if there is a backend and a file name + if (mBackend && !fileName.isEmpty()) { + + bFileImmutable = false; + + QList<QString> files; + if (wantDefaults()) { + if (bSuppressGlobal) { + files = getGlobalFiles(); + } else { + if (QDir::isAbsolutePath(fileName)) { + files << fileName; + } else { + Q_FOREACH (const QString& f, QStandardPaths::locateAll(resourceType, fileName)) + files.prepend(f); + } + } + } else { + files << mBackend->filePath(); + } + if (!isSimple()) + files = extraFiles.toList() + files; + +// qDebug() << "parsing local files" << files; + + const QByteArray utf8Locale = locale.toUtf8(); + foreach(const QString& file, files) { +#ifndef Q_OS_WIN + if (file == mBackend->filePath()) { +#else + if (file.compare(mBackend->filePath(), Qt::CaseInsensitive) == 0) { +#endif + switch (mBackend->parseConfig(utf8Locale, entryMap, KConfigBackend::ParseExpansions)) { + case KConfigBackend::ParseOk: + break; + case KConfigBackend::ParseImmutable: + bFileImmutable = true; + break; + case KConfigBackend::ParseOpenError: + configState = KConfigBase::NoAccess; + break; + } + } else { + QExplicitlySharedDataPointer<KConfigBackend> backend = KConfigBackend::create(file); + bFileImmutable = (backend->parseConfig(utf8Locale, entryMap, + KConfigBackend::ParseDefaults|KConfigBackend::ParseExpansions) + == KConfigBackend::ParseImmutable); + } + + if (bFileImmutable) + break; + } +#pragma message("TODO: enable kiosk feature again (resource restrictions), but without KStandardDirs... Needs a class in the kconfig framework.") +#if 0 + if (componentData.dirs()->isRestrictedResource(resourceType, fileName)) + bFileImmutable = true; +#endif + } +} + +KConfig::AccessMode KConfig::accessMode() const +{ + Q_D(const KConfig); + return d->configState; +} + +void KConfig::addConfigSources(const QStringList& files) +{ + Q_D(KConfig); + Q_FOREACH(const QString& file, files) { + d->extraFiles.push(file); + } + + if (!files.isEmpty()) { + reparseConfiguration(); + } +} + +QString KConfig::locale() const +{ + Q_D(const KConfig); + return d->locale; +} + +bool KConfigPrivate::setLocale(const QString& aLocale) +{ + if (aLocale != locale) { + locale = aLocale; + return true; + } + return false; +} + +bool KConfig::setLocale(const QString& locale) +{ + Q_D(KConfig); + if (d->setLocale(locale)) { + reparseConfiguration(); + return true; + } + return false; +} + +void KConfig::setReadDefaults(bool b) +{ + Q_D(KConfig); + d->bReadDefaults = b; +} + +bool KConfig::readDefaults() const +{ + Q_D(const KConfig); + return d->bReadDefaults; +} + +bool KConfig::isImmutable() const +{ + Q_D(const KConfig); + return d->bFileImmutable; +} + +bool KConfig::isGroupImmutableImpl(const QByteArray& aGroup) const +{ + Q_D(const KConfig); + return isImmutable() || d->entryMap.getEntryOption(aGroup, 0, 0, KEntryMap::EntryImmutable); +} + +#ifndef KDE_NO_DEPRECATED +void KConfig::setForceGlobal(bool b) +{ + Q_D(KConfig); + d->bForceGlobal = b; +} +#endif + +#ifndef KDE_NO_DEPRECATED +bool KConfig::forceGlobal() const +{ + Q_D(const KConfig); + return d->bForceGlobal; +} +#endif + +KConfigGroup KConfig::groupImpl(const QByteArray &group) +{ + return KConfigGroup(this, group.constData()); +} + +const KConfigGroup KConfig::groupImpl(const QByteArray &group) const +{ + return KConfigGroup(this, group.constData()); +} + +KEntryMap::EntryOptions convertToOptions(KConfig::WriteConfigFlags flags) +{ + KEntryMap::EntryOptions options=0; + + if (flags&KConfig::Persistent) + options |= KEntryMap::EntryDirty; + if (flags&KConfig::Global) + options |= KEntryMap::EntryGlobal; + if (flags&KConfig::Localized) + options |= KEntryMap::EntryLocalized; + return options; +} + +void KConfig::deleteGroupImpl(const QByteArray &aGroup, WriteConfigFlags flags) +{ + Q_D(KConfig); + KEntryMap::EntryOptions options = convertToOptions(flags)|KEntryMap::EntryDeleted; + + const QSet<QByteArray> groups = d->allSubGroups(aGroup); + Q_FOREACH (const QByteArray& group, groups) { + const QStringList keys = d->keyListImpl(group); + Q_FOREACH (const QString& _key, keys) { + const QByteArray &key = _key.toUtf8(); + if (d->canWriteEntry(group, key.constData())) { + d->entryMap.setEntry(group, key, QByteArray(), options); + d->bDirty = true; + } + } + } +} + +bool KConfig::isConfigWritable(bool warnUser) +{ + Q_D(KConfig); + bool allWritable = (d->mBackend ? d->mBackend->isWritable() : false); + + if (warnUser && !allWritable) { + QString errorMsg; + if (d->mBackend) // TODO how can be it be null? Set errorMsg appropriately + errorMsg = d->mBackend->nonWritableErrorMessage(); + + // Note: We don't ask the user if we should not ask this question again because we can't save the answer. + errorMsg += QCoreApplication::translate("KConfig", "Please contact your system administrator."); + QString cmdToExec = QStandardPaths::findExecutable(QString::fromLatin1("kdialog")); + if (!cmdToExec.isEmpty()) + { + QProcess::execute(cmdToExec, QStringList() + << QString::fromLatin1("--title") << QCoreApplication::applicationName() + << QString::fromLatin1("--msgbox") << errorMsg); + } + } + + d->configState = allWritable ? ReadWrite : ReadOnly; // update the read/write status + + return allWritable; +} + +bool KConfig::hasGroupImpl(const QByteArray& aGroup) const +{ + Q_D(const KConfig); + + // No need to look for the actual group entry anymore, or for subgroups: + // a group exists if it contains any non-deleted entry. + + return d->hasNonDeletedEntries(aGroup); +} + +bool KConfigPrivate::canWriteEntry(const QByteArray& group, const char* key, bool isDefault) const +{ + if (bFileImmutable || + entryMap.getEntryOption(group, key, KEntryMap::SearchLocalized, KEntryMap::EntryImmutable)) + return isDefault; + return true; +} + +void KConfigPrivate::putData( const QByteArray& group, const char* key, + const QByteArray& value, KConfigBase::WriteConfigFlags flags, bool expand) +{ + KEntryMap::EntryOptions options = convertToOptions(flags); + + if (bForceGlobal) + options |= KEntryMap::EntryGlobal; + if (expand) + options |= KEntryMap::EntryExpansion; + + if (value.isNull()) // deleting entry + options |= KEntryMap::EntryDeleted; + + bool dirtied = entryMap.setEntry(group, key, value, options); + if (dirtied && (flags & KConfigBase::Persistent)) + bDirty = true; +} + +void KConfigPrivate::revertEntry(const QByteArray& group, const char* key) +{ + bool dirtied = entryMap.revertEntry(group, key); + if (dirtied) + bDirty = true; +} + +QByteArray KConfigPrivate::lookupData(const QByteArray& group, const char* key, + KEntryMap::SearchFlags flags) const +{ + if (bReadDefaults) + flags |= KEntryMap::SearchDefaults; + const KEntryMapConstIterator it = entryMap.findEntry(group, key, flags); + if (it == entryMap.constEnd()) + return QByteArray(); + return it->mValue; +} + +QString KConfigPrivate::lookupData(const QByteArray& group, const char* key, + KEntryMap::SearchFlags flags, bool *expand) const +{ + if (bReadDefaults) + flags |= KEntryMap::SearchDefaults; + return entryMap.getEntry(group, key, QString(), flags, expand); +} + +QStandardPaths::StandardLocation KConfig::locationType() const +{ + Q_D(const KConfig); + return d->resourceType; +} + +void KConfig::virtual_hook(int /*id*/, void* /*data*/) +{ + /* nothing */ +} diff --git a/tier1/kconfig/src/core/kconfig.h b/tier1/kconfig/src/core/kconfig.h new file mode 100644 index 00000000..6dbf1d26 --- /dev/null +++ b/tier1/kconfig/src/core/kconfig.h @@ -0,0 +1,397 @@ +/* + This file is part of the KDE libraries + Copyright (c) 2006, 2007 Thomas Braxton <kde.braxton@gmail.com> + Copyright (c) 2001 Waldo Bastian <bastian@kde.org> + Copyright (c) 1999 Preston Brown <pbrown@kde.org> + Copyright (c) 1997 Matthias Kalle Dalheimer <kalle@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef KCONFIG_H +#define KCONFIG_H + +#include "kconfigbase.h" + +#include <kconfigcore_export.h> + +#include <QtCore/QString> +#include <QtCore/QVariant> +#include <QtCore/QByteArray> +#include <QtCore/QList> +#include <qstandardpaths.h> + +class KConfigGroup; +class KEntryMap; +class KConfigPrivate; + +/** + * \class KConfig kconfig.h <KConfig> + * + * \brief The central class of the KDE configuration data system. + * + * Quickstart: + * + * Get the default application config object via KSharedConfig::openConfig(). + * + * Load a specific configuration file: + * \code + * KConfig config( "/etc/kderc", KConfig::SimpleConfig ); + * \endcode + * + * Load the configuration of a specific component: + * \code + * KConfig config( "pluginrc" ); + * \endcode + * + * In general it is recommended to use KSharedConfig instead of + * creating multiple instances of KConfig to avoid the overhead of + * separate objects or concerns about synchronizing writes to disk + * even if the configuration object is updated from multiple code paths. + * KSharedConfig provides a set of open methods as counterparts for the + * KConfig constructors. + * + * \sa KSharedConfig, KConfigGroup, <a href="http://techbase.kde.org/index.php?title=Development/Tutorials/KConfig">the techbase HOWTO on KConfig</a>. + */ +class KCONFIGCORE_EXPORT KConfig : public KConfigBase +{ +public: + /** + * Determines how the system-wide and user's global settings will affect + * the reading of the configuration. + * + * If CascadeConfig is selected, system-wide configuration sources are used + * to provide defaults for the settings accessed through this object, or + * possibly to override those settings in certain cases. + * + * IncludeGlobals does the same, but with the global settings sources. + * + * Note that the main configuration source overrides the cascaded sources, + * which override those provided to addConfigSources(), which override the + * global sources. The exception is that if a key or group is marked as + * being immutable, it will not be overridden. + * + * Note that all values other than IncludeGlobals and CascadeConfig are + * convenience definitions for the basic mode. + * Do @em not combine them with anything. + */ + enum OpenFlag { + IncludeGlobals = 0x01, ///< Blend kdeglobals into the config object. + CascadeConfig = 0x02, ///< Cascade to system-wide config files. + + SimpleConfig = 0x00, ///< Just a single config file. + NoCascade = IncludeGlobals, ///< Include user's globals, but omit system settings. + NoGlobals = CascadeConfig, ///< Cascade to system settings, but omit user's globals. + FullConfig = IncludeGlobals|CascadeConfig ///< Fully-fledged config, including globals and cascading to system settings + }; + Q_DECLARE_FLAGS(OpenFlags, OpenFlag) + + /** + * Creates a KConfig object to manipulate a configuration file for the + * current application. + * + * If an absolute path is specified for @p file, that file will be used + * as the store for the configuration settings. If a non-absolute path + * is provided, the file will be looked for in the standard directory + * specified by type. If no path is provided, a default + * configuration file will be used based on the name of the main + * application component. + * + * @p mode determines whether the user or global settings will be allowed + * to influence the values returned by this object. See OpenFlags for + * more details. + * + * @note You probably want to use KSharedConfig::openConfig instead. + * + * @param file the name of the file. If an empty string is passed in + * and SimpleConfig is passed in for the OpenFlags, then an in-memory + * KConfig object is created which will not write out to file nor which + * requires any file in the filesystem at all. + * @param mode how global settings should affect the configuration + * options exposed by this KConfig object + * @param type The standard directory to look for the configuration + * file in + * + * @sa KSharedConfig::openConfig(const QString&, OpenFlags, const char*) + */ + explicit KConfig(const QString& file = QString(), OpenFlags mode = FullConfig, + QStandardPaths::StandardLocation type = QStandardPaths::GenericConfigLocation); + + /** + * @internal + * + * Creates a KConfig object using the specified backend. If the backend can not + * be found or loaded, then the standard configuration parser is used as a fallback. + * + * @param file the file to be parsed + * @param backend the backend to load + * @param type where to look for the file if an absolute path is not provided + * + * @since 4.1 + */ + KConfig(const QString& file, const QString& backend, QStandardPaths::StandardLocation type = QStandardPaths::GenericConfigLocation); + + virtual ~KConfig(); + + /** + * Returns the standard location enum passed to the constructor. + * Used by KSharedConfig. + * @since 5.0 + */ + QStandardPaths::StandardLocation locationType() const; + + /** + * Returns the filename used to store the configuration. + */ + QString name() const; + + /// @reimp + bool sync() Q_DECL_OVERRIDE; + + /// Returns true if sync has any changes to write out. + /// @since 4.12 + bool isDirty() const; + + /// @reimp + void markAsClean(); + + /// @{ configuration object state + /// @reimp + AccessMode accessMode() const; + + /** + * Whether the configuration can be written to. + * + * If @p warnUser is true and the configuration cannot be + * written to (ie: this method returns @c false), a warning + * message box will be shown to the user telling them to + * contact their system administrator to get the problem fixed. + * + * The most likely cause for this method returning @c false + * is that the user does not have write permission for the + * configuration file. + * + * @param warnUser whether to show a warning message to the user + * if the configuration cannot be written to + * + * @returns true if the configuration can be written to, false + * if the configuration cannot be written to + */ + bool isConfigWritable(bool warnUser); + /// @} + + /** + * Copies all entries from this config object to a new config + * object that will save itself to @p file. + * + * The configuration will not actually be saved to @p file + * until the returned object is destroyed, or sync() is called + * on it. + * + * Do not forget to delete the returned KConfig object if + * @p config was 0. + * + * @param file the new config object will save itself to + * @param config if not 0, copy to the given KConfig object rather + * than creating a new one + * + * @return @p config if it was set, otherwise a new KConfig object + */ + KConfig* copyTo(const QString &file, KConfig *config = 0) const; + + /** + * Ensures that the configuration file contains a certain update. + * + * If the configuration file does not contain the update @p id + * as contained in @p updateFile, kconf_update is run to update + * the configuration file. + * + * If you install config update files with critical fixes + * you may wish to use this method to verify that a critical + * update has indeed been performed to catch the case where + * a user restores an old config file from backup that has + * not been updated yet. + * + * @param id the update to check + * @param updateFile the file containing the update + */ + void checkUpdate(const QString &id, const QString &updateFile); + + /** + * Updates the state of this object to match the persistent storage. + */ + void reparseConfiguration(); + + /// @{ extra config files + /** + * Adds the list of configuration sources to the merge stack. + * + * Currently only files are accepted as configuration sources. + * + * The first entry in @p sources is treated as the most general and will + * be overridden by the second entry. The settings in the final entry + * in @p sources will override all the other sources provided in the list. + * + * The settings in @p sources will also be overridden by the sources + * provided by any previous calls to addConfigSources(). + * + * The settings in the global configuration sources will be overridden by + * the sources provided to this method (@see IncludeGlobals). + * All the sources provided to any call to this method will be overridden + * by any files that cascade from the source provided to the constructor + * (@see CascadeConfig), which will in turn be + * overridden by the source provided to the constructor. + * + * Note that only the most specific file, ie: the file provided to the + * constructor, will be written to by this object. + * + * The state is automatically updated by this method, so there is no need to call + * reparseConfiguration(). + * + * @param sources A list of extra config sources. + */ + void addConfigSources(const QStringList &sources); + + /// @} + /// @{ locales + /** + * Returns the current locale. + */ + QString locale() const; + /** + * Sets the locale to @p aLocale. + * + * The global locale is used by default. + * + * @note If set to the empty string, @b no locale will be matched. This effectively disables + * reading translated entries. + * + * @return @c true if locale was changed, @c false if the call had no + * effect (eg: @p aLocale was already the current locale for this + * object) + */ + bool setLocale(const QString& aLocale); + /// @} + + /// @{ defaults + /** + * When set, all readEntry calls return the system-wide (default) values + * instead of the user's settings. + * + * This is off by default. + * + * @param b whether to read the system-wide defaults instead of the + * user's settings + */ + void setReadDefaults(bool b); + /** + * @returns @c true if the system-wide defaults will be read instead of the + * user's settings + */ + bool readDefaults() const; + /// @} + + /// @{ immutability + /// @reimp + bool isImmutable() const; + /// @} + + /// @{ global + /** + * @deprecated + * + * Forces all following write-operations to be performed on @c kdeglobals, + * independent of the @c Global flag in writeEntry(). + * + * @param force true to force writing to kdeglobals + * @see forceGlobal + */ +#ifndef KDE_NO_DEPRECATED + KCONFIGCORE_DEPRECATED void setForceGlobal(bool force); +#endif + /** + * @deprecated + * + * Returns whether all entries are being written to @c kdeglobals. + * + * @return @c true if all entries are being written to @c kdeglobals + * @see setForceGlobal + * @deprecated + */ +#ifndef KDE_NO_DEPRECATED + KCONFIGCORE_DEPRECATED bool forceGlobal() const; +#endif + /// @} + + /// @reimp + QStringList groupList() const; + + /** + * Returns a map (tree) of entries in a particular group. + * + * The entries are all returned as strings. + * + * @param aGroup The group to get entries from. + * + * @return A map of entries in the group specified, indexed by key. + * The returned map may be empty if the group is empty, or not found. + * @see QMap + */ + QMap<QString, QString> entryMap(const QString &aGroup=QString()) const; + + /** + * Sets the name of the application config file. + * @since 5.0 + */ + static void setMainConfigName(const QString& str); + +protected: + virtual bool hasGroupImpl(const QByteArray &group) const; + virtual KConfigGroup groupImpl( const QByteArray &b); + virtual const KConfigGroup groupImpl(const QByteArray &b) const; + virtual void deleteGroupImpl(const QByteArray &group, WriteConfigFlags flags = Normal); + virtual bool isGroupImmutableImpl(const QByteArray& aGroup) const; + + friend class KConfigGroup; + friend class KConfigGroupPrivate; + friend class KSharedConfig; + + /** Virtual hook, used to add new "virtual" functions while maintaining + * binary compatibility. Unused in this class. + */ + virtual void virtual_hook( int id, void* data ); + + KConfigPrivate *const d_ptr; + + KConfig(KConfigPrivate &d); + +private: + friend class KConfigTest; + + QStringList keyList(const QString& aGroup=QString()) const; + + /** + * @internal for KSharedConfig. Could be made public if needed, though. + */ + static QString mainConfigName(); + + Q_DISABLE_COPY(KConfig) + + Q_DECLARE_PRIVATE(KConfig) +}; +Q_DECLARE_OPERATORS_FOR_FLAGS( KConfig::OpenFlags ) + +#endif // KCONFIG_H diff --git a/tier1/kconfig/src/core/kconfig_p.h b/tier1/kconfig/src/core/kconfig_p.h new file mode 100644 index 00000000..e6fb1ca0 --- /dev/null +++ b/tier1/kconfig/src/core/kconfig_p.h @@ -0,0 +1,110 @@ +/* + This file is part of the KDE libraries + Copyright (c) 2006, 2007 Thomas Braxton <kde.braxton@gmail.com> + Copyright (c) 2001 Waldo Bastian <bastian@kde.org> + Copyright (c) 1999 Preston Brown <pbrown@kde.org> + Copyright (c) 1997 Matthias Kalle Dalheimer <kalle@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef KCONFIG_P_H +#define KCONFIG_P_H + +#include "kconfigdata.h" +#include "kconfigbackend.h" +#include "kconfiggroup.h" + +#include <QtCore/QStringList> +#include <QtCore/QStack> +#include <QtCore/QFile> +#include <QtCore/QDir> + +class KConfigPrivate +{ + friend class KConfig; +public: + KConfig::OpenFlags openFlags; + QStandardPaths::StandardLocation resourceType; + + void changeFileName(const QString& fileName); + + // functions for KConfigGroup + bool canWriteEntry(const QByteArray& group, const char* key, bool isDefault=false) const; + QString lookupData(const QByteArray& group, const char* key, KEntryMap::SearchFlags flags, + bool* expand) const; + QByteArray lookupData(const QByteArray& group, const char* key, KEntryMap::SearchFlags flags) const; + + void putData(const QByteArray& group, const char* key, const QByteArray& value, + KConfigBase::WriteConfigFlags flags, bool expand=false); + void revertEntry(const QByteArray& group, const char* key); + QStringList groupList(const QByteArray& group) const; + // copies the entries from @p source to @p otherGroup changing all occurrences + // of @p source with @p destination + void copyGroup(const QByteArray& source, const QByteArray& destination, + KConfigGroup *otherGroup, KConfigBase::WriteConfigFlags flags) const; + QStringList keyListImpl(const QByteArray& theGroup) const; + QSet<QByteArray> allSubGroups(const QByteArray& parentGroup) const; + bool hasNonDeletedEntries(const QByteArray& group) const; + + static QString expandString(const QString& value); + +protected: + QExplicitlySharedDataPointer<KConfigBackend> mBackend; + + KConfigPrivate(KConfig::OpenFlags flags, + QStandardPaths::StandardLocation type); + + virtual ~KConfigPrivate() + { + } + + bool bDynamicBackend:1; // do we own the backend? +private: + bool bDirty:1; + bool bLocaleInitialized:1; + bool bReadDefaults:1; + bool bFileImmutable:1; + bool bForceGlobal:1; + bool bSuppressGlobal:1; + + QString sGlobalFileName; + static bool mappingsRegistered; + + + KEntryMap entryMap; + QString backendType; + QStack<QString> extraFiles; + + QString locale; + QString fileName; + QString etc_kderc; + KConfigBase::AccessMode configState; + + bool wantGlobals() const { return openFlags&KConfig::IncludeGlobals && !bSuppressGlobal; } + bool wantDefaults() const { return openFlags&KConfig::CascadeConfig; } + bool isSimple() const { return openFlags == KConfig::SimpleConfig; } + bool isReadOnly() const { return configState == KConfig::ReadOnly; } + + bool setLocale(const QString& aLocale); + QStringList getGlobalFiles() const; + void parseGlobalFiles(); + void parseConfigFiles(); + void initCustomized(KConfig*); + bool lockLocal(); +}; + +#endif // KCONFIG_P_H diff --git a/tier1/kconfig/src/core/kconfigbackend.cpp b/tier1/kconfig/src/core/kconfigbackend.cpp new file mode 100644 index 00000000..eb92a964 --- /dev/null +++ b/tier1/kconfig/src/core/kconfigbackend.cpp @@ -0,0 +1,123 @@ +/* + This file is part of the KDE libraries + Copyright (c) 2006 Thomas Braxton <brax108@cox.net> + Copyright (c) 1999 Preston Brown <pbrown@kde.org> + Copyright (c) 1997-1999 Matthias Kalle Dalheimer <kalle@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "kconfigbackend.h" + +#include <QtCore/QDateTime> +#include <QtCore/QStringList> +#include <QtCore/QDir> +#include <QtCore/QFileInfo> +#include <QtCore/QHash> +#include <QtCore/QDebug> + +#include "kconfig.h" +#include "kconfigini_p.h" +#include "kconfigdata.h" + +typedef QExplicitlySharedDataPointer<KConfigBackend> BackendPtr; + +class KConfigBackend::Private +{ +public: + qint64 size; + QDateTime lastModified; + QString localFileName; + + static QString whatSystem(const QString& /*fileName*/) + { + return QLatin1String("INI"); + } +}; + + +void KConfigBackend::registerMappings(const KEntryMap& /*entryMap*/) +{ +} + +BackendPtr KConfigBackend::create(const QString& file, const QString& sys) +{ + //qDebug() << "creating a backend for file" << file << "with system" << sys; + const QString system = (sys.isEmpty() ? Private::whatSystem(file) : sys); + KConfigBackend* backend = 0; + +#if 0 // TODO port to Qt5 plugin loading + if (system.compare(QLatin1String("INI"), Qt::CaseInsensitive) != 0) { + const QString constraint = QString::fromLatin1("[X-KDE-PluginInfo-Name] ~~ '%1'").arg(system); + KService::List offers = KServiceTypeTrader::self()->query(QLatin1String("KConfigBackend"), constraint); + + //qDebug() << "found" << offers.count() << "offers for KConfigBackend plugins with name" << system; + foreach (const KService::Ptr& offer, offers) { + backend = offer->createInstance<KConfigBackend>(0); + if (backend) { + //qDebug() << "successfully created a backend for" << system; + backend->setFilePath(file); + return BackendPtr(backend); + } + } // foreach offers + } +#endif + + //qDebug() << "default creation of the Ini backend"; + backend = new KConfigIniBackend; + backend->setFilePath(file); + return BackendPtr(backend); +} + +KConfigBackend::KConfigBackend() + : d(new Private) +{ +} + +KConfigBackend::~KConfigBackend() +{ + delete d; +} + +QDateTime KConfigBackend::lastModified() const +{ + return d->lastModified; +} + +void KConfigBackend::setLastModified(const QDateTime& dt) +{ + d->lastModified = dt; +} + +qint64 KConfigBackend::size() const +{ + return d->size; +} + +void KConfigBackend::setSize(qint64 sz) +{ + d->size = sz; +} + +QString KConfigBackend::filePath() const +{ + return d->localFileName; +} + +void KConfigBackend::setLocalFilePath(const QString& file) +{ + d->localFileName = file; +} diff --git a/tier1/kconfig/src/core/kconfigbackend.desktop b/tier1/kconfig/src/core/kconfigbackend.desktop new file mode 100644 index 00000000..bebcbff6 --- /dev/null +++ b/tier1/kconfig/src/core/kconfigbackend.desktop @@ -0,0 +1,86 @@ +[Desktop Entry] +Type=ServiceType +X-KDE-ServiceType=KConfigBackend + +Comment=Storage backend for KConfig +Comment[ar]=خلفية الحفظ لـ KConfig +Comment[as]=KConfig ৰ বাবে ভঁৰালৰ বেকএন্ড +Comment[ast]=Infraestructura d'atroxamientu pa KConfig +Comment[be@latin]=Słužba schovišča dla systemy „KConfig” +Comment[bg]=Storage backend for KConfig +Comment[bn]=KConfig-এর স্টোরেজ ব্যাকেন্ড +Comment[bn_IN]=KConfig-র জন্য ব্যবহৃত ব্যাক-এন্ড সংগ্রহস্থল +Comment[bs]=Skladišna pozadina za K‑konfig +Comment[ca]=Dorsal d'emmagatzematge per al KConfig +Comment[ca@valencia]=Dorsal d'emmagatzematge per al KConfig +Comment[cs]=Úložiště pro KConfig +Comment[csb]=Zôpisownô zbiérnica dlô KConfig +Comment[da]=Lagringsmotor til KConfig +Comment[de]=Speicher-Unterstützung für KConfig +Comment[el]=Σύστημα υποστήριξης αποθήκευσης για το KConfig +Comment[en_GB]=Storage backend for KConfig +Comment[es]=Motor de almacenamiento para KConfig +Comment[et]=KConfigi salvestamise taustaprogramm +Comment[eu]=KConfig-en biltegiratze euskarria +Comment[fi]=Asetusvaraston taustaosa +Comment[fr]=Module de stockage pour KConfig +Comment[fy]=Opslach efterein foar KConfig +Comment[ga]=Inneall stórais KConfig +Comment[gl]=Infraestrutura de almacenaxe para KConfig +Comment[gu]=KConfig માટે સંગ્રહ પાશ્ર્વભાગ +Comment[he]=מנוע שמירה עבור KConfig +Comment[hne]=के-कानफिग बर भंडार बैकएण्ड +Comment[hr]=Skladišna pozadina za KConfig +Comment[hsb]=składowanski backend za KConfig +Comment[hu]=Tároló a KConfighoz +Comment[hy]=Բահեստի հետևի մասը KConfig-ի համար +Comment[ia]=Retro-administration de immagazinage (storage) pro Kconfig +Comment[id]=Backend penyimpanan untuk KConfig +Comment[is]=Geymslubakendi fyrir KConfig +Comment[it]=Backend di archiviazione per KConfig +Comment[ja]=KConfig のストレージバックエンド +Comment[kk]=KConfig үшін сақтау тетігі +Comment[km]=កម្មវិធីខាងក្រោយការផ្ទុកសម្រាប់ KConfig +Comment[kn]=ಕೆಕಾನ್ಫಿಗ್ ಗೆ ಸಂಗ್ರಹಣಾ ಹಿಂಬದಿ (ಬಾಕೆಂಡ್) +Comment[ko]=KConfig의 저장소 백엔드 +Comment[ku]=Embara ser-dawî ji bo KVeavakirin +Comment[lt]=KConfig saugojimo sąsaja +Comment[lv]=KConfig glabāšanas aizmugure +Comment[mai]=KConfig क' लेल भंडारक बैकेंड +Comment[ml]=കെകോണ്ഫിഗിനുളള സ്റ്റോറേജ് ബാക്കെന്ഡ് +Comment[mr]=के-कॉन्फिग करिता संचयन बॅकएन्ड +Comment[ms]=Storan belakang untuk KConfig +Comment[nb]=Bakgrunnslagring for KConfig +Comment[nds]=Spieker-Hülpprogramm för KConfig +Comment[nl]=Opslagbackend voor KConfig +Comment[nn]=Lagringsmotor for KConfig +Comment[or]=KConfig ପାଇଁ ଭଣ୍ଡାର ପଛ ପାଖ +Comment[pa]=KConfig ਲਈ ਸਟੋਰੇਜ਼ ਬੈਕਐਂਡ +Comment[pl]=Przechowywanie danych dla KConfig +Comment[pt]=Armazenamento da infra-estrutura do KConfig +Comment[pt_BR]=Infraestrutura de armazenamento para o KConfig +Comment[ro]=Suport de stocare pentru KConfig +Comment[ru]=Модуль хранения параметров KConfig +Comment[se]=KConfig vurkenduogáš +Comment[si]=KConfig සඳහා ගබඩා පසුඈදුම +Comment[sk]=Úložisko pre KConfig +Comment[sl]=Zaledje za shranjevanje v KConfig +Comment[sq]=Mbështetëse Ruajtëse për KConfig +Comment[sr]=Складишна позадина за К‑конфиг +Comment[sr@ijekavian]=Складишна позадина за К‑конфиг +Comment[sr@ijekavianlatin]=Skladišna pozadina za KConfig +Comment[sr@latin]=Skladišna pozadina za KConfig +Comment[sv]=Lagringsgränssnitt för KConfig +Comment[ta]=கேவடிவமைப்பிற்கான பின்னணி சேமிப்பகம் +Comment[tg]=Пуштибонии захирагоҳ барои KConfig +Comment[th]=โปรแกรมเบื้องหลังพื้นที่จัดเก็บข้อมูลสำหรับ KConfig +Comment[tr]=KConfig için Depolama Arka Ucu +Comment[tt]=KConfig өчен саклау бэкенды +Comment[ug]=KConfig نىڭ ساقلاش ئارقا ئۇچى +Comment[uk]=Засіб збереження для KConfig +Comment[vi]=Hậu trường lưu trữ cho KConfig +Comment[wa]=Bouye di fond di stocaedje po KConfig +Comment[x-test]=xxStorage backend for KConfigxx +Comment[zh_CN]=KConfig 存储后端 +Comment[zh_TW]=KConfig 儲存後端介面 + diff --git a/tier1/kconfig/src/core/kconfigbackend.h b/tier1/kconfig/src/core/kconfigbackend.h new file mode 100644 index 00000000..49239e66 --- /dev/null +++ b/tier1/kconfig/src/core/kconfigbackend.h @@ -0,0 +1,211 @@ +/* + This file is part of the KDE libraries + Copyright (c) 2006, 2007 Thomas Braxton <kde.braxton@gmail.com> + Copyright (c) 1999 Preston Brown <pbrown@kde.org> + Portions copyright (c) 1997 Matthias Kalle Dalheimer <kalle@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef KCONFIGBACKEND_H +#define KCONFIGBACKEND_H + +#include <QtCore/QObject> +#include <QtCore/QString> +#include <QExplicitlySharedDataPointer> + +#include <kconfigcore_export.h> +#include <kconfigbase.h> + +class KEntryMap; +class QFile; +class QByteArray; +class QDateTime; + +/** + * \class KConfigBackend kconfigbackend.h <KConfigBackend> + * + * Provides the implementation for accessing configuration sources. + * + * KDELibs only provides an INI backend, but this class can be used + * to create plugins that allow access to other file formats and + * configuration systems. + */ +class KCONFIGCORE_EXPORT KConfigBackend : public QObject, public QSharedData +{ + Q_OBJECT + Q_FLAGS(ParseOption) + Q_FLAGS(WriteOption) + +public: + /** + * Creates a new KConfig backend. + * + * If no @p system is given, or the given @p system is unknown, this method tries + * to determine the correct backend to use. + * + * @param fileName the absolute file name of the configuration file + * @param system the configuration system to use + * @return a KConfigBackend object to be used with KConfig + */ + static QExplicitlySharedDataPointer<KConfigBackend> create(const QString& fileName = QString(), + const QString& system = QString()); + + /** + * Registers mappings from directories/files to configuration systems + * + * Allows you to tell KConfigBackend that create() should use a particular + * backend for a particular file or directory. + * + * @warning currently does nothing + * + * @param entryMap the KEntryMap to build the mappings from + */ + static void registerMappings(const KEntryMap& entryMap); + + /** Destroys the backend */ + virtual ~KConfigBackend(); + + /** Allows the behaviour of parseConfig() to be tuned */ + enum ParseOption { + ParseGlobal = 1, /// entries should be marked as @em global + ParseDefaults = 2, /// entries should be marked as @em default + ParseExpansions = 4 /// entries are allowed to be marked as @em expandable + }; + /// @typedef typedef QFlags<ParseOption> ParseOptions + Q_DECLARE_FLAGS(ParseOptions, ParseOption) + + /** Allows the behaviour of writeConfig() to be tuned */ + enum WriteOption { + WriteGlobal = 1 /// only write entries marked as "global" + }; + /// @typedef typedef QFlags<WriteOption> WriteOptions + Q_DECLARE_FLAGS(WriteOptions, WriteOption) + + /** Return value from parseConfig() */ + enum ParseInfo { + ParseOk, /// the configuration was opened read/write + ParseImmutable, /// the configuration is @em immutable + ParseOpenError /// the configuration could not be opened + }; + + /** + * Read persistent storage + * + * @param locale the locale to read entries for (if the backend supports localized entries) + * @param pWriteBackMap the KEntryMap where the entries are placed + * @param options @see ParseOptions + * @return @see ParseInfo + */ + virtual ParseInfo parseConfig(const QByteArray& locale, + KEntryMap& pWriteBackMap, + ParseOptions options = ParseOptions()) = 0; + + /** + * Write the @em dirty entries to permanent storage + * + * @param locale the locale to write entries for (if the backend supports localized entries) + * @param entryMap the KEntryMap containing the config object's entries. + * @param options @see WriteOptions + * + * @return @c true if the write was successful, @c false if writing the configuration failed + */ + virtual bool writeConfig(const QByteArray& locale, KEntryMap& entryMap, + WriteOptions options) = 0; + + /** + * If isWritable() returns false, writeConfig() will always fail. + * + * @return @c true if the configuration is writable, @c false if it is immutable + */ + virtual bool isWritable() const = 0; + /** + * When isWritable() returns @c false, return an error message to + * explain to the user why saving configuration will not work. + * + * The return value when isWritable() returns @c true is undefined. + * + * @returns a translated user-visible explanation for the configuration + * object not being writable + */ + virtual QString nonWritableErrorMessage() const = 0; + /** + * @return the read/write status of the configuration object + * + * @see KConfigBase::AccessMode + */ + virtual KConfigBase::AccessMode accessMode() const = 0; + /** + * Create the enclosing object of the configuration object + * + * For example, if the configuration object is a file, this should create + * the parent directory. + */ + virtual void createEnclosing() = 0; + + /** + * Set the file path. + * + * @note @p path @b MUST be @em absolute. + * + * @param path the absolute file path + */ + virtual void setFilePath(const QString& path) = 0; + + /** + * Lock the file + */ + virtual bool lock() = 0; + /** + * Release the lock on the file + */ + virtual void unlock() = 0; + /** + * @return @c true if the file is locked, @c false if it is not locked + */ + virtual bool isLocked() const = 0; + + /** + * @return the date and time when the object was last modified + */ + QDateTime lastModified() const; + /** @return the absolute path to the object */ + QString filePath() const; + /** @return the size of the object */ + qint64 size() const; + +protected: + KConfigBackend(); + void setLastModified(const QDateTime& dt); + void setSize(qint64 sz); + void setLocalFilePath(const QString& file); + +private: + class Private; + Private *const d; +}; + +Q_DECLARE_OPERATORS_FOR_FLAGS(KConfigBackend::ParseOptions) +Q_DECLARE_OPERATORS_FOR_FLAGS(KConfigBackend::WriteOptions) + +/** + * Register a KConfig backend when it is contained in a loadable module + */ +#define K_EXPORT_KCONFIGBACKEND(libname, classname) \ +K_PLUGIN_FACTORY(factory, registerPlugin<classname>();) + + +#endif // KCONFIGBACKEND_H diff --git a/tier1/kconfig/src/core/kconfigbase.cpp b/tier1/kconfig/src/core/kconfigbase.cpp new file mode 100644 index 00000000..4be7ac23 --- /dev/null +++ b/tier1/kconfig/src/core/kconfigbase.cpp @@ -0,0 +1,112 @@ +/* + This file is part of the KDE libraries + Copyright (c) 2006, 2007 Thomas Braxton <kde.braxton@gmail.com> + Copyright (c) 1999 Preston Brown <pbrown@kde.org> + Copyright (c) 1997-1999 Matthias Kalle Dalheimer <kalle@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "kconfigbase.h" + +#include "kconfiggroup.h" + +#include <QtCore/QString> + +bool KConfigBase::hasGroup(const QString &group) const +{ + return hasGroupImpl(group.toUtf8()); +} + +bool KConfigBase::hasGroup(const char *group) const +{ + return hasGroupImpl(QByteArray(group)); +} + +bool KConfigBase::hasGroup(const QByteArray &group) const +{ + return hasGroupImpl(group); +} + +KConfigGroup KConfigBase::group( const QByteArray &b) +{ + return groupImpl(b); +} + +KConfigGroup KConfigBase::group( const QString &str) +{ + return groupImpl(str.toUtf8()); +} + +KConfigGroup KConfigBase::group( const char *str) +{ + return groupImpl(QByteArray(str)); +} + +const KConfigGroup KConfigBase::group( const QByteArray &b ) const +{ + return groupImpl(b); +} + +const KConfigGroup KConfigBase::group( const QString &s ) const +{ + return groupImpl(s.toUtf8()); +} + +const KConfigGroup KConfigBase::group( const char *s ) const +{ + return groupImpl(QByteArray(s)); +} + +void KConfigBase::deleteGroup(const QByteArray &group, WriteConfigFlags flags) +{ + deleteGroupImpl(group, flags); +} + +void KConfigBase::deleteGroup(const QString &group, WriteConfigFlags flags) +{ + deleteGroupImpl(group.toUtf8(), flags); +} + +void KConfigBase::deleteGroup(const char *group, WriteConfigFlags flags) +{ + deleteGroupImpl(QByteArray(group), flags); +} + +bool KConfigBase::isGroupImmutable(const QByteArray& aGroup) const +{ + return isGroupImmutableImpl(aGroup); +} + +bool KConfigBase::isGroupImmutable(const QString& aGroup) const +{ + return isGroupImmutableImpl(aGroup.toUtf8()); +} + + +bool KConfigBase::isGroupImmutable(const char *aGroup) const +{ + return isGroupImmutableImpl(QByteArray(aGroup)); +} + +KConfigBase::~KConfigBase() +{} + +KConfigBase::KConfigBase() +{} + +void KConfigBase::virtual_hook(int , void *) +{} diff --git a/tier1/kconfig/src/core/kconfigbase.h b/tier1/kconfig/src/core/kconfigbase.h new file mode 100644 index 00000000..782ff4b6 --- /dev/null +++ b/tier1/kconfig/src/core/kconfigbase.h @@ -0,0 +1,184 @@ +/* + This file is part of the KDE libraries + Copyright (c) 2006, 2007 Thomas Braxton <kde.braxton@gmail.com> + Copyright (c) 2001 Waldo Bastian <bastian@kde.org> + Copyright (c) 1999 Preston Brown <pbrown@kde.org> + Copyright (c) 1997 Matthias Kalle Dalheimer <kalle@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef KCONFIGBASE_H +#define KCONFIGBASE_H + +#include <kconfigcore_export.h> + +#include <QtCore/QtGlobal> + +class QStringList; +class KConfigGroup; +class KConfigBasePrivate; + +/** + * \class KConfigBase kconfigbase.h <KConfigBase> + */ +class KCONFIGCORE_EXPORT KConfigBase +{ +public: + /** + * Flags to control write entry + */ + enum WriteConfigFlag + { + Persistent = 0x01, + /**< + * Save this entry when saving the config object. + */ + Global = 0x02, + /**< + * Save the entry to the global %KDE config file instead of the + * application specific config file. + */ + Localized = 0x04, + /**< + * Add the locale tag to the key when writing it. + */ + Normal=Persistent + /**< + * Save the entry to the application specific config file without + * a locale tag. This is the default. + */ + + }; + Q_DECLARE_FLAGS(WriteConfigFlags, WriteConfigFlag) + + /** + * Destructs the KConfigBase object. + */ + virtual ~KConfigBase(); + + /** + * Returns a list of groups that are known about. + * + * @return The list of groups. + **/ + virtual QStringList groupList() const = 0; + + /** + * Returns true if the specified group is known about. + * + * @param group The group to search for. + * @return true if the group exists. + */ + bool hasGroup(const QString &group) const; + bool hasGroup(const char *group) const; + bool hasGroup(const QByteArray &group) const; + + /** + * Returns an object for the named subgroup. + * + * @param group the group to open. Pass a null string on to the KConfig + * object to obtain a handle on the root group. + * @return The list of groups. + **/ + KConfigGroup group(const QByteArray &group); + KConfigGroup group(const QString &group); + KConfigGroup group(const char *group); + + /** + * @overload + **/ + const KConfigGroup group(const QByteArray &group) const; + const KConfigGroup group(const QString &group) const; + const KConfigGroup group(const char *group) const; + + /** + * Delete @p aGroup. This marks @p aGroup as @em deleted in the config object. This effectively + * removes any cascaded values from config files earlier in the stack. + */ + void deleteGroup(const QByteArray &group, WriteConfigFlags flags = Normal); + void deleteGroup(const QString &group, WriteConfigFlags flags = Normal); + void deleteGroup(const char *group, WriteConfigFlags flags = Normal); + + /** + * Syncs the configuration object that this group belongs to. + * Unrelated concurrent changes to the same file are merged and thus + * not overwritten. Note however, that this object is @em not automatically + * updated with those changes. + */ + virtual bool sync() = 0; + + /** + * Reset the dirty flags of all entries in the entry map, so the + * values will not be written to disk on a later call to sync(). + */ + virtual void markAsClean() = 0; + + /** + * Possible return values for accessMode(). + */ + enum AccessMode { NoAccess, ReadOnly, ReadWrite }; + + /** + * Returns the access mode of the app-config object. + * + * Possible return values + * are NoAccess (the application-specific config file could not be + * opened neither read-write nor read-only), ReadOnly (the + * application-specific config file is opened read-only, but not + * read-write) and ReadWrite (the application-specific config + * file is opened read-write). + * + * @return the access mode of the app-config object + */ + virtual AccessMode accessMode() const = 0; + + /** + * Checks whether this configuration object can be modified. + * @return whether changes may be made to this configuration object. + */ + virtual bool isImmutable() const = 0; + + /** + * Can changes be made to the entries in @p aGroup? + * + * @param aGroup The group to check for immutability. + * @return @c false if the entries in @p aGroup can be modified. + */ + bool isGroupImmutable(const QByteArray& aGroup) const; + bool isGroupImmutable(const QString& aGroup) const; + bool isGroupImmutable(const char *aGroup) const; + +protected: + KConfigBase(); + + virtual bool hasGroupImpl(const QByteArray &group) const = 0; + virtual KConfigGroup groupImpl( const QByteArray &b) = 0; + virtual const KConfigGroup groupImpl(const QByteArray &b) const = 0; + virtual void deleteGroupImpl(const QByteArray &group, WriteConfigFlags flags = Normal) = 0; + virtual bool isGroupImmutableImpl(const QByteArray& aGroup) const = 0; + + /** Virtual hook, used to add new "virtual" functions while maintaining + * binary compatibility. Unused in this class. + */ + virtual void virtual_hook( int id, void* data ); +}; + +Q_DECLARE_OPERATORS_FOR_FLAGS(KConfigBase::WriteConfigFlags) + + + +#endif // KCONFIG_H diff --git a/tier1/kconfig/src/core/kconfigbase_p.h b/tier1/kconfig/src/core/kconfigbase_p.h new file mode 100644 index 00000000..c1066267 --- /dev/null +++ b/tier1/kconfig/src/core/kconfigbase_p.h @@ -0,0 +1,30 @@ +/* + This file is part of the KDE libraries + Copyright (c) 1999 Preston Brown <pbrown@kde.org> + Copyright (C) 1997 Matthias Kalle Dalheimer <kalle@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef KCONFIGBASE_P_H +#define KCONFIGBASE_P_H + +#include <QtCore/QSharedData> + +class KConfigBasePrivate : public QSharedData +{ +}; +#endif diff --git a/tier1/kconfig/src/core/kconfigdata.cpp b/tier1/kconfig/src/core/kconfigdata.cpp new file mode 100644 index 00000000..74a068be --- /dev/null +++ b/tier1/kconfig/src/core/kconfigdata.cpp @@ -0,0 +1,317 @@ +/* + This file is part of the KDE libraries + Copyright (c) 2006, 2007 Thomas Braxton <kde.braxton@gmail.com> + Copyright (c) 1999-2000 Preston Brown <pbrown@kde.org> + Copyright (C) 1996-2000 Matthias Kalle Dalheimer <kalle@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include <kconfigdata.h> + +QDebug operator<<(QDebug dbg, const KEntryKey& key) +{ + dbg.nospace() << "[" << key.mGroup << ", " << key.mKey << (key.bLocal?" localized":"") << + (key.bDefault?" default":"") << (key.bRaw?" raw":"") << "]"; + return dbg.space(); +} + +QDebug operator<<(QDebug dbg, const KEntry& entry) +{ + dbg.nospace() << "[" << entry.mValue << (entry.bDirty?" dirty":"") << + (entry.bGlobal?" global":"") << (entry.bImmutable?" immutable":"") << + (entry.bDeleted?" deleted":"") << (entry.bReverted?" reverted":"") << + (entry.bExpand?" expand":"") << "]"; + + return dbg.space(); +} + +QMap< KEntryKey, KEntry >::Iterator KEntryMap::findExactEntry(const QByteArray& group, const QByteArray& key, KEntryMap::SearchFlags flags) +{ + KEntryKey theKey(group, key, bool(flags&SearchLocalized), bool(flags&SearchDefaults)); + return find(theKey); +} + +QMap< KEntryKey, KEntry >::Iterator KEntryMap::findEntry(const QByteArray& group, const QByteArray& key, KEntryMap::SearchFlags flags) +{ + KEntryKey theKey(group, key, false, bool(flags&SearchDefaults)); + + // try the localized key first + if (flags&SearchLocalized) { + theKey.bLocal = true; + + Iterator it = find(theKey); + if (it != end()) + return it; + + theKey.bLocal = false; + } + return find(theKey); +} + +QMap< KEntryKey, KEntry >::ConstIterator KEntryMap::findEntry(const QByteArray& group, const QByteArray& key, KEntryMap::SearchFlags flags) const +{ + KEntryKey theKey(group, key, false, bool(flags&SearchDefaults)); + + // try the localized key first + if (flags&SearchLocalized) { + theKey.bLocal = true; + + ConstIterator it = find(theKey); + if (it != constEnd()) + return it; + + theKey.bLocal = false; + } + return find(theKey); +} + +bool KEntryMap::setEntry(const QByteArray& group, const QByteArray& key, const QByteArray& value, KEntryMap::EntryOptions options) +{ + KEntryKey k; + KEntry e; + bool newKey = false; + + const Iterator it = findExactEntry(group, key, SearchFlags(options>>16)); + + if (key.isEmpty()) { // inserting a group marker + k.mGroup = group; + e.bImmutable = (options&EntryImmutable); + if (options&EntryDeleted) { + qWarning("Internal KConfig error: cannot mark groups as deleted"); + } + if(it == end()) { + insert(k, e); + return true; + } else if(it.value() == e) { + return false; + } + + it.value() = e; + return true; + } + + + if (it != end()) { + if (it->bImmutable) + return false; // we cannot change this entry. Inherits group immutability. + k = it.key(); + e = *it; + //qDebug() << "found existing entry for key" << k; + } else { + // make sure the group marker is in the map + KEntryMap const *that = this; + ConstIterator cit = that->findEntry(group); + if (cit == constEnd()) + insert(KEntryKey(group), KEntry()); + else if (cit->bImmutable) + return false; // this group is immutable, so we cannot change this entry. + + k = KEntryKey(group, key); + newKey = true; + } + + // set these here, since we may be changing the type of key from the one we found + k.bLocal = (options&EntryLocalized); + k.bDefault = (options&EntryDefault); + k.bRaw = (options&EntryRawKey); + + e.mValue = value; + e.bDirty = e.bDirty || (options&EntryDirty); + e.bGlobal = (options&EntryGlobal); //we can't use || here, because changes to entries in + //kdeglobals would be written to kdeglobals instead + //of the local config file, regardless of the globals flag + e.bImmutable = e.bImmutable || (options&EntryImmutable); + if (value.isNull()) + e.bDeleted = e.bDeleted || (options&EntryDeleted); + else + e.bDeleted = false; // setting a value to a previously deleted entry + e.bExpand = (options&EntryExpansion); + e.bReverted = false; + + if(newKey) + { + //qDebug() << "inserting" << k << "=" << value; + insert(k, e); + if(k.bDefault) + { + k.bDefault = false; + //qDebug() << "also inserting" << k << "=" << value; + insert(k, e); + } + // TODO check for presence of unlocalized key + return true; + } else { +// KEntry e2 = it.value(); + if(it.value() != e) + { + //qDebug() << "changing" << k << "from" << e.mValue << "to" << value; + it.value() = e; + if(k.bDefault) + { + KEntryKey nonDefaultKey(k); + nonDefaultKey.bDefault = false; + insert(nonDefaultKey, e); + } + if (!(options & EntryLocalized)) { + KEntryKey theKey(group, key, true, false); + //qDebug() << "non-localized entry, remove localized one:" << theKey; + remove(theKey); + if (k.bDefault) { + theKey.bDefault = true; + remove(theKey); + } + } + return true; + } else { + //qDebug() << k << "was already set to" << e.mValue; + if (!(options & EntryLocalized)) { + //qDebug() << "unchanged non-localized entry, remove localized one."; + KEntryKey theKey(group, key, true, false); + bool ret = false; + Iterator cit = find(theKey); + if (cit != end()) { + erase(cit); + ret = true; + } + if (k.bDefault) { + theKey.bDefault = true; + Iterator cit = find(theKey); + if (cit != end()) { + erase(cit); + return true; + } + } + return ret; + } + //qDebug() << "localized entry, unchanged, return false"; + // When we are writing a default, we know that the non- + // default is the same as the default, so we can simply + // use the same branch. + return false; + } + } +} + +QString KEntryMap::getEntry(const QByteArray& group, const QByteArray& key, const QString& defaultValue, KEntryMap::SearchFlags flags, bool* expand) const +{ + const ConstIterator it = findEntry(group, key, flags); + QString theValue = defaultValue; + + if (it != constEnd() && !it->bDeleted) { + if (!it->mValue.isNull()) { + const QByteArray data=it->mValue; + theValue = QString::fromUtf8(data.constData(), data.length()); + if (expand) + *expand = it->bExpand; + } + } + + return theValue; +} + +bool KEntryMap::hasEntry(const QByteArray& group, const QByteArray& key, KEntryMap::SearchFlags flags) const +{ + const ConstIterator it = findEntry(group, key, flags); + if (it == constEnd()) + return false; + if (it->bDeleted) + return false; + if (key.isNull()) { // looking for group marker + return it->mValue.isNull(); + } + // if it->bReverted, we'll just return true; the real answer depends on lookup up with SearchDefaults, though. + return true; +} + +bool KEntryMap::getEntryOption(const QMap< KEntryKey, KEntry >::ConstIterator& it, KEntryMap::EntryOption option) const +{ + if (it != constEnd()) { + switch (option) { + case EntryDirty: + return it->bDirty; + case EntryLocalized: + return it.key().bLocal; + case EntryGlobal: + return it->bGlobal; + case EntryImmutable: + return it->bImmutable; + case EntryDeleted: + return it->bDeleted; + case EntryExpansion: + return it->bExpand; + default: + break; // fall through + } + } + + return false; +} + +void KEntryMap::setEntryOption(QMap< KEntryKey, KEntry >::Iterator it, KEntryMap::EntryOption option, bool bf) +{ + if (it != end()) { + switch (option) { + case EntryDirty: + it->bDirty = bf; + break; + case EntryGlobal: + it->bGlobal = bf; + break; + case EntryImmutable: + it->bImmutable = bf; + break; + case EntryDeleted: + it->bDeleted = bf; + break; + case EntryExpansion: + it->bExpand = bf; + break; + default: + break; // fall through + } + } +} + +bool KEntryMap::revertEntry(const QByteArray& group, const QByteArray& key, KEntryMap::SearchFlags flags) +{ + Q_ASSERT((flags & KEntryMap::SearchDefaults) == 0); + Iterator entry = findEntry(group, key, flags); + if (entry != end()) { + //qDebug() << "reverting" << entry.key() << " = " << entry->mValue; + if (entry->bReverted) { // already done before + return false; + } + + KEntryKey defaultKey(entry.key()); + defaultKey.bDefault = true; + //qDebug() << "looking up default entry with key=" << defaultKey; + const ConstIterator defaultEntry = constFind(defaultKey); + if (defaultEntry != constEnd()) { + Q_ASSERT(defaultEntry.key().bDefault); + //qDebug() << "found, update entry"; + *entry = *defaultEntry; // copy default value, for subsequent lookups + } else { + entry->mValue = QByteArray(); + } + entry->bDirty = true; + entry->bReverted = true; // skip it when writing out to disk + + //qDebug() << "Here's what we have now:" << *this; + return true; + } + return false; +} diff --git a/tier1/kconfig/src/core/kconfigdata.h b/tier1/kconfig/src/core/kconfigdata.h new file mode 100644 index 00000000..f7ad81b9 --- /dev/null +++ b/tier1/kconfig/src/core/kconfigdata.h @@ -0,0 +1,237 @@ +/* + This file is part of the KDE libraries + Copyright (c) 2006, 2007 Thomas Braxton <kde.braxton@gmail.com> + Copyright (c) 1999-2000 Preston Brown <pbrown@kde.org> + Copyright (C) 1996-2000 Matthias Kalle Dalheimer <kalle@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef KCONFIGDATA_H +#define KCONFIGDATA_H + +#include <QtCore/QByteArray> +#include <QtCore/QString> +#include <QtCore/QMap> +#include <QtCore/QDebug> + +/** + * map/dict/list config node entry. + * @internal + */ +struct KEntry +{ + /** Constructor. @internal */ + KEntry() + : mValue(), bDirty(false), + bGlobal(false), bImmutable(false), bDeleted(false), bExpand(false), bReverted(false) {} + /** @internal */ + QByteArray mValue; + /** + * Must the entry be written back to disk? + */ + bool bDirty :1; + /** + * Entry should be written to the global config file + */ + bool bGlobal:1; + /** + * Entry can not be modified. + */ + bool bImmutable:1; + /** + * Entry has been deleted. + */ + bool bDeleted:1; + /** + * Whether to apply dollar expansion or not. + */ + bool bExpand:1; + /** + * Entry has been reverted to its default value (from a more global file). + */ + bool bReverted:1; +}; + +// These operators are used to check whether an entry which is about +// to be written equals the previous value. As such, this intentionally +// omits the dirty flag from the comparison. +inline bool operator ==(const KEntry &k1, const KEntry &k2) +{ + return k1.bGlobal == k2.bGlobal && k1.bImmutable == k2.bImmutable + && k1.bDeleted == k2.bDeleted && k1.bExpand == k2.bExpand + && k1.mValue == k2.mValue; +} + +inline bool operator !=(const KEntry &k1, const KEntry &k2) +{ + return !(k1 == k2); +} + +/** + * key structure holding both the actual key and the group + * to which it belongs. + * @internal + */ +struct KEntryKey +{ + /** Constructor. @internal */ + KEntryKey(const QByteArray& _group = QByteArray(), + const QByteArray& _key = QByteArray(), bool isLocalized=false, bool isDefault=false) + : mGroup(_group), mKey(_key), bLocal(isLocalized), bDefault(isDefault), bRaw(false) + { ; } + /** + * The "group" to which this EntryKey belongs + */ + QByteArray mGroup; + /** + * The _actual_ key of the entry in question + */ + QByteArray mKey; + /** + * Entry is localised or not + */ + bool bLocal :1; + /** + * Entry indicates if this is a default value. + */ + bool bDefault:1; + /** @internal + * Key is a raw unprocessed key. + * @warning this should only be set during merging, never for normal use. + */ + bool bRaw:1; +}; + +/** + * Compares two KEntryKeys (needed for QMap). The order is localized, localized-default, + * non-localized, non-localized-default + * @internal + */ +inline bool operator <(const KEntryKey &k1, const KEntryKey &k2) +{ + int result = qstrcmp(k1.mGroup, k2.mGroup); + if (result != 0) { + return result < 0; + } + + result = qstrcmp(k1.mKey, k2.mKey); + if (result != 0) { + return result < 0; + } + + if (k1.bLocal != k2.bLocal) + return k1.bLocal; + return (!k1.bDefault && k2.bDefault); +} + + +QDebug operator<<(QDebug dbg, const KEntryKey& key); +QDebug operator<<(QDebug dbg, const KEntry& entry); + +/** + * \relates KEntry + * type specifying a map of entries (key,value pairs). + * The keys are actually a key in a particular config file group together + * with the group name. + * @internal + */ +class KEntryMap : public QMap<KEntryKey, KEntry> +{ + public: + enum SearchFlag { + SearchDefaults=1, + SearchLocalized=2 + }; + Q_DECLARE_FLAGS(SearchFlags, SearchFlag) + + enum EntryOption { + EntryDirty=1, + EntryGlobal=2, + EntryImmutable=4, + EntryDeleted=8, + EntryExpansion=16, + EntryRawKey=32, + EntryDefault=(SearchDefaults<<16), + EntryLocalized=(SearchLocalized<<16) + }; + Q_DECLARE_FLAGS(EntryOptions, EntryOption) + + Iterator findExactEntry(const QByteArray& group, const QByteArray& key = QByteArray(), + SearchFlags flags = SearchFlags()); + + Iterator findEntry(const QByteArray& group, const QByteArray& key = QByteArray(), + SearchFlags flags = SearchFlags()); + + ConstIterator findEntry(const QByteArray& group, const QByteArray& key = QByteArray(), + SearchFlags flags = SearchFlags()) const; + + /** + * Returns true if the entry gets dirtied or false in other case + */ + bool setEntry(const QByteArray& group, const QByteArray& key, + const QByteArray& value, EntryOptions options); + + void setEntry(const QByteArray& group, const QByteArray& key, + const QString & value, EntryOptions options) + { + setEntry(group, key, value.toUtf8(), options); + } + + QString getEntry(const QByteArray& group, const QByteArray& key, + const QString & defaultValue = QString(), + SearchFlags flags = SearchFlags(), + bool * expand=0) const; + + bool hasEntry(const QByteArray& group, const QByteArray& key = QByteArray(), + SearchFlags flags = SearchFlags()) const; + + bool getEntryOption(const ConstIterator& it, EntryOption option) const; + bool getEntryOption(const QByteArray& group, const QByteArray& key, + SearchFlags flags, EntryOption option) const + { + return getEntryOption(findEntry(group, key, flags), option); + } + + void setEntryOption(Iterator it, EntryOption option, bool bf); + void setEntryOption(const QByteArray& group, const QByteArray& key, SearchFlags flags, + EntryOption option, bool bf) + { + setEntryOption(findEntry(group, key, flags), option, bf); + } + + bool revertEntry(const QByteArray& group, const QByteArray& key, SearchFlags flags=SearchFlags()); +}; +Q_DECLARE_OPERATORS_FOR_FLAGS(KEntryMap::SearchFlags) +Q_DECLARE_OPERATORS_FOR_FLAGS(KEntryMap::EntryOptions) + +/** + * \relates KEntry + * type for iterating over keys in a KEntryMap in sorted order. + * @internal + */ +typedef QMap<KEntryKey, KEntry>::Iterator KEntryMapIterator; + +/** + * \relates KEntry + * type for iterating over keys in a KEntryMap in sorted order. + * It is const, thus you cannot change the entries in the iterator, + * only examine them. + * @internal + */ +typedef QMap<KEntryKey, KEntry>::ConstIterator KEntryMapConstIterator; + +#endif diff --git a/tier1/kconfig/src/core/kconfiggroup.cpp b/tier1/kconfig/src/core/kconfiggroup.cpp new file mode 100644 index 00000000..ab7d494f --- /dev/null +++ b/tier1/kconfig/src/core/kconfiggroup.cpp @@ -0,0 +1,1243 @@ +/* + This file is part of the KDE libraries + Copyright (c) 2006, 2007 Thomas Braxton <kde.braxton@gmail.com> + Copyright (c) 1999 Preston Brown <pbrown@kde.org> + Copyright (c) 1997 Matthias Kalle Dalheimer <kalle@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +// Qt5 TODO: re-enable. No point in doing it before, it breaks on QString::fromUtf8(QByteArray), which exists in qt5. +#undef QT_NO_CAST_FROM_BYTEARRAY + +#include "kconfiggroup.h" +#include "kconfiggroup_p.h" + +#include "kconfig.h" +#include "kconfig_p.h" +#include "ksharedconfig.h" +#include "kconfigdata.h" + +#include <QtCore/QDate> +#include <QtCore/QSharedData> +#include <QtCore/QFile> +#include <QtCore/QPoint> +#include <QtCore/QRect> +#include <QtCore/QString> +#include <QtCore/QTextStream> +#include <QtCore/QDir> +#include <QtCore/QUrl> + +#include <stdlib.h> + +class KConfigGroupPrivate : public QSharedData +{ + public: + KConfigGroupPrivate(KConfig* owner, bool isImmutable, bool isConst, const QByteArray &name) + : mOwner(owner), mName(name), bImmutable(isImmutable), bConst(isConst) + { + } + + KConfigGroupPrivate(const KSharedConfigPtr &owner, const QByteArray& name) + : sOwner(owner), mOwner(sOwner.data()), mName(name), + bImmutable(name.isEmpty()? owner->isImmutable(): owner->isGroupImmutable(name)), bConst(false) + { + } + + KConfigGroupPrivate(KConfigGroup* parent, bool isImmutable, bool isConst, const QByteArray& name) + : sOwner(parent->d->sOwner), mOwner(parent->d->mOwner), mName(name), + bImmutable(isImmutable), bConst(isConst) + { + if (!parent->d->mName.isEmpty()) + mParent = parent->d; + } + + KConfigGroupPrivate(const KConfigGroupPrivate* other, bool isImmutable, const QByteArray &name) + : sOwner(other->sOwner), mOwner(other->mOwner), mName(name), + bImmutable(isImmutable), bConst(other->bConst) + { + if (!other->mName.isEmpty()) + mParent = const_cast<KConfigGroupPrivate *>(other); + } + + KSharedConfig::Ptr sOwner; + KConfig *mOwner; + QExplicitlySharedDataPointer<KConfigGroupPrivate> mParent; + QByteArray mName; + + /* bitfield */ + const bool bImmutable:1; // is this group immutable? + const bool bConst:1; // is this group read-only? + + QByteArray fullName() const + { + if (!mParent) { + return name(); + } + return mParent->fullName(mName); + } + + QByteArray name() const + { + if (mName.isEmpty()) + return "<default>"; + return mName; + } + + QByteArray fullName(const QByteArray& aGroup) const + { + if (mName.isEmpty()) + return aGroup; + return fullName() + '\x1d' + aGroup; + } + + static QExplicitlySharedDataPointer<KConfigGroupPrivate> create(KConfigBase *master, + const QByteArray &name, + bool isImmutable, + bool isConst) + { + QExplicitlySharedDataPointer<KConfigGroupPrivate> data; + if (dynamic_cast<KConfigGroup*>(master)) + data = new KConfigGroupPrivate(dynamic_cast<KConfigGroup*>(master), isImmutable, isConst, name); + else + data = new KConfigGroupPrivate(dynamic_cast<KConfig*>(master), isImmutable, isConst, name); + return data; + } + + static QByteArray serializeList(const QList<QByteArray> &list); + static QStringList deserializeList(const QString &data); +}; + +QByteArray KConfigGroupPrivate::serializeList(const QList<QByteArray> &list) +{ + QByteArray value = ""; + + if (!list.isEmpty()) { + QList<QByteArray>::ConstIterator it = list.constBegin(); + const QList<QByteArray>::ConstIterator end = list.constEnd(); + + value = QByteArray(*it).replace('\\', "\\\\").replace(',', "\\,"); + + while (++it != end) { + // In the loop, so it is not done when there is only one element. + // Doing it repeatedly is a pretty cheap operation. + value.reserve(4096); + + value += ','; + value += QByteArray(*it).replace('\\', "\\\\").replace(',', "\\,"); + } + + // To be able to distinguish an empty list from a list with one empty element. + if (value.isEmpty()) + value = "\\0"; + } + + return value; +} + +QStringList KConfigGroupPrivate::deserializeList(const QString &data) +{ + if (data.isEmpty()) + return QStringList(); + if (data == QLatin1String("\\0")) + return QStringList(QString()); + QStringList value; + QString val; + val.reserve(data.size()); + bool quoted = false; + for (int p = 0; p < data.length(); p++) { + if (quoted) { + val += data[p]; + quoted = false; + } else if (data[p].unicode() == '\\') { + quoted = true; + } else if (data[p].unicode() == ',') { + val.squeeze(); // release any unused memory + value.append(val); + val.clear(); + val.reserve(data.size() - p); + } else { + val += data[p]; + } + } + value.append(val); + return value; +} + +static QList<int> asIntList(const QByteArray& string) +{ + QList<int> list; + Q_FOREACH(const QByteArray& s, string.split(',')) + list << s.toInt(); + return list; +} + +static QList<qreal> asRealList(const QByteArray& string) +{ + QList<qreal> list; + Q_FOREACH(const QByteArray& s, string.split(',')) + list << s.toDouble(); + return list; +} + +static QString errString( const char * pKey, const QByteArray & value, const QVariant & aDefault ) { + return QString::fromLatin1("\"%1\" - conversion of \"%3\" to %2 failed") + .arg(QString::fromLatin1(pKey)) + .arg(QString::fromLatin1(QVariant::typeToName(aDefault.type()))) + .arg(QString::fromLatin1(value)); +} + +static QString formatError( int expected, int got ) { + return QString::fromLatin1(" (wrong format: expected %1 items, got %2)").arg( expected ).arg( got ); +} + +QVariant KConfigGroup::convertToQVariant(const char *pKey, const QByteArray& value, const QVariant& aDefault) +{ + // if a type handler is added here you must add a QVConversions definition + // to conversion_check.h, or ConversionCheck::to_QVariant will not allow + // readEntry<T> to convert to QVariant. + switch( aDefault.type() ) { + case QVariant::Invalid: + return QVariant(); + case QVariant::String: + // this should return the raw string not the dollar expanded string. + // imho if processed string is wanted should call + // readEntry(key, QString) not readEntry(key, QVariant) + return QString::fromUtf8(value); + case QVariant::List: + case QVariant::StringList: + return KConfigGroupPrivate::deserializeList(QString::fromUtf8(value)); + case QVariant::ByteArray: + return value; + case QVariant::Bool: { + const QByteArray lower(value.toLower()); + if (lower == "false" || lower == "no" || lower == "off" || lower == "0") + return false; + return true; + } + case QVariant::Double: + case QMetaType::Float: + case QVariant::Int: + case QVariant::UInt: + case QVariant::LongLong: + case QVariant::ULongLong: { + QVariant tmp = value; + if ( !tmp.convert(aDefault.type()) ) + tmp = aDefault; + return tmp; + } + case QVariant::Point: { + const QList<int> list = asIntList(value); + + if ( list.count() != 2 ) { + qWarning() << errString( pKey, value, aDefault ) + << formatError( 2, list.count() ); + return aDefault; + } + return QPoint(list.at( 0 ), list.at( 1 )); + } + case QVariant::PointF: { + const QList<qreal> list = asRealList(value); + + if ( list.count() != 2 ) { + qWarning() << errString( pKey, value, aDefault ) + << formatError( 2, list.count() ); + return aDefault; + } + return QPointF(list.at( 0 ), list.at( 1 )); + } + case QVariant::Rect: { + const QList<int> list = asIntList(value); + + if ( list.count() != 4 ) { + qWarning() << errString( pKey, value, aDefault ) + << formatError( 4, list.count() ); + return aDefault; + } + const QRect rect(list.at( 0 ), list.at( 1 ), list.at( 2 ), list.at( 3 )); + if ( !rect.isValid() ) { + qWarning() << errString( pKey, value, aDefault ); + return aDefault; + } + return rect; + } + case QVariant::RectF: { + const QList<qreal> list = asRealList(value); + + if ( list.count() != 4 ) { + qWarning() << errString( pKey, value, aDefault ) + << formatError( 4, list.count() ); + return aDefault; + } + const QRectF rect(list.at( 0 ), list.at( 1 ), list.at( 2 ), list.at( 3 )); + if ( !rect.isValid() ) { + qWarning() << errString( pKey, value, aDefault ); + return aDefault; + } + return rect; + } + case QVariant::Size: { + const QList<int> list = asIntList(value); + + if ( list.count() != 2 ) { + qWarning() << errString( pKey, value, aDefault ) + << formatError( 2, list.count() ); + return aDefault; + } + const QSize size(list.at( 0 ), list.at( 1 )); + if ( !size.isValid() ) { + qWarning() << errString( pKey, value, aDefault ); + return aDefault; + } + return size; + } + case QVariant::SizeF: { + const QList<qreal> list = asRealList(value); + + if ( list.count() != 2 ) { + qWarning() << errString( pKey, value, aDefault ) + << formatError( 2, list.count() ); + return aDefault; + } + const QSizeF size(list.at( 0 ), list.at( 1 )); + if ( !size.isValid() ) { + qWarning() << errString( pKey, value, aDefault ); + return aDefault; + } + return size; + } + case QVariant::DateTime: { + const QList<int> list = asIntList(value); + if ( list.count() != 6 ) { + qWarning() << errString( pKey, value, aDefault ) + << formatError( 6, list.count() ); + return aDefault; + } + const QDate date( list.at( 0 ), list.at( 1 ), list.at( 2 ) ); + const QTime time( list.at( 3 ), list.at( 4 ), list.at( 5 ) ); + const QDateTime dt( date, time ); + if ( !dt.isValid() ) { + qWarning() << errString( pKey, value, aDefault ); + return aDefault; + } + return dt; + } + case QVariant::Date: { + QList<int> list = asIntList(value); + if ( list.count() == 6 ) + list = list.mid(0, 3); // don't break config files that stored QDate as QDateTime + if ( list.count() != 3 ) { + qWarning() << errString( pKey, value, aDefault ) + << formatError( 3, list.count() ); + return aDefault; + } + const QDate date( list.at( 0 ), list.at( 1 ), list.at( 2 ) ); + if ( !date.isValid() ) { + qWarning() << errString( pKey, value, aDefault ); + return aDefault; + } + return date; + } + case QVariant::Color: + case QVariant::Font: + qWarning() << "KConfigGroup::readEntry was passed GUI type '" + << aDefault.typeName() + << "' but kdeui isn't linked! If it is linked to your program, " + "this is a platform bug. Please inform the KDE developers"; + break; + case QVariant::Url: + return QUrl(QString::fromUtf8(value)); + + default: + break; + } + + qWarning() << "unhandled type " << aDefault.typeName(); + return QVariant(); +} + +#ifdef Q_OS_WIN +# include <QtCore/QDir> +#endif + +static bool cleanHomeDirPath( QString &path, const QString &homeDir ) +{ +#ifdef Q_OS_WIN //safer + if (!QDir::toNativeSeparators(path).startsWith(QDir::toNativeSeparators(homeDir))) + return false; +#else + if (!path.startsWith(homeDir)) + return false; +#endif + + int len = homeDir.length(); + // replace by "$HOME" if possible + if (len && (path.length() == len || path[len] == QLatin1Char('/'))) { + path.replace(0, len, QString::fromLatin1("$HOME")); + return true; + } else + return false; +} + +static QString translatePath( QString path ) // krazy:exclude=passbyvalue +{ + if (path.isEmpty()) + return path; + + // only "our" $HOME should be interpreted + path.replace(QLatin1Char('$'), QLatin1String("$$")); + + bool startsWithFile = path.startsWith(QLatin1String("file:"), Qt::CaseInsensitive); + + // return original path, if it refers to another type of URL (e.g. http:/), or + // if the path is already relative to another directory + if ((!startsWithFile && QFileInfo(path).isRelative()) || + (startsWithFile && QFileInfo(path.mid(5)).isRelative())) + return path; + + if (startsWithFile) + path.remove(0,5); // strip leading "file:/" off the string + + // keep only one single '/' at the beginning - needed for cleanHomeDirPath() + while (path[0] == QLatin1Char('/') && path[1] == QLatin1Char('/')) + path.remove(0,1); + + // we can not use KGlobal::dirs()->relativeLocation("home", path) here, + // since it would not recognize paths without a trailing '/'. + // All of the 3 following functions to return the user's home directory + // can return different paths. We have to test all them. + const QString homeDir0 = QFile::decodeName(qgetenv("HOME")); + const QString homeDir1 = QDir::homePath(); + const QString homeDir2 = QDir(homeDir1).canonicalPath(); + if (cleanHomeDirPath(path, homeDir0) || + cleanHomeDirPath(path, homeDir1) || + cleanHomeDirPath(path, homeDir2) ) { + // qDebug() << "Path was replaced\n"; + } + + if (startsWithFile) + path.prepend(QString::fromLatin1("file://")); + + return path; +} + + +KConfigGroup::KConfigGroup() : d(0) +{ +} + +bool KConfigGroup::isValid() const +{ + return 0 != d.constData(); +} + +KConfigGroupGui _kde_internal_KConfigGroupGui; +static inline bool readEntryGui(const QByteArray& data, const char* key, const QVariant &input, + QVariant &output) +{ + if (_kde_internal_KConfigGroupGui.readEntryGui) + return _kde_internal_KConfigGroupGui.readEntryGui(data, key, input, output); + return false; +} + +static inline bool writeEntryGui(KConfigGroup *cg, const char* key, const QVariant &input, + KConfigGroup::WriteConfigFlags flags) +{ + if (_kde_internal_KConfigGroupGui.writeEntryGui) + return _kde_internal_KConfigGroupGui.writeEntryGui(cg, key, input, flags); + return false; +} + +KConfigGroup::KConfigGroup(KConfigBase *master, const QString &_group) + : d(KConfigGroupPrivate::create(master, _group.toUtf8(), master->isGroupImmutable(_group), false)) +{ +} + +KConfigGroup::KConfigGroup(KConfigBase *master, const char *_group) + : d(KConfigGroupPrivate::create(master, _group, master->isGroupImmutable(_group), false)) +{ +} + +KConfigGroup::KConfigGroup(const KConfigBase *master, const QString &_group) + : d(KConfigGroupPrivate::create(const_cast<KConfigBase*>(master), _group.toUtf8(), master->isGroupImmutable(_group), true)) +{ +} + +KConfigGroup::KConfigGroup(const KConfigBase *master, const char * _group) + : d(KConfigGroupPrivate::create(const_cast<KConfigBase*>(master), _group, master->isGroupImmutable(_group), true)) +{ +} + +KConfigGroup::KConfigGroup(const KSharedConfigPtr &master, const QString &_group) + : d(new KConfigGroupPrivate(master, _group.toUtf8())) +{ +} + +KConfigGroup::KConfigGroup(const KSharedConfigPtr &master, const char * _group) + : d(new KConfigGroupPrivate(master, _group)) +{ +} + +KConfigGroup &KConfigGroup::operator=(const KConfigGroup &rhs) +{ + d = rhs.d; + return *this; +} + +KConfigGroup::KConfigGroup(const KConfigGroup &rhs) + : KConfigBase(), d(rhs.d) +{ +} + +KConfigGroup::~KConfigGroup() +{ + d = 0; +} + +KConfigGroup KConfigGroup::groupImpl(const QByteArray& aGroup) +{ + Q_ASSERT_X(isValid(), "KConfigGroup::groupImpl", "accessing an invalid group"); + Q_ASSERT_X(!aGroup.isEmpty(), "KConfigGroup::groupImpl", "can not have an unnamed child group"); + + KConfigGroup newGroup; + + newGroup.d = new KConfigGroupPrivate(this, isGroupImmutableImpl(aGroup), d->bConst, aGroup); + + return newGroup; +} + +const KConfigGroup KConfigGroup::groupImpl(const QByteArray& aGroup) const +{ + Q_ASSERT_X(isValid(), "KConfigGroup::groupImpl", "accessing an invalid group"); + Q_ASSERT_X(!aGroup.isEmpty(), "KConfigGroup::groupImpl", "can not have an unnamed child group"); + + KConfigGroup newGroup; + + newGroup.d = new KConfigGroupPrivate(const_cast<KConfigGroup*>(this), isGroupImmutableImpl(aGroup), + true, aGroup); + + return newGroup; +} + +KConfigGroup KConfigGroup::parent() const +{ + Q_ASSERT_X(isValid(), "KConfigGroup::parent", "accessing an invalid group"); + + KConfigGroup parentGroup; + + if (d->mParent) { + parentGroup.d = d->mParent; + } else { + parentGroup.d = new KConfigGroupPrivate(d->mOwner, d->mOwner->isImmutable(), d->bConst, ""); + // make sure we keep the refcount up on the KConfig object + parentGroup.d->sOwner = d->sOwner; + } + + return parentGroup; +} + +void KConfigGroup::deleteGroup(WriteConfigFlags flags) +{ + Q_ASSERT_X(isValid(), "KConfigGroup::deleteGroup", "accessing an invalid group"); + Q_ASSERT_X(!d->bConst, "KConfigGroup::deleteGroup", "deleting a read-only group"); + + config()->deleteGroup(d->fullName(), flags); +} + +#ifndef KDE_NO_DEPRECATED +void KConfigGroup::changeGroup( const QString &group ) +{ + Q_ASSERT_X(isValid(), "KConfigGroup::changeGroup", "accessing an invalid group"); + d.detach(); + d->mName = group.toUtf8(); +} +#endif + +#ifndef KDE_NO_DEPRECATED +void KConfigGroup::changeGroup( const char *group ) +{ + Q_ASSERT_X(isValid(), "KConfigGroup::changeGroup", "accessing an invalid group"); + d.detach(); + d->mName = group; +} +#endif + +QString KConfigGroup::name() const +{ + Q_ASSERT_X(isValid(), "KConfigGroup::name", "accessing an invalid group"); + + return QString::fromUtf8(d->name()); +} + +bool KConfigGroup::exists() const +{ + Q_ASSERT_X(isValid(), "KConfigGroup::exists", "accessing an invalid group"); + + return config()->hasGroup( d->fullName() ); +} + +bool KConfigGroup::sync() +{ + Q_ASSERT_X(isValid(), "KConfigGroup::sync", "accessing an invalid group"); + + if (!d->bConst) + return config()->sync(); + + return false; +} + +QMap<QString, QString> KConfigGroup::entryMap() const +{ + Q_ASSERT_X(isValid(), "KConfigGroup::entryMap", "accessing an invalid group"); + + return config()->entryMap(QString::fromUtf8(d->fullName())); +} + +KConfig* KConfigGroup::config() +{ + Q_ASSERT_X(isValid(), "KConfigGroup::config", "accessing an invalid group"); + + return d->mOwner; +} + +const KConfig* KConfigGroup::config() const +{ + Q_ASSERT_X(isValid(), "KConfigGroup::config", "accessing an invalid group"); + + return d->mOwner; +} + +bool KConfigGroup::isEntryImmutable(const char* key) const +{ + Q_ASSERT_X(isValid(), "KConfigGroup::isEntryImmutable", "accessing an invalid group"); + + return (isImmutable() || + !config()->d_func()->canWriteEntry(d->fullName(), key, config()->readDefaults())); +} + +bool KConfigGroup::isEntryImmutable(const QString& key) const +{ + return isEntryImmutable(key.toUtf8().constData()); +} + +QString KConfigGroup::readEntryUntranslated(const QString& pKey, const QString& aDefault) const +{ + return readEntryUntranslated(pKey.toUtf8().constData(), aDefault); +} + +QString KConfigGroup::readEntryUntranslated(const char *key, const QString& aDefault) const +{ + Q_ASSERT_X(isValid(), "KConfigGroup::readEntryUntranslated", "accessing an invalid group"); + + QString result = config()->d_func()->lookupData(d->fullName(), key, KEntryMap::SearchFlags(), 0); + if (result.isNull()) + return aDefault; + return result; +} + +QString KConfigGroup::readEntry(const char *key, const char* aDefault) const +{ + return readEntry(key, QString::fromUtf8(aDefault)); +} + +QString KConfigGroup::readEntry(const QString &key, const char* aDefault) const +{ + return readEntry(key.toUtf8().constData(), aDefault); +} + +QString KConfigGroup::readEntry(const char* key, const QString& aDefault) const +{ + Q_ASSERT_X(isValid(), "KConfigGroup::readEntry", "accessing an invalid group"); + + bool expand = false; + + // read value from the entry map + QString aValue = config()->d_func()->lookupData(d->fullName(), key, KEntryMap::SearchLocalized, + &expand); + if (aValue.isNull()) + aValue = aDefault; + + if (expand) + return KConfigPrivate::expandString(aValue); + + return aValue; +} + +QString KConfigGroup::readEntry(const QString &key, const QString& aDefault) const +{ + return readEntry(key.toUtf8().constData(), aDefault); +} + +QStringList KConfigGroup::readEntry(const char* key, const QStringList& aDefault) const +{ + Q_ASSERT_X(isValid(), "KConfigGroup::readEntry", "accessing an invalid group"); + + const QString data = readEntry(key, QString()); + if (data.isNull()) + return aDefault; + + return KConfigGroupPrivate::deserializeList(data); +} + +QStringList KConfigGroup::readEntry( const QString& key, const QStringList& aDefault) const +{ + return readEntry( key.toUtf8().constData(), aDefault ); +} + +QVariant KConfigGroup::readEntry( const char* key, const QVariant &aDefault ) const +{ + Q_ASSERT_X(isValid(), "KConfigGroup::readEntry", "accessing an invalid group"); + + const QByteArray data = config()->d_func()->lookupData(d->fullName(), key, KEntryMap::SearchLocalized); + if (data.isNull()) + return aDefault; + + QVariant value; + if (!readEntryGui( data, key, aDefault, value )) + return convertToQVariant(key, data, aDefault); + + return value; +} + +QVariant KConfigGroup::readEntry( const QString& key, const QVariant& aDefault) const +{ + return readEntry( key.toUtf8().constData(), aDefault ); +} + +QVariantList KConfigGroup::readEntry( const char* key, const QVariantList& aDefault) const +{ + Q_ASSERT_X(isValid(), "KConfigGroup::readEntry", "accessing an invalid group"); + + const QString data = readEntry(key, QString()); + if (data.isNull()) + return aDefault; + + QVariantList value; + Q_FOREACH(const QString& v, KConfigGroupPrivate::deserializeList(data)) + value << v; + + return value; +} + +QVariantList KConfigGroup::readEntry( const QString& key, const QVariantList& aDefault) const +{ + return readEntry( key.toUtf8().constData(), aDefault ); +} + +QStringList KConfigGroup::readXdgListEntry(const QString& key, const QStringList& aDefault) const +{ + return readXdgListEntry(key.toUtf8().constData(), aDefault); +} + +QStringList KConfigGroup::readXdgListEntry(const char *key, const QStringList& aDefault) const +{ + Q_ASSERT_X(isValid(), "KConfigGroup::readXdgListEntry", "accessing an invalid group"); + + const QString data = readEntry(key, QString()); + if (data.isNull()) + return aDefault; + + QStringList value; + QString val; + val.reserve(data.size()); + // XXX List serialization being a separate layer from low-level parsing is + // probably a bug. No affected entries are defined, though. + bool quoted = false; + for (int p = 0; p < data.length(); p++) { + if (quoted) { + val += data[p]; + quoted = false; + } else if (data[p] == QLatin1Char('\\')) { + quoted = true; + } else if (data[p] == QLatin1Char(';')) { + value.append(val); + val.clear(); + val.reserve(data.size() - p); + } else { + val += data[p]; + } + } + if (!val.isEmpty()) { + qWarning() << "List entry" << key << "in" << config()->name() << "is not compliant with XDG standard (missing trailing semicolon)."; + value.append(val); + } + return value; +} + +QString KConfigGroup::readPathEntry(const QString& pKey, const QString & aDefault) const +{ + return readPathEntry(pKey.toUtf8().constData(), aDefault); +} + +QString KConfigGroup::readPathEntry(const char *key, const QString & aDefault) const +{ + Q_ASSERT_X(isValid(), "KConfigGroup::readPathEntry", "accessing an invalid group"); + + bool expand = false; + + QString aValue = config()->d_func()->lookupData(d->fullName(), key, KEntryMap::SearchLocalized, + &expand); + if (aValue.isNull()) + aValue = aDefault; + + return KConfigPrivate::expandString(aValue); +} + +QStringList KConfigGroup::readPathEntry(const QString& pKey, const QStringList& aDefault) const +{ + return readPathEntry(pKey.toUtf8().constData(), aDefault); +} + +QStringList KConfigGroup::readPathEntry(const char *key, const QStringList& aDefault) const +{ + Q_ASSERT_X(isValid(), "KConfigGroup::readPathEntry", "accessing an invalid group"); + + const QString data = readPathEntry(key, QString()); + if (data.isNull()) + return aDefault; + + return KConfigGroupPrivate::deserializeList(data); +} + +void KConfigGroup::writeEntry( const char* key, const QString& value, WriteConfigFlags flags ) +{ + Q_ASSERT_X(isValid(), "KConfigGroup::writeEntry", "accessing an invalid group"); + Q_ASSERT_X(!d->bConst, "KConfigGroup::writeEntry", "writing to a read-only group"); + + writeEntry(key, value.toUtf8(), flags); +} + +void KConfigGroup::writeEntry( const QString& key, const QString& value, WriteConfigFlags flags ) +{ + writeEntry(key.toUtf8().constData(), value, flags); +} + +void KConfigGroup::writeEntry(const QString &key, const char *value, WriteConfigFlags pFlags) +{ + Q_ASSERT_X(isValid(), "KConfigGroup::writeEntry", "accessing an invalid group"); + Q_ASSERT_X(!d->bConst, "KConfigGroup::writeEntry", "writing to a read-only group"); + + writeEntry(key.toUtf8().constData(), QVariant(QString::fromLatin1(value)), pFlags); +} + +void KConfigGroup::writeEntry(const char *key, const char *value, WriteConfigFlags pFlags) +{ + writeEntry(key, QVariant(QString::fromLatin1(value)), pFlags); +} + +void KConfigGroup::writeEntry( const char* key, const QByteArray& value, + WriteConfigFlags flags ) +{ + Q_ASSERT_X(isValid(), "KConfigGroup::writeEntry", "accessing an invalid group"); + Q_ASSERT_X(!d->bConst, "KConfigGroup::writeEntry", "writing to a read-only group"); + + config()->d_func()->putData(d->fullName(), key, value.isNull()? QByteArray(""): value, flags); +} + +void KConfigGroup::writeEntry(const QString& key, const QByteArray& value, + WriteConfigFlags pFlags) +{ + writeEntry(key.toUtf8().constData(), value, pFlags); +} + +void KConfigGroup::writeEntry(const char* key, const QStringList &list, WriteConfigFlags flags) +{ + Q_ASSERT_X(isValid(), "KConfigGroup::writeEntry", "accessing an invalid group"); + Q_ASSERT_X(!d->bConst, "KConfigGroup::writeEntry", "writing to a read-only group"); + + QList<QByteArray> balist; + + Q_FOREACH(const QString &entry, list) + balist.append(entry.toUtf8()); + + writeEntry(key, KConfigGroupPrivate::serializeList(balist), flags); +} + +void KConfigGroup::writeEntry(const QString& key, const QStringList &list, WriteConfigFlags flags) +{ + writeEntry(key.toUtf8().constData(), list, flags); +} + +void KConfigGroup::writeEntry( const char* key, const QVariantList& list, WriteConfigFlags flags ) +{ + Q_ASSERT_X(isValid(), "KConfigGroup::writeEntry", "accessing an invalid group"); + Q_ASSERT_X(!d->bConst, "KConfigGroup::writeEntry", "writing to a read-only group"); + + QList<QByteArray> data; + + Q_FOREACH(const QVariant& v, list) { + if (v.type() == QVariant::ByteArray) + data << v.toByteArray(); + else + data << v.toString().toUtf8(); + } + + writeEntry(key, KConfigGroupPrivate::serializeList(data), flags); +} + +void KConfigGroup::writeEntry( const char* key, const QVariant &value, + WriteConfigFlags flags ) +{ + Q_ASSERT_X(isValid(), "KConfigGroup::writeEntry", "accessing an invalid group"); + Q_ASSERT_X(!d->bConst, "KConfigGroup::writeEntry", "writing to a read-only group"); + + if ( writeEntryGui( this, key, value, flags ) ) + return; // GUI type that was handled + + QByteArray data; + // if a type handler is added here you must add a QVConversions definition + // to conversion_check.h, or ConversionCheck::to_QVariant will not allow + // writeEntry<T> to convert to QVariant. + switch( value.type() ) { + case QVariant::Invalid: + data = ""; + break; + case QVariant::ByteArray: + data = value.toByteArray(); + break; + case QVariant::String: + case QVariant::Int: + case QVariant::UInt: + case QVariant::Double: + case QMetaType::Float: + case QVariant::Bool: + case QVariant::LongLong: + case QVariant::ULongLong: + data = value.toString().toUtf8(); + break; + case QVariant::List: + if (!value.canConvert(QVariant::StringList)) + qWarning() << "not all types in \"" << key << "\" can convert to QString," + " information will be lost"; + case QVariant::StringList: + writeEntry( key, value.toList(), flags ); + return; + case QVariant::Point: { + QVariantList list; + const QPoint rPoint = value.toPoint(); + list.insert( 0, rPoint.x() ); + list.insert( 1, rPoint.y() ); + + writeEntry( key, list, flags ); + return; + } + case QVariant::PointF: { + QVariantList list; + const QPointF point = value.toPointF(); + list.insert( 0, point.x() ); + list.insert( 1, point.y() ); + + writeEntry( key, list, flags ); + return; + } + case QVariant::Rect:{ + QVariantList list; + const QRect rRect = value.toRect(); + list.insert( 0, rRect.left() ); + list.insert( 1, rRect.top() ); + list.insert( 2, rRect.width() ); + list.insert( 3, rRect.height() ); + + writeEntry( key, list, flags ); + return; + } + case QVariant::RectF:{ + QVariantList list; + const QRectF rRectF = value.toRectF(); + list.insert(0, rRectF.left()); + list.insert(1, rRectF.top()); + list.insert(2, rRectF.width()); + list.insert(3, rRectF.height()); + + writeEntry(key, list, flags); + return; + } + case QVariant::Size:{ + QVariantList list; + const QSize rSize = value.toSize(); + list.insert( 0, rSize.width() ); + list.insert( 1, rSize.height() ); + + writeEntry( key, list, flags ); + return; + } + case QVariant::SizeF:{ + QVariantList list; + const QSizeF rSizeF = value.toSizeF(); + list.insert(0, rSizeF.width()); + list.insert(1, rSizeF.height()); + + writeEntry(key, list, flags); + return; + } + case QVariant::Date: { + QVariantList list; + const QDate date = value.toDate(); + + list.insert( 0, date.year() ); + list.insert( 1, date.month() ); + list.insert( 2, date.day() ); + + writeEntry( key, list, flags ); + return; + } + case QVariant::DateTime: { + QVariantList list; + const QDateTime rDateTime = value.toDateTime(); + + const QTime time = rDateTime.time(); + const QDate date = rDateTime.date(); + + list.insert( 0, date.year() ); + list.insert( 1, date.month() ); + list.insert( 2, date.day() ); + + list.insert( 3, time.hour() ); + list.insert( 4, time.minute() ); + list.insert( 5, time.second() ); + + writeEntry( key, list, flags ); + return; + } + + case QVariant::Color: + case QVariant::Font: + qWarning() << "KConfigGroup::writeEntry was passed GUI type '" + << value.typeName() + << "' but kdeui isn't linked! If it is linked to your program, this is a platform bug. " + "Please inform the KDE developers"; + break; + case QVariant::Url: + data = QUrl(value.toUrl()).toString().toUtf8(); + break; + default: + qWarning() << "KConfigGroup::writeEntry - unhandled type" << value.typeName() << "in group" << name(); + } + + writeEntry(key, data, flags); +} + +void KConfigGroup::writeEntry( const QString& key, const QVariant& value, WriteConfigFlags flags ) +{ + writeEntry(key.toUtf8().constData(), value, flags); +} + +void KConfigGroup::writeEntry(const QString& key, const QVariantList &list, WriteConfigFlags flags) +{ + writeEntry(key.toUtf8().constData(), list, flags); +} + +void KConfigGroup::writeXdgListEntry(const QString& key, const QStringList &value, WriteConfigFlags pFlags) +{ + writeXdgListEntry(key.toUtf8().constData(), value, pFlags); +} + +void KConfigGroup::writeXdgListEntry(const char *key, const QStringList &list, WriteConfigFlags flags) +{ + Q_ASSERT_X(isValid(), "KConfigGroup::writeXdgListEntry", "accessing an invalid group"); + Q_ASSERT_X(!d->bConst, "KConfigGroup::writeXdgListEntry", "writing to a read-only group"); + + QString value; + value.reserve(4096); + + // XXX List serialization being a separate layer from low-level escaping is + // probably a bug. No affected entries are defined, though. + QStringList::ConstIterator it = list.constBegin(); + const QStringList::ConstIterator end = list.constEnd(); + for (; it != end; ++it) { + QString val(*it); + val.replace(QLatin1Char('\\'), QLatin1String("\\\\")).replace(QLatin1Char(';'), QLatin1String("\\;")); + value += val; + value += QLatin1Char(';'); + } + + writeEntry(key, value, flags); +} + +void KConfigGroup::writePathEntry(const QString& pKey, const QString & path, WriteConfigFlags pFlags) +{ + writePathEntry(pKey.toUtf8().constData(), path, pFlags); +} + +void KConfigGroup::writePathEntry(const char *pKey, const QString & path, WriteConfigFlags pFlags) +{ + Q_ASSERT_X(isValid(), "KConfigGroup::writePathEntry", "accessing an invalid group"); + Q_ASSERT_X(!d->bConst, "KConfigGroup::writePathEntry", "writing to a read-only group"); + + config()->d_func()->putData(d->fullName(), pKey, translatePath(path).toUtf8(), pFlags, true); +} + +void KConfigGroup::writePathEntry(const QString& pKey, const QStringList &value, WriteConfigFlags pFlags) +{ + writePathEntry(pKey.toUtf8().constData(), value, pFlags); +} + +void KConfigGroup::writePathEntry(const char *pKey, const QStringList &value, WriteConfigFlags pFlags) +{ + Q_ASSERT_X(isValid(), "KConfigGroup::writePathEntry", "accessing an invalid group"); + Q_ASSERT_X(!d->bConst, "KConfigGroup::writePathEntry", "writing to a read-only group"); + + QList<QByteArray> list; + Q_FOREACH(const QString& path, value) + list << translatePath(path).toUtf8(); + + config()->d_func()->putData(d->fullName(), pKey, KConfigGroupPrivate::serializeList(list), pFlags, true); +} + +void KConfigGroup::deleteEntry( const char *key, WriteConfigFlags flags) +{ + Q_ASSERT_X(isValid(), "KConfigGroup::deleteEntry", "accessing an invalid group"); + Q_ASSERT_X(!d->bConst, "KConfigGroup::deleteEntry", "deleting from a read-only group"); + + config()->d_func()->putData(d->fullName(), key, QByteArray(), flags); +} + +void KConfigGroup::deleteEntry( const QString& key, WriteConfigFlags flags) +{ + deleteEntry(key.toUtf8().constData(), flags); +} + +void KConfigGroup::revertToDefault(const char *key) +{ + Q_ASSERT_X(isValid(), "KConfigGroup::revertToDefault", "accessing an invalid group"); + Q_ASSERT_X(!d->bConst, "KConfigGroup::revertToDefault", "writing to a read-only group"); + + config()->d_func()->revertEntry(d->fullName(), key); +} + +void KConfigGroup::revertToDefault(const QString &key) +{ + revertToDefault(key.toUtf8().constData()); +} + +bool KConfigGroup::hasDefault(const char *key) const +{ + Q_ASSERT_X(isValid(), "KConfigGroup::hasDefault", "accessing an invalid group"); + + KEntryMap::SearchFlags flags = KEntryMap::SearchDefaults|KEntryMap::SearchLocalized; + + return !config()->d_func()->lookupData(d->fullName(), key, flags).isNull(); +} + +bool KConfigGroup::hasDefault(const QString &key) const +{ + return hasDefault(key.toUtf8().constData()); +} + +bool KConfigGroup::hasKey(const char *key) const +{ + Q_ASSERT_X(isValid(), "KConfigGroup::hasKey", "accessing an invalid group"); + + KEntryMap::SearchFlags flags = KEntryMap::SearchLocalized; + if ( config()->readDefaults() ) + flags |= KEntryMap::SearchDefaults; + + return !config()->d_func()->lookupData(d->fullName(), key, flags).isNull(); +} + +bool KConfigGroup::hasKey(const QString &key) const +{ + return hasKey(key.toUtf8().constData()); +} + +bool KConfigGroup::isImmutable() const +{ + Q_ASSERT_X(isValid(), "KConfigGroup::isImmutable", "accessing an invalid group"); + + return d->bImmutable; +} + +QStringList KConfigGroup::groupList() const +{ + Q_ASSERT_X(isValid(), "KConfigGroup::groupList", "accessing an invalid group"); + + return config()->d_func()->groupList(d->fullName()); +} + +QStringList KConfigGroup::keyList() const +{ + Q_ASSERT_X(isValid(), "KConfigGroup::keyList", "accessing an invalid group"); + + return entryMap().keys(); +} + +void KConfigGroup::markAsClean() +{ + Q_ASSERT_X(isValid(), "KConfigGroup::markAsClean", "accessing an invalid group"); + + config()->markAsClean(); +} + +KConfigGroup::AccessMode KConfigGroup::accessMode() const +{ + Q_ASSERT_X(isValid(), "KConfigGroup::accessMode", "accessing an invalid group"); + + return config()->accessMode(); +} + +bool KConfigGroup::hasGroupImpl(const QByteArray & b) const +{ + Q_ASSERT_X(isValid(), "KConfigGroup::hasGroupImpl", "accessing an invalid group"); + + return config()->hasGroup(d->fullName(b)); +} + +void KConfigGroup::deleteGroupImpl(const QByteArray &b, WriteConfigFlags flags) +{ + Q_ASSERT_X(isValid(), "KConfigGroup::deleteGroupImpl", "accessing an invalid group"); + Q_ASSERT_X(!d->bConst,"KConfigGroup::deleteGroupImpl", "deleting from a read-only group"); + + config()->deleteGroup(d->fullName(b), flags); +} + +bool KConfigGroup::isGroupImmutableImpl(const QByteArray& b) const +{ + Q_ASSERT_X(isValid(), "KConfigGroup::isGroupImmutableImpl", "accessing an invalid group"); + + if (!hasGroupImpl(b)) // group doesn't exist yet + return d->bImmutable; // child groups are immutable if the parent is immutable. + + return config()->isGroupImmutable(d->fullName(b)); +} + +void KConfigGroup::copyTo(KConfigBase* other, WriteConfigFlags pFlags) const +{ + Q_ASSERT_X(isValid(), "KConfigGroup::copyTo", "accessing an invalid group"); + Q_ASSERT(other != 0); + + if (KConfigGroup *otherGroup = dynamic_cast<KConfigGroup*>(other)) { + config()->d_func()->copyGroup(d->fullName(), otherGroup->d->fullName(), otherGroup, pFlags); + } else if (KConfig* otherConfig = dynamic_cast<KConfig*>(other)) { + KConfigGroup newGroup = otherConfig->group(d->fullName()); + otherConfig->d_func()->copyGroup(d->fullName(), d->fullName(), &newGroup, pFlags); + } else { + Q_ASSERT_X(false, "KConfigGroup::copyTo", "unknown type of KConfigBase"); + } +} + +void KConfigGroup::reparent(KConfigBase* parent, WriteConfigFlags pFlags) +{ + Q_ASSERT_X(isValid(), "KConfigGroup::reparent", "accessing an invalid group"); + Q_ASSERT_X(!d->bConst, "KConfigGroup::reparent", "reparenting a read-only group"); + Q_ASSERT_X(!d->bImmutable, "KConfigGroup::reparent", "reparenting an immutable group"); + Q_ASSERT(parent != 0); + + KConfigGroup oldGroup(*this); + + d = KConfigGroupPrivate::create(parent, d->mName, false, false); + oldGroup.copyTo(this, pFlags); + oldGroup.deleteGroup(); // so that the entries with the old group name are deleted on sync +} diff --git a/tier1/kconfig/src/core/kconfiggroup.h b/tier1/kconfig/src/core/kconfiggroup.h new file mode 100644 index 00000000..ce0330be --- /dev/null +++ b/tier1/kconfig/src/core/kconfiggroup.h @@ -0,0 +1,767 @@ +/* + This file is part of the KDE libraries + Copyright (c) 2006, 2007 Thomas Braxton <kde.braxton@gmail.com> + Copyright (c) 1999 Preston Brown <pbrown@kde.org> + Copyright (c) 1997 Matthias Kalle Dalheimer <kalle@kde.org> + Copyright (c) 2001 Waldo Bastian <bastian@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef KCONFIGGROUP_H +#define KCONFIGGROUP_H + +#include "kconfigbase.h" + +#include <kconfigcore_export.h> + +#include <QtCore/QExplicitlySharedDataPointer> +#include <QtCore/QVariant> +#include <QtCore/QStringList> + +class KConfig; +class KConfigGroupPrivate; +class KSharedConfig; +typedef QExplicitlySharedDataPointer<KSharedConfig> KSharedConfigPtr; +/** + * \class KConfigGroup kconfiggroup.h <KConfigGroup> + * + * A class for one specific group in a KConfig object. + * + * If you want to access the top-level entries of a KConfig + * object, which are not associated with any group, use an + * empty group name. + * + * A KConfigGroup will be read-only if it is constructed from a + * const config object or from another read-only group. + */ +class KCONFIGCORE_EXPORT KConfigGroup : public KConfigBase +{ +public: + /** + * Constructs an invalid group. + * + * \see isValid + */ + KConfigGroup(); + + /** + * Construct a config group corresponding to @p group in @p master. + * + * This allows the creation of subgroups by passing another + * group as @p master. + * + * @p group is the group name encoded in UTF-8. + */ + KConfigGroup(KConfigBase *master, const QString &group); + /** Overload for KConfigGroup(KConfigBase*,const QString&) */ + KConfigGroup(KConfigBase *master, const char *group); + + /** + * Construct a read-only config group. + * + * A read-only group will silently ignore any attempts to write to it. + * + * This allows the creation of subgroups by passing an existing group + * as @p master. + */ + KConfigGroup(const KConfigBase *master, const QString &group); + /** Overload for KConfigGroup(const KConfigBase*,const QString&) */ + KConfigGroup(const KConfigBase *master, const char *group); + + /** Overload for KConfigGroup(const KConfigBase*,const QString&) */ + KConfigGroup(const KSharedConfigPtr &master, const QString &group); + /** Overload for KConfigGroup(const KConfigBase*,const QString&) */ + KConfigGroup(const KSharedConfigPtr &master, const char *group); + + /** + * Creates a read-only copy of a read-only group. + */ + KConfigGroup(const KConfigGroup &); + KConfigGroup &operator=(const KConfigGroup &); + + ~KConfigGroup(); + + /** + * Whether the group is valid. + * + * A group is invalid if it was constructed without arguments. + * + * You should not call any functions on an invalid group. + * + * @return @c true if the group is valid, @c false if it is invalid. + */ + bool isValid() const; + + /** + * The name of this group. + * + * The root group is named "<default>". + */ + QString name() const; + + /** + * Check whether the containing KConfig object acutally contains a + * group with this name. + */ + bool exists() const; + + /** + * @reimp + * + * Syncs the parent config. + */ + bool sync() Q_DECL_OVERRIDE; + + /// @reimp + void markAsClean(); + + /// @reimp + AccessMode accessMode() const; + + /** + * Return the config object that this group belongs to + */ + KConfig* config(); + /** + * Return the config object that this group belongs to + */ + const KConfig* config() const; + + /** + * Changes the group of the object + * + * @deprecated + * Create another KConfigGroup from the parent of this group instead. + */ +#ifndef KDE_NO_DEPRECATED + KCONFIGCORE_DEPRECATED void changeGroup(const QString &group); +#endif + /** + * Overload for changeGroup(const QString&) + * + * @deprecated + * Create another KConfigGroup from the parent of this group instead. + */ +#ifndef KDE_NO_DEPRECATED + KCONFIGCORE_DEPRECATED void changeGroup(const char *group); +#endif + + /** + * Copies the entries in this group to another configuration object + * + * @note @p other can be either another group or a different file. + * + * @param other the configuration object to copy this group's entries to + * @param pFlags the flags to use when writing the entries to the + * other configuration object + * + * @since 4.1 + */ + void copyTo(KConfigBase *other, WriteConfigFlags pFlags = Normal) const; + + /** + * Changes the configuration object that this group belongs to + * + * @note @p other can be another group, the top-level KConfig object or + * a different KConfig object entirely. + * + * If @p parent is already the parent of this group, this method will have + * no effect. + * + * @param parent the config object to place this group under + * @param pFlags the flags to use in determining which storage source to + * write the data to + * + * @since 4.1 + */ + void reparent(KConfigBase *parent, WriteConfigFlags pFlags = Normal); + + /** + * Returns the group that this group belongs to + * + * @return the parent group, or an invalid group if this is a top-level + * group + * + * @since 4.1 + */ + KConfigGroup parent() const; + + /** + * @reimp + */ + QStringList groupList() const; + + /** + * Returns a list of keys this group contains + */ + QStringList keyList() const; + + /** + * Delete all entries in the entire group + * + * @param pFlags flags passed to KConfig::deleteGroup + * + * @see deleteEntry() + */ + void deleteGroup(WriteConfigFlags pFlags = Normal); + using KConfigBase::deleteGroup; + + /** + * Reads the value of an entry specified by @p pKey in the current group + * + * This template method makes it possible to write + * QString foo = readEntry("...", QString("default")); + * and the same with all other types supported by QVariant. + * + * The return type of the method is simply the same as the type of the default value. + * + * @note readEntry("...", Qt::white) will not compile because Qt::white is an enum. + * You must turn it into readEntry("...", QColor(Qt::white)). + * + * @note Only the following QVariant types are allowed : String, + * StringList, List, Font, Point, Rect, Size, Color, Int, UInt, Bool, + * Double, LongLong, ULongLong, DateTime and Date. + * + * @param key The key to search for + * @param aDefault A default value returned if the key was not found + * @return The value for this key, or @p aDefault. + * + * @see writeEntry(), deleteEntry(), hasKey() + */ + template <typename T> + inline T readEntry(const QString &key, const T &aDefault) const + { return readCheck(key.toUtf8().constData(), aDefault); } + /** Overload for readEntry(const QString&, const T&) const */ + template <typename T> + inline T readEntry(const char *key, const T &aDefault) const + { return readCheck(key, aDefault); } + + /** + * Reads the value of an entry specified by @p key in the current group + * + * @param key the key to search for + * @param aDefault a default value returned if the key was not found + * @return the value for this key, or @p aDefault if the key was not found + * + * @see writeEntry(), deleteEntry(), hasKey() + */ + QVariant readEntry(const QString &key, const QVariant &aDefault) const; + /** Overload for readEntry(const QString&, const QVariant&) */ + QVariant readEntry(const char *key, const QVariant &aDefault) const; + + /** + * Reads the string value of an entry specified by @p key in the current group + * + * If you want to read a path, please use readPathEntry(). + * + * @param key the key to search for + * @param aDefault a default value returned if the key was not found + * @return the value for this key, or @p aDefault if the key was not found + * + * @see readPathEntry(), writeEntry(), deleteEntry(), hasKey() + */ + QString readEntry(const QString &key, const QString &aDefault) const; + /** Overload for readEntry(const QString&, const QString&) */ + QString readEntry(const char *key, const QString &aDefault) const; + + /** Overload for readEntry(const QString&, const QString&) */ + QString readEntry(const QString &key, const char *aDefault = 0) const; + /** Overload for readEntry(const QString&, const QString&) */ + QString readEntry(const char *key, const char *aDefault = 0) const; + + /** + * @copydoc readEntry(const char*, const QStringList&) const + * + * @warning This function doesn't convert the items returned + * to any type. It's actually a list of QVariant::String's. If you + * want the items converted to a specific type use + * readEntry(const char*, const QList<T>&) const + */ + QVariantList readEntry(const QString &key, const QVariantList &aDefault) const; + /** Overload for readEntry(const QString&, const QVariantList&) */ + QVariantList readEntry(const char *key, const QVariantList &aDefault) const; + + /** + * Reads a list of strings from the config object + * + * @param key The key to search for + * @param aDefault The default value to use if the key does not exist + * @return The list, or @p aDefault if @p key does not exist + * + * @see readXdgListEntry(), writeEntry(), deleteEntry(), hasKey() + */ + QStringList readEntry(const QString &key, const QStringList &aDefault) const; + /** Overload for readEntry(const QString&, const QStringList&) */ + QStringList readEntry(const char *key, const QStringList &aDefault) const; + + /** + * Reads a list of values from the config object + * + * @param key the key to search for + * @param aDefault the default value to use if the key does not exist + * @return the list, or @p aDefault if @p key does not exist + * + * @see readXdgListEntry(), writeEntry(), deleteEntry(), hasKey() + */ + template<typename T> + inline QList<T> readEntry(const QString &key, const QList<T> &aDefault) const + { return readListCheck(key.toUtf8().constData(), aDefault); } + /** Overload for readEntry(const QString&, const QList<T>&) */ + template<typename T> + inline QList<T> readEntry(const char *key, const QList<T> &aDefault) const + { return readListCheck(key, aDefault); } + + /** + * Reads a list of strings from the config object, following XDG + * desktop entry spec separator semantics + * + * @param pKey the key to search for + * @param aDefault the default value to use if the key does not exist + * @return the list, or @p aDefault if @p pKey does not exist + * + * @see readEntry(const QString&, const QStringList&) const + */ + QStringList readXdgListEntry(const QString &pKey, const QStringList &aDefault = QStringList()) const; + /** Overload for readXdgListEntry(const QString&, const QStringList&) */ + QStringList readXdgListEntry(const char *pKey, const QStringList &aDefault = QStringList()) const; + + /** + * Reads a path + * + * Read the value of an entry specified by @p pKey in the current group + * and interpret it as a path. This means, dollar expansion is activated + * for this value, so that e.g. $HOME gets expanded. + * + * @param pKey The key to search for. + * @param aDefault A default value returned if the key was not found. + * @return The value for this key. Can be QString() if @p aDefault is null. + */ + QString readPathEntry(const QString &pKey, const QString &aDefault) const; + /** Overload for readPathEntry(const QString&, const QString&) */ + QString readPathEntry(const char *key, const QString &aDefault) const; + + /** + * Reads a list of paths + * + * Read the value of an entry specified by @p pKey in the current group + * and interpret it as a list of paths. This means, dollar expansion is activated + * for this value, so that e.g. $HOME gets expanded. + * + * @param pKey the key to search for + * @param aDefault a default value returned if the key was not found + * @return the list, or @p aDefault if the key does not exist + */ + QStringList readPathEntry(const QString &pKey, const QStringList &aDefault) const; + /** Overload for readPathEntry(const QString&, const QStringList&) */ + QStringList readPathEntry(const char *key, const QStringList &aDefault) const; + + /** + * Reads an untranslated string entry + * + * You should not normally need to use this. + * + * @param pKey the key to search for + * @param aDefault a default value returned if the key was not found + * @return the value for this key, or @p aDefault if the key does not exist + */ + QString readEntryUntranslated(const QString &pKey, + const QString &aDefault = QString()) const; + /** Overload for readEntryUntranslated(const QString&, const QString&) */ + QString readEntryUntranslated(const char *key, + const QString &aDefault = QString()) const; + + /** + * Writes a value to the configuration object. + * + * @param key the key to write to + * @param value the value to write + * @param pFlags the flags to use when writing this entry + * + * @see readEntry(), writeXdgListEntry(), deleteEntry() + */ + void writeEntry(const QString &key, const QVariant &value, + WriteConfigFlags pFlags = Normal); + /** Overload for writeEntry(const QString&, const QVariant&, WriteConfigFlags) */ + void writeEntry(const char *key, const QVariant &value, + WriteConfigFlags pFlags = Normal); + + /** Overload for writeEntry(const QString&, const QVariant&, WriteConfigFlags) */ + void writeEntry(const QString &key, const QString &value, + WriteConfigFlags pFlags = Normal); + /** Overload for writeEntry(const QString&, const QVariant&, WriteConfigFlags) */ + void writeEntry(const char *key, const QString &value, + WriteConfigFlags pFlags = Normal); + + /** Overload for writeEntry(const QString&, const QVariant&, WriteConfigFlags) */ + void writeEntry(const QString &key, const QByteArray &value, + WriteConfigFlags pFlags = Normal); + /** Overload for writeEntry(const QString&, const QVariant&, WriteConfigFlags) */ + void writeEntry(const char *key, const QByteArray &value, + WriteConfigFlags pFlags = Normal); + + /** Overload for writeEntry(const QString&, const QVariant&, WriteConfigFlags) */ + void writeEntry(const QString &key, const char *value, WriteConfigFlags pFlags = Normal); + /** Overload for writeEntry(const QString&, const QVariant&, WriteConfigFlags) */ + void writeEntry(const char *key, const char *value, WriteConfigFlags pFlags = Normal); + + /** Overload for writeEntry(const QString&, const QVariant&, WriteConfigFlags) */ + template <typename T> + inline void writeEntry(const char *key, const T &value, WriteConfigFlags pFlags = Normal) + { writeCheck( key, value, pFlags ); } + /** Overload for writeEntry(const QString&, const QVariant&, WriteConfigFlags) */ + template <typename T> + inline void writeEntry(const QString &key, const T &value, WriteConfigFlags pFlags = Normal) + { writeCheck( key.toUtf8().constData(), value, pFlags ); } + + /** Overload for writeEntry(const QString&, const QVariant&, WriteConfigFlags) */ + void writeEntry(const QString &key, const QStringList &value, + WriteConfigFlags pFlags = Normal); + /** Overload for writeEntry(const QString&, const QVariant&, WriteConfigFlags) */ + void writeEntry(const char *key, const QStringList &value, + WriteConfigFlags pFlags = Normal); + + /** Overload for writeEntry(const QString&, const QVariant&, WriteConfigFlags) */ + void writeEntry(const QString &key, const QVariantList &value, + WriteConfigFlags pFlags = Normal); + /** Overload for writeEntry(const QString&, const QVariant&, WriteConfigFlags) */ + void writeEntry(const char *key, const QVariantList &value, + WriteConfigFlags pFlags = Normal); + + /** Overload for writeEntry(const QString&, const QVariant&, WriteConfigFlags) */ + template <typename T> + inline void writeEntry(const QString &key, const QList<T> &value, WriteConfigFlags pFlags = Normal) + { writeListCheck( key.toUtf8().constData(), value, pFlags ); } + /** Overload for writeEntry(const QString&, const QVariant&, WriteConfigFlags) */ + template <typename T> + inline void writeEntry(const char *key, const QList<T> &value, WriteConfigFlags pFlags = Normal) + { writeListCheck( key, value, pFlags ); } + + /** + * Writes a list of strings to the config object, following XDG + * desktop entry spec separator semantics + * + * @param pKey the key to write to + * @param value the list to write + * @param pFlags the flags to use when writing this entry + * + * @see writeEntry(), readXdgListEntry() + */ + void writeXdgListEntry(const QString &pKey, const QStringList &value, + WriteConfigFlags pFlags = Normal); + /** Overload for writeXdgListEntry(const QString&, const QStringList&, WriteConfigFlags) */ + void writeXdgListEntry(const char *pKey, const QStringList &value, + WriteConfigFlags pFlags = Normal); + + /** + * Writes a file path to the configuration + * + * If the path is located under $HOME, the user's home directory + * is replaced with $HOME in the persistent storage. + * The path should therefore be read back with readPathEntry() + * + * @param pKey the key to write to + * @param path the path to write + * @param pFlags the flags to use when writing this entry + * + * @see writeEntry(), readPathEntry() + */ + void writePathEntry(const QString &pKey, const QString &path, + WriteConfigFlags pFlags = Normal); + /** Overload for writePathEntry(const QString&, const QString&, WriteConfigFlags) */ + void writePathEntry(const char *pKey, const QString &path, + WriteConfigFlags pFlags = Normal); + + /** + * Writes a list of paths to the configuration + * + * If any of the paths are located under $HOME, the user's home directory + * is replaced with $HOME in the persistent storage. + * The paths should therefore be read back with readPathEntry() + * + * @param pKey the key to write to + * @param value the list to write + * @param pFlags the flags to use when writing this entry + * + * @see writeEntry(), readPathEntry() + */ + void writePathEntry(const QString &pKey, const QStringList &value, + WriteConfigFlags pFlags = Normal); + /** Overload for writePathEntry(const QString&, const QStringList&, WriteConfigFlags) */ + void writePathEntry(const char *pKey, const QStringList &value, + WriteConfigFlags pFlags = Normal); + + /** + * Deletes the entry specified by @p pKey in the current group + * + * This also hides system wide defaults. + * + * @param pKey the key to delete + * @param pFlags the flags to use when deleting this entry + * + * @see deleteGroup(), readEntry(), writeEntry() + */ + void deleteEntry(const QString &pKey, WriteConfigFlags pFlags = Normal); + /** Overload for deleteEntry(const QString&, WriteConfigFlags) */ + void deleteEntry(const char *pKey, WriteConfigFlags pFlags = Normal); + + /** + * Checks whether the key has an entry in this group + * + * Use this to determine if a key is not specified for the current + * group (hasKey() returns false). + * + * If this returns @c false for a key, readEntry() (and its variants) + * will return the default value passed to them. + * + * @param key the key to search for + * @return @c true if the key is defined in this group by any of the + * configuration sources, @c false otherwise + * + * @see readEntry() + */ + bool hasKey(const QString &key) const; + /** Overload for hasKey(const QString&) const */ + bool hasKey(const char *key) const; + + /** + * Whether this group may be changed + * + * @return @c false if the group may be changed, @c true otherwise + */ + bool isImmutable() const; + + /** + * Checks if it is possible to change the given entry + * + * If isImmutable() returns @c true, then this method will return + * @c true for all inputs. + * + * @param key the key to check + * @return @c false if the key may be changed using this configuration + * group object, @c true otherwise + */ + bool isEntryImmutable(const QString &key) const; + /** Overload for isEntryImmutable(const QString&) const */ + bool isEntryImmutable(const char *key) const; + + /** + * Reverts an entry to the default settings. + * + * Reverts the entry with key @p key in the current group in the + * application specific config file to either the system wide (default) + * value or the value specified in the global KDE config file. + * + * To revert entries in the global KDE config file, the global KDE config + * file should be opened explicitly in a separate config object. + * + * @note This is @em not the same as deleting the key, as instead the + * global setting will be copied to the configuration file that this + * object manipulates. + * + * @param key The key of the entry to revert. + */ + void revertToDefault(const QString &key); + /** Overload for revertToDefault(const QString&) */ + void revertToDefault(const char* key); + + /** + * Whether a default is specified for an entry in either the + * system wide configuration file or the global KDE config file + * + * If an application computes a default value at runtime for + * a certain entry, e.g. like: + * \code + * QColor computedDefault = qApp->palette().color(QPalette::Active, QPalette::Text); + * QColor color = group.readEntry(key, computedDefault); + * \endcode + * then it may wish to make the following check before + * writing back changes: + * \code + * if ( (value == computedDefault) && !group.hasDefault(key) ) + * group.revertToDefault(key); + * else + * group.writeEntry(key, value); + * \endcode + * + * This ensures that as long as the entry is not modified to differ from + * the computed default, the application will keep using the computed default + * and will follow changes the computed default makes over time. + * + * @param key the key of the entry to check + * @return @c true if the global or system settings files specify a default + * for @p key in this group, @c false otherwise + */ + bool hasDefault(const QString &key) const; + /** Overload for hasDefault(const QString&) const */ + bool hasDefault(const char *key) const; + + /** + * Returns a map (tree) of entries for all entries in this group + * + * Only the actual entry string is returned, none of the + * other internal data should be included. + * + * @return a map of entries in this group, indexed by key + */ + QMap<QString, QString> entryMap() const; + +protected: + bool hasGroupImpl(const QByteArray &group) const; + KConfigGroup groupImpl(const QByteArray &b); + const KConfigGroup groupImpl(const QByteArray &b) const; + void deleteGroupImpl(const QByteArray &group, WriteConfigFlags flags); + bool isGroupImmutableImpl(const QByteArray &aGroup) const; + +private: + QExplicitlySharedDataPointer<KConfigGroupPrivate> d; + + template<typename T> + inline T readCheck(const char *key, const T &defaultValue) const; + + template<typename T> + inline QList<T> readListCheck(const char *key, const QList<T> &defaultValue) const; + + template<typename T> + inline void writeCheck(const char *key, const T &value, WriteConfigFlags pFlags); + + template<typename T> + inline void writeListCheck(const char *key, const QList<T> &value, WriteConfigFlags pFlags); + + friend class KConfigGroupPrivate; + + /** + * Return the data in @p value converted to a QVariant + * + * @param pKey the name of the entry being converted, this is only used for error + * reporting + * @param value the UTF-8 data to be converted + * @param aDefault the default value if @p pKey is not found + * @return @p value converted to QVariant, or @p aDefault if @p value is invalid or cannot be converted. + */ + static QVariant convertToQVariant(const char *pKey, const QByteArray &value, const QVariant &aDefault); + friend class KServicePrivate; // XXX yeah, ugly^5 +}; + +#define KCONFIGGROUP_ENUMERATOR_ERROR(ENUM) \ +"The Qt MetaObject system does not seem to know about \"" ENUM \ +"\" please use Q_ENUMS or Q_FLAGS to register it." + +/** + * To add support for your own enums in KConfig, you can declare them with Q_ENUMS() + * in a QObject subclass (which will make moc generate the code to turn the + * enum into a string and vice-versa), and then (in the cpp code) + * use the macro + * <code>KCONFIGGROUP_DECLARE_ENUM_QOBJECT(MyClass, MyEnum)</code> + * + * After that, you can use readEntry(group, key, value) and writeEntry(group, key, value[, flags]). + * Note that those are global functions, NOT member functions of KConfigGroup. + * + */ +#define KCONFIGGROUP_DECLARE_ENUM_QOBJECT(Class, Enum) \ +inline Class::Enum readEntry(const KConfigGroup& group, const char* key, const Class::Enum& def) \ +{ \ +const QMetaObject* M_obj = &Class::staticMetaObject; \ +const int M_index = M_obj->indexOfEnumerator(#Enum); \ +if(M_index == -1) qFatal(KCONFIGGROUP_ENUMERATOR_ERROR(#Enum)); \ +const QMetaEnum M_enum = M_obj->enumerator(M_index); \ +const QByteArray M_data = group.readEntry(key, QByteArray(M_enum.valueToKey(def)));\ +return static_cast<Class::Enum>(M_enum.keyToValue(M_data.constData())); \ +} \ +inline void writeEntry(KConfigGroup& group, const char* key, const Class::Enum& value, KConfigBase::WriteConfigFlags flags = KConfigBase::Normal)\ +{ \ +const QMetaObject* M_obj = &Class::staticMetaObject; \ +const int M_index = M_obj->indexOfEnumerator(#Enum); \ +if(M_index == -1) qFatal(KCONFIGGROUP_ENUMERATOR_ERROR(#Enum)); \ +const QMetaEnum M_enum = M_obj->enumerator(M_index); \ +group.writeEntry(key, QByteArray(M_enum.valueToKey(value)), flags); \ +} + +/** + * Similar to KCONFIGGROUP_DECLARE_ENUM_QOBJECT but for flags declared with Q_FLAGS() + * (where multiple values can be set at the same time) + */ +#define KCONFIGGROUP_DECLARE_FLAGS_QOBJECT(Class, Flags) \ +inline Class::Flags readEntry(const KConfigGroup& group, const char* key, const Class::Flags& def) \ +{ \ +const QMetaObject* M_obj = &Class::staticMetaObject; \ +const int M_index = M_obj->indexOfEnumerator(#Flags); \ +if(M_index == -1) qFatal(KCONFIGGROUP_ENUMERATOR_ERROR(#Flags)); \ +const QMetaEnum M_enum = M_obj->enumerator(M_index); \ +const QByteArray M_data = group.readEntry(key, QByteArray(M_enum.valueToKeys(def)));\ +return static_cast<Class::Flags>(M_enum.keysToValue(M_data.constData())); \ +} \ +inline void writeEntry(KConfigGroup& group, const char* key, const Class::Flags& value, KConfigBase::WriteConfigFlags flags = KConfigBase::Normal)\ +{ \ +const QMetaObject* M_obj = &Class::staticMetaObject; \ +const int M_index = M_obj->indexOfEnumerator(#Flags); \ +if(M_index == -1) qFatal(KCONFIGGROUP_ENUMERATOR_ERROR(#Flags)); \ +const QMetaEnum M_enum = M_obj->enumerator(M_index); \ +group.writeEntry(key, QByteArray(M_enum.valueToKeys(value)), flags); \ +} + +#include "conversion_check.h" + +template <typename T> +T KConfigGroup::readCheck(const char *key, const T &defaultValue) const +{ + ConversionCheck::to_QVariant<T>(); + return qvariant_cast<T>(readEntry(key, qVariantFromValue(defaultValue))); +} + +template <typename T> +QList<T> KConfigGroup::readListCheck(const char *key, const QList<T> &defaultValue) const +{ + ConversionCheck::to_QVariant<T>(); + ConversionCheck::to_QString<T>(); + + QVariantList data; + + Q_FOREACH(const T& value, defaultValue) + data.append(qVariantFromValue(value)); + + QList<T> list; + Q_FOREACH (const QVariant &value, readEntry<QVariantList>(key, data)) { + Q_ASSERT(value.canConvert<T>()); + list.append(qvariant_cast<T>(value)); + } + + return list; +} + +template <typename T> +void KConfigGroup::writeCheck(const char *key, const T &value, + WriteConfigFlags pFlags) +{ + ConversionCheck::to_QVariant<T>(); + writeEntry(key, qVariantFromValue(value), pFlags); +} + +template <typename T> +void KConfigGroup::writeListCheck(const char *key, const QList<T> &list, + WriteConfigFlags pFlags) +{ + ConversionCheck::to_QVariant<T>(); + ConversionCheck::to_QString<T>(); + QVariantList data; + Q_FOREACH(const T &value, list) { + data.append(qVariantFromValue(value)); + } + + writeEntry(key, data, pFlags); +} + +#endif // KCONFIGGROUP_H diff --git a/tier1/kconfig/src/core/kconfiggroup_p.h b/tier1/kconfig/src/core/kconfiggroup_p.h new file mode 100644 index 00000000..c5d4f150 --- /dev/null +++ b/tier1/kconfig/src/core/kconfiggroup_p.h @@ -0,0 +1,42 @@ +/* + This file is part of the KDE libraries + Copyright (c) 2007 Thiago Macieira <thiago@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef KCONFIGGROUP_P_H +#define KCONFIGGROUP_P_H + +#include <QtCore/QVariant> +#include "kconfiggroup.h" + +class KConfigGroup; + +struct KConfigGroupGui +{ + typedef bool (*kReadEntryGui)(const QByteArray& data, const char* key, const QVariant &input, + QVariant &output); + typedef bool (*kWriteEntryGui)(KConfigGroup *, const char* key, const QVariant &input, + KConfigGroup::WriteConfigFlags flags); + + kReadEntryGui readEntryGui; + kWriteEntryGui writeEntryGui; +}; + +extern KCONFIGCORE_EXPORT KConfigGroupGui _kde_internal_KConfigGroupGui; + +#endif diff --git a/tier1/kconfig/src/core/kconfigini.cpp b/tier1/kconfig/src/core/kconfigini.cpp new file mode 100644 index 00000000..f44b2c39 --- /dev/null +++ b/tier1/kconfig/src/core/kconfigini.cpp @@ -0,0 +1,770 @@ +/* + This file is part of the KDE libraries + Copyright (c) 2006, 2007 Thomas Braxton <kde.braxton@gmail.com> + Copyright (c) 1999 Preston Brown <pbrown@kde.org> + Copyright (C) 1997-1999 Matthias Kalle Dalheimer (kalle@kde.org) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "kconfigini_p.h" + +#include "kconfig.h" +#include "kconfigbackend.h" +#include "bufferfragment_p.h" +#include "kconfigdata.h" + +#include <qsavefile.h> +#include <qlockfile.h> +#include <qdatetime.h> +#include <qdir.h> +#include <qfile.h> +#include <qfileinfo.h> +#include <qdebug.h> +#include <qplatformdefs.h> + +#ifndef Q_OS_WIN +#include <unistd.h> // getuid, close +#endif +#include <sys/types.h> // uid_t +#include <fcntl.h> // open + +KCONFIGCORE_EXPORT bool kde_kiosk_exception = false; // flag to disable kiosk restrictions + +QString KConfigIniBackend::warningProlog(const QFile &file, int line) +{ + return QString::fromLatin1("KConfigIni: In file %2, line %1: ") + .arg(line).arg(file.fileName()); +} + +KConfigIniBackend::KConfigIniBackend() + : KConfigBackend(), lockFile(NULL) +{ +} + +KConfigIniBackend::~KConfigIniBackend() +{ +} + +KConfigBackend::ParseInfo + KConfigIniBackend::parseConfig(const QByteArray& currentLocale, KEntryMap& entryMap, + ParseOptions options) +{ + return parseConfig(currentLocale, entryMap, options, false); +} + +// merging==true is the merging that happens at the beginning of writeConfig: +// merge changes in the on-disk file with the changes in the KConfig object. +KConfigBackend::ParseInfo +KConfigIniBackend::parseConfig(const QByteArray& currentLocale, KEntryMap& entryMap, + ParseOptions options, bool merging) +{ + if (filePath().isEmpty() || !QFile::exists(filePath())) + return ParseOk; + + bool bDefault = options&ParseDefaults; + bool allowExecutableValues = options&ParseExpansions; + + QByteArray currentGroup("<default>"); + + QFile file(filePath()); + if (!file.open(QIODevice::ReadOnly|QIODevice::Text)) + return ParseOpenError; + + QList<QByteArray> immutableGroups; + + bool fileOptionImmutable = false; + bool groupOptionImmutable = false; + bool groupSkip = false; + + int lineNo = 0; + // on systems using \r\n as end of line, \r will be taken care of by + // trim() below + QByteArray buffer = file.readAll(); + BufferFragment contents(buffer.data(), buffer.size()); + unsigned int len = contents.length(); + unsigned int startOfLine = 0; + + while (startOfLine < len) { + BufferFragment line = contents.split('\n', &startOfLine); + line.trim(); + lineNo++; + + // skip empty lines and lines beginning with '#' + if (line.isEmpty() || line.at(0) == '#') + continue; + + if (line.at(0) == '[') { // found a group + groupOptionImmutable = fileOptionImmutable; + + QByteArray newGroup; + int start = 1, end; + do { + end = start; + for (;;) { + if (end == line.length()) { + qWarning() << warningProlog(file, lineNo) << "Invalid group header."; + // XXX maybe reset the current group here? + goto next_line; + } + if (line.at(end) == ']') + break; + end++; + } + if (end + 1 == line.length() && start + 2 == end && + line.at(start) == '$' && line.at(start + 1) == 'i') + { + if (newGroup.isEmpty()) + fileOptionImmutable = !kde_kiosk_exception; + else + groupOptionImmutable = !kde_kiosk_exception; + } + else { + if (!newGroup.isEmpty()) + newGroup += '\x1d'; + BufferFragment namePart=line.mid(start, end - start); + printableToString(&namePart, file, lineNo); + newGroup += namePart.toByteArray(); + } + } while ((start = end + 2) <= line.length() && line.at(end + 1) == '['); + currentGroup = newGroup; + + groupSkip = entryMap.getEntryOption(currentGroup, 0, 0, KEntryMap::EntryImmutable); + + if (groupSkip && !bDefault) + continue; + + if (groupOptionImmutable) + // Do not make the groups immutable until the entries from + // this file have been added. + immutableGroups.append(currentGroup); + } else { + if (groupSkip && !bDefault) + continue; // skip entry + + BufferFragment aKey; + int eqpos = line.indexOf('='); + if (eqpos < 0) { + aKey = line; + line.clear(); + } else { + BufferFragment temp = line.left(eqpos); + temp.trim(); + aKey = temp; + line.truncateLeft(eqpos + 1); + } + if (aKey.isEmpty()) { + qWarning() << warningProlog(file, lineNo) << "Invalid entry (empty key)"; + continue; + } + + KEntryMap::EntryOptions entryOptions=0; + if (groupOptionImmutable) + entryOptions |= KEntryMap::EntryImmutable; + + BufferFragment locale; + int start; + while ((start = aKey.lastIndexOf('[')) >= 0) { + int end = aKey.indexOf(']', start); + if (end < 0) { + qWarning() << warningProlog(file, lineNo) + << "Invalid entry (missing ']')"; + goto next_line; + } else if (end > start + 1 && aKey.at(start + 1) == '$') { // found option(s) + int i = start + 2; + while (i < end) { + switch (aKey.at(i)) { + case 'i': + if (!kde_kiosk_exception) + entryOptions |= KEntryMap::EntryImmutable; + break; + case 'e': + if (allowExecutableValues) + entryOptions |= KEntryMap::EntryExpansion; + break; + case 'd': + entryOptions |= KEntryMap::EntryDeleted; + aKey = aKey.left(start); + printableToString(&aKey, file, lineNo); + entryMap.setEntry(currentGroup, aKey.toByteArray(), QByteArray(), entryOptions); + goto next_line; + default: + break; + } + i++; + } + } else { // found a locale + if (!locale.isNull()) { + qWarning() << warningProlog(file, lineNo) + << "Invalid entry (second locale!?)"; + goto next_line; + } + + locale = aKey.mid(start + 1,end - start - 1); + } + aKey.truncate(start); + } + if (eqpos < 0) { // Do this here after [$d] was checked + qWarning() << warningProlog(file, lineNo) << "Invalid entry (missing '=')"; + continue; + } + printableToString(&aKey, file, lineNo); + if (!locale.isEmpty()) { + if (locale != currentLocale) { + // backward compatibility. C == en_US + if (locale.at(0) != 'C' || currentLocale != "en_US") { + if (merging) + entryOptions |= KEntryMap::EntryRawKey; + else + goto next_line; // skip this entry if we're not merging + } + } + } + + if (!(entryOptions & KEntryMap::EntryRawKey)) + printableToString(&aKey, file, lineNo); + + if (options&ParseGlobal) + entryOptions |= KEntryMap::EntryGlobal; + if (bDefault) + entryOptions |= KEntryMap::EntryDefault; + if (!locale.isNull()) + entryOptions |= KEntryMap::EntryLocalized; + printableToString(&line, file, lineNo); + if (entryOptions & KEntryMap::EntryRawKey) { + QByteArray rawKey; + rawKey.reserve(aKey.length() + locale.length() + 2); + rawKey.append(aKey.toVolatileByteArray()); + rawKey.append('[').append(locale.toVolatileByteArray()).append(']'); + entryMap.setEntry(currentGroup, rawKey, line.toByteArray(), entryOptions); + } else { + entryMap.setEntry(currentGroup, aKey.toByteArray(), line.toByteArray(), entryOptions); + } + } +next_line: + continue; + } + + // now make sure immutable groups are marked immutable + Q_FOREACH(const QByteArray& group, immutableGroups) { + entryMap.setEntry(group, QByteArray(), QByteArray(), KEntryMap::EntryImmutable); + } + + return fileOptionImmutable ? ParseImmutable : ParseOk; +} + +void KConfigIniBackend::writeEntries(const QByteArray& locale, QIODevice& file, + const KEntryMap& map, bool defaultGroup, bool &firstEntry) +{ + QByteArray currentGroup; + bool groupIsImmutable = false; + const KEntryMapConstIterator end = map.constEnd(); + for (KEntryMapConstIterator it = map.constBegin(); it != end; ++it) { + const KEntryKey& key = it.key(); + + // Either process the default group or all others + if ((key.mGroup != "<default>") == defaultGroup) + continue; // skip + + // the only thing we care about groups is, is it immutable? + if (key.mKey.isNull()) { + groupIsImmutable = it->bImmutable; + continue; // skip + } + + const KEntry& currentEntry = *it; + if (!defaultGroup && currentGroup != key.mGroup) { + if (!firstEntry) + file.putChar('\n'); + currentGroup = key.mGroup; + for (int start = 0, end;; start = end + 1) { + file.putChar('['); + end = currentGroup.indexOf('\x1d', start); + if (end < 0) { + int cgl = currentGroup.length(); + if (currentGroup.at(start) == '$' && cgl - start <= 10) { + for (int i = start + 1; i < cgl; i++) { + char c = currentGroup.at(i); + if (c < 'a' || c > 'z') + goto nope; + } + file.write("\\x24"); + start++; + } + nope: + file.write(stringToPrintable(currentGroup.mid(start), GroupString)); + file.putChar(']'); + if (groupIsImmutable) { + file.write("[$i]", 4); + } + file.putChar('\n'); + break; + } else { + file.write(stringToPrintable(currentGroup.mid(start, end - start), GroupString)); + file.putChar(']'); + } + } + } + + firstEntry = false; + // it is data for a group + + if (key.bRaw) // unprocessed key with attached locale from merge + file.write(key.mKey); + else { + file.write(stringToPrintable(key.mKey, KeyString)); // Key + if (key.bLocal && locale != "C") { // 'C' locale == untranslated + file.putChar('['); + file.write(locale); // locale tag + file.putChar(']'); + } + } + if (currentEntry.bDeleted) { + if (currentEntry.bImmutable) + file.write("[$di]", 5); // Deleted + immutable + else + file.write("[$d]", 4); // Deleted + } else { + if (currentEntry.bImmutable || currentEntry.bExpand) { + file.write("[$", 2); + if (currentEntry.bImmutable) + file.putChar('i'); + if (currentEntry.bExpand) + file.putChar('e'); + file.putChar(']'); + } + file.putChar('='); + file.write(stringToPrintable(currentEntry.mValue, ValueString)); + } + file.putChar('\n'); + } +} + +void KConfigIniBackend::writeEntries(const QByteArray& locale, QIODevice& file, const KEntryMap& map) +{ + bool firstEntry = true; + + // write default group + writeEntries(locale, file, map, true, firstEntry); + + // write all other groups + writeEntries(locale, file, map, false, firstEntry); +} + +bool KConfigIniBackend::writeConfig(const QByteArray& locale, KEntryMap& entryMap, + WriteOptions options) +{ + Q_ASSERT(!filePath().isEmpty()); + + KEntryMap writeMap; + const bool bGlobal = options & WriteGlobal; + + // First, reparse the file on disk, to merge our changes with the ones done by other apps + // Store the result into writeMap. + { + ParseOptions opts = ParseExpansions; + if (bGlobal) + opts |= ParseGlobal; + ParseInfo info = parseConfig(locale, writeMap, opts, true); + if (info != ParseOk) // either there was an error or the file became immutable + return false; + } + + const KEntryMapIterator end = entryMap.end(); + for (KEntryMapIterator it=entryMap.begin(); it != end; ++it) { + if (!it.key().mKey.isEmpty() && !it->bDirty) // not dirty, doesn't overwrite entry in writeMap. skips default entries, too. + continue; + + const KEntryKey& key = it.key(); + + // only write entries that have the same "globality" as the file + if (it->bGlobal == bGlobal) { + if (it->bReverted) { + writeMap.remove(key); + } else if (!it->bDeleted) { + writeMap[key] = *it; + } else { + KEntryKey defaultKey = key; + defaultKey.bDefault = true; + if (!entryMap.contains(defaultKey)) { + writeMap.remove(key); // remove the deleted entry if there is no default + //qDebug() << "Detected as deleted=>removed:" << key.mGroup << key.mKey << "global=" << bGlobal; + } else { + writeMap[key] = *it; // otherwise write an explicitly deleted entry + //qDebug() << "Detected as deleted=>[$d]:" << key.mGroup << key.mKey << "global=" << bGlobal; + } + } + it->bDirty = false; + } + } + + // now writeMap should contain only entries to be written + // so write it out to disk + + // check if file exists + QFile::Permissions fileMode = QFile::ReadUser | QFile::WriteUser; + bool createNew = true; + + QFileInfo fi(filePath()); + if (fi.exists()) + { +#ifdef Q_OS_WIN + //TODO: getuid does not exist on windows, use GetSecurityInfo and GetTokenInformation instead + createNew = false; +#else + if (fi.ownerId() == ::getuid()) + { + // Preserve file mode if file exists and is owned by user. + fileMode = fi.permissions(); + } + else + { + // File is not owned by user: + // Don't create new file but write to existing file instead. + createNew = false; + } +#endif + } + + if (createNew) { + QSaveFile file(filePath()); + if (!file.open(QIODevice::WriteOnly)) { + return false; + } + + file.setTextModeEnabled(true); // to get eol translation + writeEntries(locale, file, writeMap); + + if (!file.size() && (fileMode == (QFile::ReadUser | QFile::WriteUser))) { + // File is empty and doesn't have special permissions: delete it. + file.cancelWriting(); + + if (fi.exists()) { + // also remove the old file in case it existed. this can happen + // when we delete all the entries in an existing config file. + // if we don't do this, then deletions and revertToDefault's + // will mysteriously fail + QFile::remove(filePath()); + } + } else { + // Normal case: Close the file + if (file.commit()) { + QFile::setPermissions(filePath(), fileMode); + return true; + } + // Couldn't write. Disk full? + qWarning() << "Couldn't write" << filePath() << ". Disk full?"; + return false; + } + } else { + // Open existing file. *DON'T* create it if it suddenly does not exist! +#ifdef Q_OS_UNIX + int fd = QT_OPEN(QFile::encodeName(filePath()).constData(), O_WRONLY | O_TRUNC); + if (fd < 0) { + return false; + } + FILE *fp = ::fdopen(fd, "w"); + if (!fp) { + QT_CLOSE(fd); + return false; + } + QFile f; + if (!f.open(fp, QIODevice::WriteOnly)) { + fclose(fp); + return false; + } + writeEntries(locale, f, writeMap); + f.close(); + fclose(fp); +#else + QFile f( filePath() ); + // XXX This is broken - it DOES create the file if it is suddenly gone. + if (!f.open( QIODevice::WriteOnly | QIODevice::Truncate )) { + return false; + } + f.setTextModeEnabled(true); + writeEntries(locale, f, writeMap); +#endif + } + return true; +} + + +bool KConfigIniBackend::isWritable() const +{ + const QString filePath = this->filePath(); + if (!filePath.isEmpty()) { + QFileInfo file(filePath); + if (!file.exists()) { + // If the file does not exist, check if the deepest + // existing dir is writable. + QFileInfo dir(file.absolutePath()); + while (!dir.exists()) { + QString parent = dir.absolutePath(); // Go up. Can't use cdUp() on non-existing dirs. + if (parent == dir.filePath()) { + // no parent + return false; + } + dir.setFile(parent); + } + return dir.isDir() && dir.isWritable(); + } else { + return file.isWritable(); + } + } + + return false; +} + +QString KConfigIniBackend::nonWritableErrorMessage() const +{ + return tr("Configuration file \"%1\" not writable.\n").arg(filePath()); +} + +void KConfigIniBackend::createEnclosing() +{ + const QString file = filePath(); + if (file.isEmpty()) + return; // nothing to do + + // Create the containing dir, maybe it wasn't there + QDir dir; + dir.mkpath(QFileInfo(file).absolutePath()); +} + +void KConfigIniBackend::setFilePath(const QString& file) +{ + if (file.isEmpty()) + return; + + Q_ASSERT(QDir::isAbsolutePath(file)); + + const QFileInfo info(file); + if (info.exists()) { + setLocalFilePath(info.canonicalFilePath()); + setLastModified(info.lastModified()); + setSize(info.size()); + } else { + setLocalFilePath(file); + setSize(0); + QDateTime dummy; + dummy.setTime_t(0); + setLastModified(dummy); + } +} + +KConfigBase::AccessMode KConfigIniBackend::accessMode() const +{ + if (filePath().isEmpty()) + return KConfigBase::NoAccess; + + if (isWritable()) + return KConfigBase::ReadWrite; + + return KConfigBase::ReadOnly; +} + +bool KConfigIniBackend::lock() +{ + Q_ASSERT(!filePath().isEmpty()); + + if (!lockFile) { + lockFile = new QLockFile(filePath() + QLatin1String(".lock")); + } + + // This is a workaround for current QLockFilePrivate::tryLock_sys + // which might crash calling qAppName() if sync() is called after + // the QCoreApplication instance is gone. It might be the case with + // KSharedConfig instances cleanup. + if (!lockFile->tryLock(lockFile->staleLockTime())) { + lockFile->removeStaleLockFile(); + lockFile->lock(); + } + return lockFile->isLocked(); +} + +void KConfigIniBackend::unlock() +{ + lockFile->unlock(); + delete lockFile; + lockFile = NULL; +} + +bool KConfigIniBackend::isLocked() const +{ + return lockFile && lockFile->isLocked(); +} + +QByteArray KConfigIniBackend::stringToPrintable(const QByteArray& aString, StringType type) +{ + static const char nibbleLookup[] = { + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' + }; + + if (aString.isEmpty()) + return aString; + const int l = aString.length(); + + QByteArray result; // Guesstimated that it's good to avoid data() initialization for a length of l*4 + result.resize(l * 4); // Maximum 4x as long as source string due to \x<ab> escape sequences + register const char *s = aString.constData(); + int i = 0; + char *data = result.data(); + char *start = data; + + // Protect leading space + if (s[0] == ' ' && type != GroupString) { + *data++ = '\\'; + *data++ = 's'; + i++; + } + + for (; i < l; ++i/*, r++*/) { + switch (s[i]) { + default: + // The \n, \t, \r cases (all < 32) are handled below; we can ignore them here + if (((unsigned char)s[i]) < 32) + goto doEscape; + *data++ = s[i]; + break; + case '\n': + *data++ = '\\'; + *data++ = 'n'; + break; + case '\t': + *data++ = '\\'; + *data++ = 't'; + break; + case '\r': + *data++ = '\\'; + *data++ = 'r'; + break; + case '\\': + *data++ = '\\'; + *data++ = '\\'; + break; + case '=': + if (type != KeyString) { + *data++ = s[i]; + break; + } + goto doEscape; + case '[': + case ']': + // Above chars are OK to put in *value* strings as plaintext + if (type == ValueString) { + *data++ = s[i]; + break; + } + doEscape: + *data++ = '\\'; + *data++ = 'x'; + *data++ = nibbleLookup[((unsigned char)s[i]) >> 4]; + *data++ = nibbleLookup[((unsigned char)s[i]) & 0x0f]; + break; + } + } + *data = 0; + result.resize(data - start); + + // Protect trailing space + if (result.endsWith(' ') && type != GroupString) { + result.replace(result.length() - 1, 1, "\\s"); + } + result.squeeze(); + + return result; +} + +char KConfigIniBackend::charFromHex(const char *str, const QFile& file, int line) +{ + unsigned char ret = 0; + for (int i = 0; i < 2; i++) { + ret <<= 4; + quint8 c = quint8(str[i]); + + if (c >= '0' && c <= '9') { + ret |= c - '0'; + } else if (c >= 'a' && c <= 'f') { + ret |= c - 'a' + 0x0a; + } else if (c >= 'A' && c <= 'F') { + ret |= c - 'A' + 0x0a; + } else { + QByteArray e(str, 2); + e.prepend("\\x"); + qWarning() << warningProlog(file, line) << "Invalid hex character " << c + << " in \\x<nn>-type escape sequence \"" << e.constData() << "\"."; + return 'x'; + } + } + return char(ret); +} + +void KConfigIniBackend::printableToString(BufferFragment* aString, const QFile& file, int line) +{ + if (aString->isEmpty() || aString->indexOf('\\')==-1) + return; + aString->trim(); + int l = aString->length(); + char *r = aString->data(); + char *str=r; + + for(int i = 0; i < l; i++, r++) { + if (str[i]!= '\\') { + *r=str[i]; + } else { + // Probable escape sequence + i++; + if (i >= l) { // Line ends after backslash - stop. + *r = '\\'; + break; + } + + switch(str[i]) { + case 's': + *r = ' '; + break; + case 't': + *r = '\t'; + break; + case 'n': + *r = '\n'; + break; + case 'r': + *r = '\r'; + break; + case '\\': + *r = '\\'; + break; + case 'x': + if (i + 2 < l) { + *r = charFromHex(str + i + 1, file, line); + i += 2; + } else { + *r = 'x'; + i = l - 1; + } + break; + default: + *r = '\\'; + qWarning() << warningProlog(file, line) + << QString::fromLatin1("Invalid escape sequence \"\\%1\".").arg(str[i]); + } + } + } + aString->truncate(r - aString->constData()); +} diff --git a/tier1/kconfig/src/core/kconfigini_p.h b/tier1/kconfig/src/core/kconfigini_p.h new file mode 100644 index 00000000..368a78fb --- /dev/null +++ b/tier1/kconfig/src/core/kconfigini_p.h @@ -0,0 +1,81 @@ +/* + This file is part of the KDE libraries + Copyright (c) 2006, 2007 Thomas Braxton <kde.braxton@gmail.com> + Copyright (c) 1999 Preston Brown <pbrown@kde.org> + Portions copyright (c) 1997 Matthias Kalle Dalheimer <kalle@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef KCONFIGINI_P_H +#define KCONFIGINI_P_H + +#include <kconfigcore_export.h> +#include <kconfigbackend.h> + +class QLockFile; +class QIODevice; + +class KConfigIniBackend : public KConfigBackend +{ +private: + class BufferFragment; + + QLockFile *lockFile; +public: + + KConfigIniBackend(); + ~KConfigIniBackend(); + + ParseInfo parseConfig(const QByteArray& locale, + KEntryMap& entryMap, + ParseOptions options); + ParseInfo parseConfig(const QByteArray& locale, + KEntryMap& entryMap, + ParseOptions options, + bool merging); + bool writeConfig(const QByteArray& locale, KEntryMap& entryMap, + WriteOptions options); + + bool isWritable() const; + QString nonWritableErrorMessage() const; + KConfigBase::AccessMode accessMode() const; + void createEnclosing(); + void setFilePath(const QString& path); + bool lock(); + void unlock(); + bool isLocked() const; + +protected: + + enum StringType { + GroupString = 0, + KeyString = 1, + ValueString = 2 + }; + // Warning: this modifies data in-place. Other BufferFragment objects referencing the same buffer + // fragment will get their data modified too. + static void printableToString(BufferFragment* aString, const QFile& file, int line); + static QByteArray stringToPrintable(const QByteArray& aString, StringType type); + static char charFromHex(const char *str, const QFile& file, int line); + static QString warningProlog(const QFile& file, int line); + + void writeEntries(const QByteArray& locale, QIODevice& file, const KEntryMap& map); + void writeEntries(const QByteArray& locale, QIODevice& file, const KEntryMap& map, + bool defaultGroup, bool &firstEntry); +}; + +#endif // KCONFIGINI_P_H diff --git a/tier1/kconfig/src/core/kcoreconfigskeleton.cpp b/tier1/kconfig/src/core/kcoreconfigskeleton.cpp new file mode 100644 index 00000000..691e0b54 --- /dev/null +++ b/tier1/kconfig/src/core/kcoreconfigskeleton.cpp @@ -0,0 +1,1343 @@ +/* + This file is part of KOrganizer. + Copyright (c) 2000,2001 Cornelius Schumacher <schumacher@kde.org> + Copyright (c) 2003 Waldo Bastian <bastian@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "kcoreconfigskeleton.h" +#include "kcoreconfigskeleton_p.h" + +#include <QUrl> + + +static QString obscuredString(const QString &str) +{ + QString result; + const QChar *unicode = str.unicode(); + for ( int i = 0; i < str.length(); ++i ) + // yes, no typo. can't encode ' ' or '!' because + // they're the unicode BOM. stupid scrambling. stupid. + result += ( unicode[ i ].unicode() <= 0x21 ) ? unicode[ i ] + : QChar( 0x1001F - unicode[ i ].unicode() ); + + return result; +} + +KConfigSkeletonItem::KConfigSkeletonItem(const QString & _group, + const QString & _key) + : mGroup(_group) + , mKey(_key) + , d( new KConfigSkeletonItemPrivate ) +{ +} + +KConfigSkeletonItem::~KConfigSkeletonItem() +{ + delete d; +} + +void KConfigSkeletonItem::setGroup( const QString &_group ) +{ + mGroup = _group; +} + +QString KConfigSkeletonItem::group() const +{ + return mGroup; +} + +void KConfigSkeletonItem::setKey( const QString &_key ) +{ + mKey = _key; +} + +QString KConfigSkeletonItem::key() const +{ + return mKey; +} + +void KConfigSkeletonItem::setName(const QString &_name) +{ + mName = _name; +} + +QString KConfigSkeletonItem::name() const +{ + return mName; +} + +void KConfigSkeletonItem::setLabel( const QString &l ) +{ + d->mLabel = l; +} + +QString KConfigSkeletonItem::label() const +{ + return d->mLabel; +} + +void KConfigSkeletonItem::setToolTip( const QString &t ) +{ + d->mToolTip = t; +} + +QString KConfigSkeletonItem::toolTip() const +{ + return d->mToolTip; +} + +void KConfigSkeletonItem::setWhatsThis( const QString &w ) +{ + d->mWhatsThis = w; +} + +QString KConfigSkeletonItem::whatsThis() const +{ + return d->mWhatsThis; +} + +QVariant KConfigSkeletonItem::minValue() const +{ + return QVariant(); +} + +QVariant KConfigSkeletonItem::maxValue() const +{ + return QVariant(); +} + +bool KConfigSkeletonItem::isImmutable() const +{ + return d->mIsImmutable; +} + +void KConfigSkeletonItem::readImmutability( const KConfigGroup &group ) +{ + d->mIsImmutable = group.isEntryImmutable( mKey ); +} + + +KCoreConfigSkeleton::ItemString::ItemString( const QString &_group, const QString &_key, + QString &reference, + const QString &defaultValue, + Type type ) + : KConfigSkeletonGenericItem<QString>( _group, _key, reference, defaultValue ), + mType( type ) +{ +} + +void KCoreConfigSkeleton::ItemString::writeConfig( KConfig *config ) +{ + if ( mReference != mLoadedValue ) // WABA: Is this test needed? + { + KConfigGroup cg(config, mGroup ); + if ((mDefault == mReference) && !cg.hasDefault( mKey)) + cg.revertToDefault( mKey ); + else if ( mType == Path ) + cg.writePathEntry( mKey, mReference ); + else if ( mType == Password ) + cg.writeEntry( mKey, obscuredString( mReference ) ); + else + cg.writeEntry( mKey, mReference ); + } +} + + +void KCoreConfigSkeleton::ItemString::readConfig( KConfig *config ) +{ + KConfigGroup cg(config, mGroup ); + + if ( mType == Path ) + { + mReference = cg.readPathEntry( mKey, mDefault ); + } + else if ( mType == Password ) + { + QString val = cg.readEntry( mKey, obscuredString( mDefault ) ); + mReference = obscuredString( val ); + } + else + { + mReference = cg.readEntry( mKey, mDefault ); + } + + mLoadedValue = mReference; + + readImmutability( cg ); +} + +void KCoreConfigSkeleton::ItemString::setProperty(const QVariant & p) +{ + mReference = p.toString(); +} + +bool KCoreConfigSkeleton::ItemString::isEqual(const QVariant &v) const +{ + return mReference == v.toString(); +} + +QVariant KCoreConfigSkeleton::ItemString::property() const +{ + return QVariant(mReference); +} + +KCoreConfigSkeleton::ItemPassword::ItemPassword( const QString &_group, const QString &_key, + QString &reference, + const QString &defaultValue) + : ItemString( _group, _key, reference, defaultValue, Password ) +{ +} + +KCoreConfigSkeleton::ItemPath::ItemPath( const QString &_group, const QString &_key, + QString &reference, + const QString &defaultValue) + : ItemString( _group, _key, reference, defaultValue, Path ) +{ +} + +KCoreConfigSkeleton::ItemUrl::ItemUrl( const QString &_group, const QString &_key, + QUrl &reference, + const QUrl &defaultValue ) + : KConfigSkeletonGenericItem<QUrl>( _group, _key, reference, defaultValue ) +{ +} + +void KCoreConfigSkeleton::ItemUrl::writeConfig( KConfig *config ) +{ + if ( mReference != mLoadedValue ) // WABA: Is this test needed? + { + KConfigGroup cg(config, mGroup ); + if ((mDefault == mReference) && !cg.hasDefault( mKey)) + cg.revertToDefault( mKey ); + else + cg.writeEntry<QString>( mKey, mReference.toString() ); + } +} + +void KCoreConfigSkeleton::ItemUrl::readConfig( KConfig *config ) +{ + KConfigGroup cg(config, mGroup ); + + mReference = QUrl( cg.readEntry<QString>( mKey, mDefault.toString() ) ); + mLoadedValue = mReference; + + readImmutability( cg ); +} + +void KCoreConfigSkeleton::ItemUrl::setProperty(const QVariant & p) +{ + mReference = qvariant_cast<QUrl>(p); +} + +bool KCoreConfigSkeleton::ItemUrl::isEqual(const QVariant &v) const +{ + return mReference == qvariant_cast<QUrl>(v); +} + +QVariant KCoreConfigSkeleton::ItemUrl::property() const +{ + return qVariantFromValue<QUrl>(mReference); +} + +KCoreConfigSkeleton::ItemProperty::ItemProperty( const QString &_group, + const QString &_key, + QVariant &reference, + const QVariant &defaultValue ) + : KConfigSkeletonGenericItem<QVariant>( _group, _key, reference, defaultValue ) +{ +} + +void KCoreConfigSkeleton::ItemProperty::readConfig( KConfig *config ) +{ + KConfigGroup cg(config, mGroup ); + mReference = cg.readEntry( mKey, mDefault ); + mLoadedValue = mReference; + + readImmutability( cg ); +} + +void KCoreConfigSkeleton::ItemProperty::setProperty(const QVariant & p) +{ + mReference = p; +} + +bool KCoreConfigSkeleton::ItemProperty::isEqual(const QVariant &v) const +{ + //this might cause problems if the QVariants are not of default types + return mReference == v; +} + +QVariant KCoreConfigSkeleton::ItemProperty::property() const +{ + return mReference; +} + +KCoreConfigSkeleton::ItemBool::ItemBool( const QString &_group, const QString &_key, + bool &reference, bool defaultValue ) + : KConfigSkeletonGenericItem<bool>( _group, _key, reference, defaultValue ) +{ +} + +void KCoreConfigSkeleton::ItemBool::readConfig( KConfig *config ) +{ + KConfigGroup cg(config, mGroup ); + mReference = cg.readEntry( mKey, mDefault ); + mLoadedValue = mReference; + + readImmutability( cg ); +} + +void KCoreConfigSkeleton::ItemBool::setProperty(const QVariant & p) +{ + mReference = p.toBool(); +} + +bool KCoreConfigSkeleton::ItemBool::isEqual(const QVariant &v) const +{ + return mReference == v.toBool(); +} + +QVariant KCoreConfigSkeleton::ItemBool::property() const +{ + return QVariant( mReference ); +} + + +KCoreConfigSkeleton::ItemInt::ItemInt( const QString &_group, const QString &_key, + qint32 &reference, qint32 defaultValue ) + : KConfigSkeletonGenericItem<qint32>( _group, _key, reference, defaultValue ) + ,mHasMin(false), mHasMax(false) +{ +} + +void KCoreConfigSkeleton::ItemInt::readConfig( KConfig *config ) +{ + KConfigGroup cg(config, mGroup ); + mReference = cg.readEntry( mKey, mDefault ); + if (mHasMin) + mReference = qMax(mReference, mMin); + if (mHasMax) + mReference = qMin(mReference, mMax); + mLoadedValue = mReference; + + readImmutability( cg ); +} + +void KCoreConfigSkeleton::ItemInt::setProperty(const QVariant & p) +{ + mReference = p.toInt(); +} + +bool KCoreConfigSkeleton::ItemInt::isEqual(const QVariant &v) const +{ + return mReference == v.toInt(); +} + +QVariant KCoreConfigSkeleton::ItemInt::property() const +{ + return QVariant(mReference); +} + +QVariant KCoreConfigSkeleton::ItemInt::minValue() const +{ + if (mHasMin) + return QVariant(mMin); + return QVariant(); +} + +QVariant KCoreConfigSkeleton::ItemInt::maxValue() const +{ + if (mHasMax) + return QVariant(mMax); + return QVariant(); +} + +void KCoreConfigSkeleton::ItemInt::setMinValue(qint32 v) +{ + mHasMin = true; + mMin = v; +} + +void KCoreConfigSkeleton::ItemInt::setMaxValue(qint32 v) +{ + mHasMax = true; + mMax = v; +} + + +KCoreConfigSkeleton::ItemLongLong::ItemLongLong( const QString &_group, const QString &_key, + qint64 &reference, qint64 defaultValue ) + : KConfigSkeletonGenericItem<qint64>( _group, _key, reference, defaultValue ) + ,mHasMin(false), mHasMax(false) +{ +} + +void KCoreConfigSkeleton::ItemLongLong::readConfig( KConfig *config ) +{ + KConfigGroup cg(config, mGroup ); + mReference = cg.readEntry( mKey, mDefault ); + if (mHasMin) + mReference = qMax(mReference, mMin); + if (mHasMax) + mReference = qMin(mReference, mMax); + mLoadedValue = mReference; + + readImmutability( cg ); +} + +void KCoreConfigSkeleton::ItemLongLong::setProperty(const QVariant & p) +{ + mReference = p.toLongLong(); +} + +bool KCoreConfigSkeleton::ItemLongLong::isEqual(const QVariant &v) const +{ + return mReference == v.toLongLong(); +} + +QVariant KCoreConfigSkeleton::ItemLongLong::property() const +{ + return QVariant(mReference); +} + +QVariant KCoreConfigSkeleton::ItemLongLong::minValue() const +{ + if (mHasMin) + return QVariant(mMin); + return QVariant(); +} + +QVariant KCoreConfigSkeleton::ItemLongLong::maxValue() const +{ + if (mHasMax) + return QVariant(mMax); + return QVariant(); +} + +void KCoreConfigSkeleton::ItemLongLong::setMinValue(qint64 v) +{ + mHasMin = true; + mMin = v; +} + +void KCoreConfigSkeleton::ItemLongLong::setMaxValue(qint64 v) +{ + mHasMax = true; + mMax = v; +} + +KCoreConfigSkeleton::ItemEnum::ItemEnum( const QString &_group, const QString &_key, + qint32 &reference, + const QList<Choice> &choices, + qint32 defaultValue ) + : ItemInt( _group, _key, reference, defaultValue ), mChoices(choices) +{ +} + +void KCoreConfigSkeleton::ItemEnum::readConfig( KConfig *config ) +{ + KConfigGroup cg(config, mGroup ); + if (!cg.hasKey(mKey)) + { + mReference = mDefault; + } + else + { + int i = 0; + mReference = -1; + QString tmp = cg.readEntry( mKey, QString() ).toLower(); + for(QList<Choice>::ConstIterator it = mChoices.constBegin(); + it != mChoices.constEnd(); ++it, ++i) + { + if ((*it).name.toLower() == tmp) + { + mReference = i; + break; + } + } + if (mReference == -1) + mReference = cg.readEntry( mKey, mDefault ); + } + mLoadedValue = mReference; + + readImmutability( cg ); +} + +void KCoreConfigSkeleton::ItemEnum::writeConfig( KConfig *config ) +{ + if ( mReference != mLoadedValue ) // WABA: Is this test needed? + { + KConfigGroup cg(config, mGroup ); + if ((mDefault == mReference) && !cg.hasDefault( mKey)) + cg.revertToDefault( mKey ); + else if ((mReference >= 0) && (mReference < (int) mChoices.count())) + cg.writeEntry( mKey, mChoices[mReference].name ); + else + cg.writeEntry( mKey, mReference ); + } +} + +QList<KCoreConfigSkeleton::ItemEnum::Choice> KCoreConfigSkeleton::ItemEnum::choices() const +{ + return mChoices; +} + +QList<KCoreConfigSkeleton::ItemEnum::Choice> KCoreConfigSkeleton::ItemEnum::choices2() const +{ + return mChoices; +} + +KCoreConfigSkeleton::ItemUInt::ItemUInt( const QString &_group, const QString &_key, + quint32 &reference, + quint32 defaultValue ) + : KConfigSkeletonGenericItem<quint32>( _group, _key, reference, defaultValue ) + ,mHasMin(false), mHasMax(false) +{ +} + +void KCoreConfigSkeleton::ItemUInt::readConfig( KConfig *config ) +{ + KConfigGroup cg(config, mGroup ); + mReference = cg.readEntry( mKey, mDefault ); + if (mHasMin) + mReference = qMax(mReference, mMin); + if (mHasMax) + mReference = qMin(mReference, mMax); + mLoadedValue = mReference; + + readImmutability( cg ); +} + +void KCoreConfigSkeleton::ItemUInt::setProperty(const QVariant & p) +{ + mReference = p.toUInt(); +} + +bool KCoreConfigSkeleton::ItemUInt::isEqual(const QVariant &v) const +{ + return mReference == v.toUInt(); +} + +QVariant KCoreConfigSkeleton::ItemUInt::property() const +{ + return QVariant(mReference); +} + +QVariant KCoreConfigSkeleton::ItemUInt::minValue() const +{ + if (mHasMin) + return QVariant(mMin); + return QVariant(); +} + +QVariant KCoreConfigSkeleton::ItemUInt::maxValue() const +{ + if (mHasMax) + return QVariant(mMax); + return QVariant(); +} + +void KCoreConfigSkeleton::ItemUInt::setMinValue(quint32 v) +{ + mHasMin = true; + mMin = v; +} + +void KCoreConfigSkeleton::ItemUInt::setMaxValue(quint32 v) +{ + mHasMax = true; + mMax = v; +} + + +KCoreConfigSkeleton::ItemULongLong::ItemULongLong( const QString &_group, const QString &_key, + quint64 &reference, quint64 defaultValue ) + : KConfigSkeletonGenericItem<quint64>( _group, _key, reference, defaultValue ) + ,mHasMin(false), mHasMax(false) +{ +} + +void KCoreConfigSkeleton::ItemULongLong::readConfig( KConfig *config ) +{ + KConfigGroup cg(config, mGroup ); + mReference = cg.readEntry( mKey, mDefault ); + if (mHasMin) + mReference = qMax(mReference, mMin); + if (mHasMax) + mReference = qMin(mReference, mMax); + mLoadedValue = mReference; + + readImmutability( cg ); +} + +void KCoreConfigSkeleton::ItemULongLong::setProperty(const QVariant & p) +{ + mReference = p.toULongLong(); +} + +bool KCoreConfigSkeleton::ItemULongLong::isEqual(const QVariant &v) const +{ + return mReference == v.toULongLong(); +} + +QVariant KCoreConfigSkeleton::ItemULongLong::property() const +{ + return QVariant(mReference); +} + +QVariant KCoreConfigSkeleton::ItemULongLong::minValue() const +{ + if (mHasMin) + return QVariant(mMin); + return QVariant(); +} + +QVariant KCoreConfigSkeleton::ItemULongLong::maxValue() const +{ + if (mHasMax) + return QVariant(mMax); + return QVariant(); +} + +void KCoreConfigSkeleton::ItemULongLong::setMinValue(quint64 v) +{ + mHasMin = true; + mMin = v; +} + +void KCoreConfigSkeleton::ItemULongLong::setMaxValue(quint64 v) +{ + mHasMax = true; + mMax = v; +} + +KCoreConfigSkeleton::ItemDouble::ItemDouble( const QString &_group, const QString &_key, + double &reference, double defaultValue ) + : KConfigSkeletonGenericItem<double>( _group, _key, reference, defaultValue ) + ,mHasMin(false), mHasMax(false) +{ +} + +void KCoreConfigSkeleton::ItemDouble::readConfig( KConfig *config ) +{ + KConfigGroup cg(config, mGroup ); + mReference = cg.readEntry( mKey, mDefault ); + if (mHasMin) + mReference = qMax(mReference, mMin); + if (mHasMax) + mReference = qMin(mReference, mMax); + mLoadedValue = mReference; + + readImmutability( cg ); +} + +void KCoreConfigSkeleton::ItemDouble::setProperty(const QVariant & p) +{ + mReference = p.toDouble(); +} + +bool KCoreConfigSkeleton::ItemDouble::isEqual(const QVariant &v) const +{ + return mReference == v.toDouble(); +} + +QVariant KCoreConfigSkeleton::ItemDouble::property() const +{ + return QVariant(mReference); +} + +QVariant KCoreConfigSkeleton::ItemDouble::minValue() const +{ + if (mHasMin) + return QVariant(mMin); + return QVariant(); +} + +QVariant KCoreConfigSkeleton::ItemDouble::maxValue() const +{ + if (mHasMax) + return QVariant(mMax); + return QVariant(); +} + +void KCoreConfigSkeleton::ItemDouble::setMinValue(double v) +{ + mHasMin = true; + mMin = v; +} + +void KCoreConfigSkeleton::ItemDouble::setMaxValue(double v) +{ + mHasMax = true; + mMax = v; +} + + +KCoreConfigSkeleton::ItemRect::ItemRect( const QString &_group, const QString &_key, + QRect &reference, + const QRect &defaultValue ) + : KConfigSkeletonGenericItem<QRect>( _group, _key, reference, defaultValue ) +{ +} + +void KCoreConfigSkeleton::ItemRect::readConfig( KConfig *config ) +{ + KConfigGroup cg(config, mGroup ); + mReference = cg.readEntry( mKey, mDefault ); + mLoadedValue = mReference; + + readImmutability( cg ); +} + +void KCoreConfigSkeleton::ItemRect::setProperty(const QVariant & p) +{ + mReference = p.toRect(); +} + +bool KCoreConfigSkeleton::ItemRect::isEqual(const QVariant &v) const +{ + return mReference == v.toRect(); +} + +QVariant KCoreConfigSkeleton::ItemRect::property() const +{ + return QVariant(mReference); +} + + +KCoreConfigSkeleton::ItemPoint::ItemPoint( const QString &_group, const QString &_key, + QPoint &reference, + const QPoint &defaultValue ) + : KConfigSkeletonGenericItem<QPoint>( _group, _key, reference, defaultValue ) +{ +} + +void KCoreConfigSkeleton::ItemPoint::readConfig( KConfig *config ) +{ + KConfigGroup cg(config, mGroup ); + mReference = cg.readEntry( mKey, mDefault ); + mLoadedValue = mReference; + + readImmutability( cg ); +} + +void KCoreConfigSkeleton::ItemPoint::setProperty(const QVariant & p) +{ + mReference = p.toPoint(); +} + +bool KCoreConfigSkeleton::ItemPoint::isEqual(const QVariant &v) const +{ + return mReference == v.toPoint(); +} + +QVariant KCoreConfigSkeleton::ItemPoint::property() const +{ + return QVariant(mReference); +} + + +KCoreConfigSkeleton::ItemSize::ItemSize( const QString &_group, const QString &_key, + QSize &reference, + const QSize &defaultValue ) + : KConfigSkeletonGenericItem<QSize>( _group, _key, reference, defaultValue ) +{ +} + +void KCoreConfigSkeleton::ItemSize::readConfig( KConfig *config ) +{ + KConfigGroup cg(config, mGroup ); + mReference = cg.readEntry( mKey, mDefault ); + mLoadedValue = mReference; + + readImmutability( cg ); +} + +void KCoreConfigSkeleton::ItemSize::setProperty(const QVariant & p) +{ + mReference = p.toSize(); +} + +bool KCoreConfigSkeleton::ItemSize::isEqual(const QVariant &v) const +{ + return mReference == v.toSize(); +} + +QVariant KCoreConfigSkeleton::ItemSize::property() const +{ + return QVariant(mReference); +} + + +KCoreConfigSkeleton::ItemDateTime::ItemDateTime( const QString &_group, const QString &_key, + QDateTime &reference, + const QDateTime &defaultValue ) + : KConfigSkeletonGenericItem<QDateTime>( _group, _key, reference, defaultValue ) +{ +} + +void KCoreConfigSkeleton::ItemDateTime::readConfig( KConfig *config ) +{ + KConfigGroup cg(config, mGroup ); + mReference = cg.readEntry( mKey, mDefault ); + mLoadedValue = mReference; + + readImmutability( cg ); +} + +void KCoreConfigSkeleton::ItemDateTime::setProperty(const QVariant & p) +{ + mReference = p.toDateTime(); +} + +bool KCoreConfigSkeleton::ItemDateTime::isEqual(const QVariant &v) const +{ + return mReference == v.toDateTime(); +} + +QVariant KCoreConfigSkeleton::ItemDateTime::property() const +{ + return QVariant(mReference); +} + + +KCoreConfigSkeleton::ItemStringList::ItemStringList( const QString &_group, const QString &_key, + QStringList &reference, + const QStringList &defaultValue ) + : KConfigSkeletonGenericItem<QStringList>( _group, _key, reference, defaultValue ) +{ +} + +void KCoreConfigSkeleton::ItemStringList::readConfig( KConfig *config ) +{ + KConfigGroup cg(config, mGroup ); + if ( !cg.hasKey( mKey ) ) + mReference = mDefault; + else + mReference = cg.readEntry( mKey, mDefault ); + mLoadedValue = mReference; + + readImmutability( cg ); +} + +void KCoreConfigSkeleton::ItemStringList::setProperty(const QVariant & p) +{ + mReference = p.toStringList(); +} + +bool KCoreConfigSkeleton::ItemStringList::isEqual(const QVariant &v) const +{ + return mReference == v.toStringList(); +} + +QVariant KCoreConfigSkeleton::ItemStringList::property() const +{ + return QVariant(mReference); +} + + +KCoreConfigSkeleton::ItemPathList::ItemPathList( const QString &_group, const QString &_key, + QStringList &reference, + const QStringList &defaultValue ) + : ItemStringList( _group, _key, reference, defaultValue ) +{ +} + +void KCoreConfigSkeleton::ItemPathList::readConfig( KConfig *config ) +{ + KConfigGroup cg(config, mGroup ); + if ( !cg.hasKey( mKey ) ) + mReference = mDefault; + else + mReference = cg.readPathEntry( mKey, QStringList() ); + mLoadedValue = mReference; + + readImmutability( cg ); +} + +void KCoreConfigSkeleton::ItemPathList::writeConfig( KConfig *config ) +{ + if ( mReference != mLoadedValue ) // WABA: Is this test needed? + { + KConfigGroup cg(config, mGroup ); + if ((mDefault == mReference) && !cg.hasDefault( mKey)) + cg.revertToDefault( mKey ); + else { + QStringList sl = mReference; + cg.writePathEntry( mKey, sl ); + } + } +} + +KCoreConfigSkeleton::ItemUrlList::ItemUrlList( const QString &_group, const QString &_key, + QList<QUrl> &reference, + const QList<QUrl> &defaultValue ) + : KConfigSkeletonGenericItem<QList<QUrl> >( _group, _key, reference, defaultValue ) +{ +} + +void KCoreConfigSkeleton::ItemUrlList::readConfig( KConfig *config ) +{ + KConfigGroup cg(config, mGroup ); + if ( !cg.hasKey( mKey ) ) + mReference = mDefault; + else { + QStringList strList; + Q_FOREACH (const QUrl& url, mDefault) { + strList.append(url.toString()); + } + mReference.clear(); + const QStringList readList = cg.readEntry<QStringList>(mKey, strList); + Q_FOREACH (const QString& str, readList) { + mReference.append(QUrl(str)); + } + } + mLoadedValue = mReference; + + readImmutability( cg ); +} + +void KCoreConfigSkeleton::ItemUrlList::writeConfig( KConfig *config ) +{ + if ( mReference != mLoadedValue ) // WABA: Is this test needed? + { + KConfigGroup cg(config, mGroup ); + if ((mDefault == mReference) && !cg.hasDefault( mKey)) + cg.revertToDefault( mKey ); + else { + QStringList strList; + Q_FOREACH (const QUrl& url, mReference) { + strList.append(url.toString()); + } + cg.writeEntry<QStringList>(mKey, strList); + } + } +} + +void KCoreConfigSkeleton::ItemUrlList::setProperty(const QVariant & p) +{ + mReference = qvariant_cast<QList<QUrl> >(p); +} + +bool KCoreConfigSkeleton::ItemUrlList::isEqual(const QVariant &v) const +{ + return mReference == qvariant_cast<QList<QUrl> >(v); +} + +QVariant KCoreConfigSkeleton::ItemUrlList::property() const +{ + return qVariantFromValue<QList<QUrl> >(mReference); +} + + +KCoreConfigSkeleton::ItemIntList::ItemIntList( const QString &_group, const QString &_key, + QList<int> &reference, + const QList<int> &defaultValue ) + : KConfigSkeletonGenericItem<QList<int> >( _group, _key, reference, defaultValue ) +{ +} + +void KCoreConfigSkeleton::ItemIntList::readConfig( KConfig *config ) +{ + KConfigGroup cg(config, mGroup ); + if ( !cg.hasKey( mKey ) ) + mReference = mDefault; + else + mReference = cg.readEntry( mKey , mDefault ); + mLoadedValue = mReference; + + readImmutability( cg ); +} + +void KCoreConfigSkeleton::ItemIntList::setProperty(const QVariant &p) +{ + mReference = qvariant_cast< QList<int> >(p); +} + +bool KCoreConfigSkeleton::ItemIntList::isEqual(const QVariant &v) const +{ + return mReference == qvariant_cast< QList<int> >(v); +} + +QVariant KCoreConfigSkeleton::ItemIntList::property() const +{ + return qVariantFromValue< QList<int> >(mReference); +} + +//static int kCoreConfigSkeletionDebugArea() { static int s_area = KDebug::registerArea("kdecore (KConfigSkeleton)"); return s_area; } + +KCoreConfigSkeleton::KCoreConfigSkeleton(const QString &configname, QObject* parent) + : QObject(parent), + d( new Private ) +{ + //qDebug() << "Creating KCoreConfigSkeleton (" << (void *)this << ")"; + + d->mConfig = KSharedConfig::openConfig( configname ); +} + +KCoreConfigSkeleton::KCoreConfigSkeleton(KSharedConfig::Ptr pConfig, QObject* parent) + : QObject(parent), + d( new Private ) +{ + //qDebug() << "Creating KCoreConfigSkeleton (" << (void *)this << ")"; + d->mConfig = pConfig; +} + + +KCoreConfigSkeleton::~KCoreConfigSkeleton() +{ + delete d; +} + +void KCoreConfigSkeleton::setCurrentGroup( const QString &group ) +{ + d->mCurrentGroup = group; +} + +QString KCoreConfigSkeleton::currentGroup() const +{ + return d->mCurrentGroup; +} + +KConfig *KCoreConfigSkeleton::config() +{ + return d->mConfig.data(); +} + +const KConfig *KCoreConfigSkeleton::config() const +{ + return d->mConfig.data(); +} + +void KCoreConfigSkeleton::setSharedConfig(KSharedConfig::Ptr pConfig) +{ + d->mConfig = pConfig; +} + +KConfigSkeletonItem::List KCoreConfigSkeleton::items() const +{ + return d->mItems; +} + +bool KCoreConfigSkeleton::useDefaults(bool b) +{ + if (b == d->mUseDefaults) + return d->mUseDefaults; + + d->mUseDefaults = b; + KConfigSkeletonItem::List::ConstIterator it; + for( it = d->mItems.constBegin(); it != d->mItems.constEnd(); ++it ) + { + (*it)->swapDefault(); + } + usrUseDefaults(b); + return !d->mUseDefaults; +} + +void KCoreConfigSkeleton::setDefaults() +{ + KConfigSkeletonItem::List::ConstIterator it; + for( it = d->mItems.constBegin(); it != d->mItems.constEnd(); ++it ) { + (*it)->setDefault(); + } + usrSetDefaults(); +} + +void KCoreConfigSkeleton::readConfig() +{ + // qDebug(); + d->mConfig->reparseConfiguration(); + KConfigSkeletonItem::List::ConstIterator it; + for( it = d->mItems.constBegin(); it != d->mItems.constEnd(); ++it ) + { + (*it)->readConfig( d->mConfig.data() ); + } + usrReadConfig(); +} + +bool KCoreConfigSkeleton::writeConfig() +{ + //qDebug(); + KConfigSkeletonItem::List::ConstIterator it; + for( it = d->mItems.constBegin(); it != d->mItems.constEnd(); ++it ) + { + (*it)->writeConfig( d->mConfig.data() ); + } + if (!usrWriteConfig()) + return false; + + if (d->mConfig->isDirty()) { + if (!d->mConfig->sync()) + return false; + readConfig(); + emit configChanged(); + } + return true; +} + +bool KCoreConfigSkeleton::usrUseDefaults(bool) +{ + return false; +} + +void KCoreConfigSkeleton::usrSetDefaults() +{ +} + +void KCoreConfigSkeleton::usrReadConfig() +{ +} + +bool KCoreConfigSkeleton::usrWriteConfig() +{ + return true; +} + +void KCoreConfigSkeleton::addItem( KConfigSkeletonItem *item, const QString &name ) +{ + if (d->mItems.contains(item)) { + if (item->name() == name || + (name.isEmpty() && item->name() == item->key())) { + // nothing to do -> it is already in our collection + // and the name isn't changing + return; + } + + d->mItemDict.remove(item->name()); + } else { + d->mItems.append( item ); + } + + item->setName(name.isEmpty() ? item->key() : name); + d->mItemDict.insert(item->name(), item); + item->readDefault(d->mConfig.data()); + item->readConfig(d->mConfig.data()); +} + +void KCoreConfigSkeleton::removeItem(const QString &name) +{ + KConfigSkeletonItem *item = d->mItemDict.value(name); + if (item) { + d->mItems.removeAll(item); + d->mItemDict.remove(item->name()); + delete item; + } +} + +void KCoreConfigSkeleton::clearItems() +{ + KConfigSkeletonItem::List items = d->mItems; + d->mItems.clear(); + d->mItemDict.clear(); + qDeleteAll(items); +} + +KCoreConfigSkeleton::ItemString *KCoreConfigSkeleton::addItemString( const QString &name, QString &reference, + const QString &defaultValue, const QString &key ) +{ + KCoreConfigSkeleton::ItemString *item; + item = new KCoreConfigSkeleton::ItemString( d->mCurrentGroup, key.isEmpty() ? name : key, + reference, defaultValue, + KCoreConfigSkeleton::ItemString::Normal ); + addItem( item, name ); + return item; +} + +KCoreConfigSkeleton::ItemPassword *KCoreConfigSkeleton::addItemPassword( const QString &name, QString &reference, + const QString &defaultValue, const QString &key ) +{ + KCoreConfigSkeleton::ItemPassword *item; + item = new KCoreConfigSkeleton::ItemPassword( d->mCurrentGroup, key.isNull() ? name : key, + reference, defaultValue ); + addItem( item, name ); + return item; +} + +KCoreConfigSkeleton::ItemPath *KCoreConfigSkeleton::addItemPath( const QString &name, QString &reference, + const QString &defaultValue, const QString &key ) +{ + KCoreConfigSkeleton::ItemPath *item; + item = new KCoreConfigSkeleton::ItemPath( d->mCurrentGroup, key.isNull() ? name : key, + reference, defaultValue ); + addItem( item, name ); + return item; +} + +KCoreConfigSkeleton::ItemProperty *KCoreConfigSkeleton::addItemProperty( const QString &name, QVariant &reference, + const QVariant &defaultValue, const QString &key ) +{ + KCoreConfigSkeleton::ItemProperty *item; + item = new KCoreConfigSkeleton::ItemProperty( d->mCurrentGroup, key.isNull() ? name : key, + reference, defaultValue ); + addItem( item, name ); + return item; +} + +KCoreConfigSkeleton::ItemBool *KCoreConfigSkeleton::addItemBool( const QString &name, bool &reference, + bool defaultValue, const QString &key ) +{ + KCoreConfigSkeleton::ItemBool *item; + item = new KCoreConfigSkeleton::ItemBool( d->mCurrentGroup, key.isNull() ? name : key, + reference, defaultValue ); + addItem( item, name ); + return item; +} + +KCoreConfigSkeleton::ItemInt *KCoreConfigSkeleton::addItemInt( const QString &name, qint32 &reference, + qint32 defaultValue, const QString &key ) +{ + KCoreConfigSkeleton::ItemInt *item; + item = new KCoreConfigSkeleton::ItemInt( d->mCurrentGroup, key.isNull() ? name : key, + reference, defaultValue ); + addItem( item, name ); + return item; +} + +KCoreConfigSkeleton::ItemUInt *KCoreConfigSkeleton::addItemUInt( const QString &name, quint32 &reference, + quint32 defaultValue, const QString &key ) +{ + KCoreConfigSkeleton::ItemUInt *item; + item = new KCoreConfigSkeleton::ItemUInt( d->mCurrentGroup, key.isNull() ? name : key, + reference, defaultValue ); + addItem( item, name ); + return item; +} + +KCoreConfigSkeleton::ItemLongLong *KCoreConfigSkeleton::addItemLongLong( const QString &name, qint64 &reference, + qint64 defaultValue, const QString &key ) +{ + KCoreConfigSkeleton::ItemLongLong *item; + item = new KCoreConfigSkeleton::ItemLongLong( d->mCurrentGroup, key.isNull() ? name : key, + reference, defaultValue ); + addItem( item, name ); + return item; +} + +#ifndef KDE_NO_DEPRECATED +KCoreConfigSkeleton::ItemLongLong *KCoreConfigSkeleton::addItemInt64( + const QString& name, + qint64 &reference, + qint64 defaultValue, + const QString & key) +{ + return addItemLongLong(name, reference, defaultValue, key); +} +#endif + +KCoreConfigSkeleton::ItemULongLong *KCoreConfigSkeleton::addItemULongLong( const QString &name, quint64 &reference, + quint64 defaultValue, const QString &key ) +{ + KCoreConfigSkeleton::ItemULongLong *item; + item = new KCoreConfigSkeleton::ItemULongLong( d->mCurrentGroup, key.isNull() ? name : key, + reference, defaultValue ); + addItem( item, name ); + return item; +} + +#ifndef KDE_NO_DEPRECATED +KCoreConfigSkeleton::ItemULongLong *KCoreConfigSkeleton::addItemUInt64( + const QString & name, + quint64 &reference, + quint64 defaultValue, + const QString & key) +{ + return addItemULongLong(name, reference, defaultValue, key); +} +#endif + +KCoreConfigSkeleton::ItemDouble *KCoreConfigSkeleton::addItemDouble( const QString &name, double &reference, + double defaultValue, const QString &key ) +{ + KCoreConfigSkeleton::ItemDouble *item; + item = new KCoreConfigSkeleton::ItemDouble( d->mCurrentGroup, key.isNull() ? name : key, + reference, defaultValue ); + addItem( item, name ); + return item; +} + +KCoreConfigSkeleton::ItemRect *KCoreConfigSkeleton::addItemRect( const QString &name, QRect &reference, + const QRect &defaultValue, const QString &key ) +{ + KCoreConfigSkeleton::ItemRect *item; + item = new KCoreConfigSkeleton::ItemRect( d->mCurrentGroup, key.isNull() ? name : key, + reference, defaultValue ); + addItem( item, name ); + return item; +} + +KCoreConfigSkeleton::ItemPoint *KCoreConfigSkeleton::addItemPoint( const QString &name, QPoint &reference, + const QPoint &defaultValue, const QString &key ) +{ + KCoreConfigSkeleton::ItemPoint *item; + item = new KCoreConfigSkeleton::ItemPoint( d->mCurrentGroup, key.isNull() ? name : key, + reference, defaultValue ); + addItem( item, name ); + return item; +} + +KCoreConfigSkeleton::ItemSize *KCoreConfigSkeleton::addItemSize( const QString &name, QSize &reference, + const QSize &defaultValue, const QString &key ) +{ + KCoreConfigSkeleton::ItemSize *item; + item = new KCoreConfigSkeleton::ItemSize( d->mCurrentGroup, key.isNull() ? name : key, + reference, defaultValue ); + addItem( item, name ); + return item; +} + +KCoreConfigSkeleton::ItemDateTime *KCoreConfigSkeleton::addItemDateTime( const QString &name, QDateTime &reference, + const QDateTime &defaultValue, const QString &key ) +{ + KCoreConfigSkeleton::ItemDateTime *item; + item = new KCoreConfigSkeleton::ItemDateTime( d->mCurrentGroup, key.isNull() ? name : key, + reference, defaultValue ); + addItem( item, name ); + return item; +} + +KCoreConfigSkeleton::ItemStringList *KCoreConfigSkeleton::addItemStringList( const QString &name, QStringList &reference, + const QStringList &defaultValue, const QString &key ) +{ + KCoreConfigSkeleton::ItemStringList *item; + item = new KCoreConfigSkeleton::ItemStringList( d->mCurrentGroup, key.isNull() ? name : key, + reference, defaultValue ); + addItem( item, name ); + return item; +} + +KCoreConfigSkeleton::ItemIntList *KCoreConfigSkeleton::addItemIntList( const QString &name, QList<int> &reference, + const QList<int> &defaultValue, const QString &key ) +{ + KCoreConfigSkeleton::ItemIntList *item; + item = new KCoreConfigSkeleton::ItemIntList( d->mCurrentGroup, key.isNull() ? name : key, + reference, defaultValue ); + addItem( item, name ); + return item; +} + +bool KCoreConfigSkeleton::isImmutable(const QString &name) const +{ + KConfigSkeletonItem *item = findItem(name); + return !item || item->isImmutable(); +} + +KConfigSkeletonItem *KCoreConfigSkeleton::findItem(const QString &name) const +{ + return d->mItemDict.value(name); +} + diff --git a/tier1/kconfig/src/core/kcoreconfigskeleton.h b/tier1/kconfig/src/core/kcoreconfigskeleton.h new file mode 100644 index 00000000..75f6fa28 --- /dev/null +++ b/tier1/kconfig/src/core/kcoreconfigskeleton.h @@ -0,0 +1,1407 @@ +/* + * This file is part of KDE. + * + * Copyright (c) 2001,2002,2003 Cornelius Schumacher <schumacher@kde.org> + * Copyright (c) 2003 Waldo Bastian <bastian@kde.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef KCORECONFIGSKELETON_H +#define KCORECONFIGSKELETON_H + +#include <kconfigcore_export.h> + +#include <ksharedconfig.h> +#include <kconfiggroup.h> + +#include <QtCore/QDate> +#include <QtCore/QHash> +#include <QtCore/QRect> +#include <QtCore/QStringList> +#include <QtCore/QVariant> +#include <QtCore/QUrl> + + class KConfigSkeletonItemPrivate; + /** + * \class KConfigSkeletonItem kcoreconfigskeleton.h <KConfigSkeletonItem> + * + * @short Class for storing a preferences setting + * @author Cornelius Schumacher + * @see KCoreConfigSkeleton + * + * This class represents one preferences setting as used by @ref KCoreConfigSkeleton. + * Subclasses of KConfigSkeletonItem implement storage functions for a certain type of + * setting. Normally you don't have to use this class directly. Use the special + * addItem() functions of KCoreConfigSkeleton instead. If you subclass this class you will + * have to register instances with the function KCoreConfigSkeleton::addItem(). + */ + class KCONFIGCORE_EXPORT KConfigSkeletonItem + { + public: + typedef QList < KConfigSkeletonItem * >List; + typedef QHash < QString, KConfigSkeletonItem* > Dict; + typedef QHash < QString, KConfigSkeletonItem* >::Iterator DictIterator; + + /** + * Constructor. + * + * @param _group Config file group. + * @param _key Config file key. + */ + KConfigSkeletonItem(const QString & _group, const QString & _key); + + /** + * Destructor. + */ + virtual ~KConfigSkeletonItem(); + + /** + * Set config file group. + */ + void setGroup( const QString &_group ); + + /** + * Return config file group. + */ + QString group() const; + + /** + * Set config file key. + */ + void setKey( const QString &_key ); + + /** + * Return config file key. + */ + QString key() const; + + /** + * Set internal name of entry. + */ + void setName(const QString &_name); + + /** + * Return internal name of entry. + */ + QString name() const; + + /** + Set label providing a translated one-line description of the item. + */ + void setLabel( const QString &l ); + + /** + Return label of item. See setLabel(). + */ + QString label() const; + + /** + Set ToolTip description of item. + @since 4.2 + */ + void setToolTip( const QString &t ); + + /** + Return ToolTip description of item. See setToolTip(). + @since 4.2 + */ + QString toolTip() const; + + /** + Set WhatsThis description of item. + */ + void setWhatsThis( const QString &w ); + + /** + Return WhatsThis description of item. See setWhatsThis(). + */ + QString whatsThis() const; + + /** + * This function is called by @ref KCoreConfigSkeleton to read the value for this setting + * from a config file. + */ + virtual void readConfig(KConfig *) = 0; + + /** + * This function is called by @ref KCoreConfigSkeleton to write the value of this setting + * to a config file. + */ + virtual void writeConfig(KConfig *) = 0; + + /** + * Read global default value. + */ + virtual void readDefault(KConfig *) = 0; + + /** + * Set item to @p p + */ + virtual void setProperty(const QVariant &p) = 0; + + /** + * Check whether the item is equal to p. + * + * Use this function to compare items that use custom types, + * because QVariant::operator== will not work for those. + * + * @param p QVariant to compare to + * @return true if the item is equal to p, false otherwise + */ + virtual bool isEqual(const QVariant &p) const = 0; + + /** + * Return item as property + */ + virtual QVariant property() const = 0; + + /** + * Return minimum value of item or invalid if not specified + */ + virtual QVariant minValue() const; + + /** + * Return maximum value of item or invalid if not specified + */ + virtual QVariant maxValue() const; + + /** + * Sets the current value to the default value. + */ + virtual void setDefault() = 0; + + /** + * Exchanges the current value with the default value + * Used by KCoreConfigSkeleton::useDefaults(bool); + */ + virtual void swapDefault() = 0; + + /** + * Return if the entry can be modified. + */ + bool isImmutable() const; + + protected: + /** + * sets mIsImmutable to true if mKey in config is immutable + * @param group KConfigGroup to check if mKey is immutable in + */ + void readImmutability(const KConfigGroup &group); + + QString mGroup; ///< The group name for this item + QString mKey; ///< The config key for this item + QString mName; ///< The name of this item + + private: + KConfigSkeletonItemPrivate * const d; + }; + + +/** + * \class KConfigSkeletonGenericItem kcoreconfigskeleton.h <KConfigSkeletonGenericItem> + */ +template < typename T > class KConfigSkeletonGenericItem:public KConfigSkeletonItem + { + public: + /** @copydoc KConfigSkeletonItem(const QString&, const QString&) + @param reference The initial value to hold in the item + @param defaultValue The default value for the item + */ + KConfigSkeletonGenericItem(const QString & _group, const QString & _key, T & reference, + T defaultValue) + : KConfigSkeletonItem(_group, _key), mReference(reference), + mDefault(defaultValue), mLoadedValue(defaultValue) + { + } + + /** + * Set value of this KConfigSkeletonItem. + */ + void setValue(const T & v) + { + mReference = v; + } + + /** + * Return value of this KConfigSkeletonItem. + */ + T & value() + { + return mReference; + } + + /** + * Return const value of this KConfigSkeletonItem. + */ + const T & value() const + { + return mReference; + } + + /** + Set default value for this item. + */ + virtual void setDefaultValue( const T &v ) + { + mDefault = v; + } + + /** + Set the value for this item to the default value + */ + virtual void setDefault() + { + mReference = mDefault; + } + + /** @copydoc KConfigSkeletonItem::writeConfig(KConfig *) */ + virtual void writeConfig(KConfig * config) + { + if ( mReference != mLoadedValue ) // Is this needed? + { + KConfigGroup cg(config, mGroup); + if ((mDefault == mReference) && !cg.hasDefault( mKey)) + cg.revertToDefault( mKey ); + else + cg.writeEntry(mKey, mReference); + } + } + + /** @copydoc KConfigSkeletonItem::readDefault(KConfig*) */ + void readDefault(KConfig * config) + { + config->setReadDefaults(true); + readConfig(config); + config->setReadDefaults(false); + mDefault = mReference; + } + + /** @copydoc KConfigSkeletonItem::swapDefault() */ + void swapDefault() + { + T tmp = mReference; + mReference = mDefault; + mDefault = tmp; + } + + protected: + T & mReference; ///< Stores the value for this item + T mDefault; ///< The default value for this item + T mLoadedValue; + }; + + /** + * \class KCoreConfigSkeleton kcoreconfigskeleton.h <KCoreConfigSkeleton> + * + * @short Class for handling preferences settings for an application. + * @author Cornelius Schumacher + * @see KConfigSkeletonItem + * + * This class provides an interface to preferences settings. Preferences items + * can be registered by the addItem() function corresponding to the data type of + * the setting. KCoreConfigSkeleton then handles reading and writing of config files and + * setting of default values. + * + * Normally you will subclass KCoreConfigSkeleton, add data members for the preferences + * settings and register the members in the constructor of the subclass. + * + * Example: + * \code + * class MyPrefs : public KCoreConfigSkeleton + * { + * public: + * MyPrefs() + * { + * setCurrentGroup("MyGroup"); + * addItemBool("MySetting1", mMyBool, false); + * addItemPoint("MySetting2", mMyPoint, QPoint(100, 200)); + * + * setCurrentGroup("MyOtherGroup"); + * addItemDouble("MySetting3", mMyDouble, 3.14); + * } + * + * bool mMyBool; + * QPoint mMyPoint; + * double mMyDouble; + * } + * \endcode + * + * It might be convenient in many cases to make this subclass of KCoreConfigSkeleton a + * singleton for global access from all over the application without passing + * references to the KCoreConfigSkeleton object around. + * + * You can write the data to the configuration file by calling @ref writeConfig() + * and read the data from the configuration file by calling @ref readConfig(). + * If you want to watch for config changes, use @ref configChanged() signal. + * + * If you have items, which are not covered by the existing addItem() functions + * you can add customized code for reading, writing and default setting by + * implementing the functions @ref usrUseDefaults(), @ref usrReadConfig() and + * @ref usrWriteConfig(). + * + * Internally preferences settings are stored in instances of subclasses of + * @ref KConfigSkeletonItem. You can also add KConfigSkeletonItem subclasses + * for your own types and call the generic @ref addItem() to register them. + * + * In many cases you don't have to write the specific KCoreConfigSkeleton + * subclasses yourself, but you can use \ref kconfig_compiler to automatically + * generate the C++ code from an XML description of the configuration options. + * + * Use KConfigSkeleton if you need GUI types as well. + */ +class KCONFIGCORE_EXPORT KCoreConfigSkeleton : public QObject +{ + Q_OBJECT +public: + /** + * Class for handling a string preferences item. + */ + class KCONFIGCORE_EXPORT ItemString:public KConfigSkeletonGenericItem < QString > + { + public: + enum Type { Normal, Password, Path }; + + /** @enum Type + The type of string that is held in this item + + @var ItemString::Type ItemString::Normal + A normal string + + @var ItemString::Type ItemString::Password + A password string + + @var ItemString::Type ItemString::Path + A path to a file or directory + */ + + + /** @copydoc KConfigSkeletonGenericItem::KConfigSkeletonGenericItem + @param type The type of string held by the item + */ + ItemString(const QString & _group, const QString & _key, + QString & reference, + const QString & defaultValue = QLatin1String(""), // NOT QString() !! + Type type = Normal); + + /** @copydoc KConfigSkeletonItem::writeConfig(KConfig*) */ + void writeConfig(KConfig * config); + + /** @copydoc KConfigSkeletonItem::readConfig(KConfig*) */ + void readConfig(KConfig * config); + + /** @copydoc KConfigSkeletonItem::setProperty(const QVariant&) */ + void setProperty(const QVariant & p); + + /** @copydoc KConfigSkeletonItem::isEqual(const QVariant &) const */ + bool isEqual(const QVariant &p) const; + + /** @copydoc KConfigSkeletonItem::property() const */ + QVariant property() const; + + private: + Type mType; + }; + + /** + * Class for handling a password preferences item. + */ + class KCONFIGCORE_EXPORT ItemPassword:public ItemString + { + public: + /** @copydoc KConfigSkeletonGenericItem::KConfigSkeletonGenericItem */ + ItemPassword(const QString & _group, const QString & _key, + QString & reference, + const QString & defaultValue = QLatin1String("")); // NOT QString() !! + }; + + /** + * Class for handling a path preferences item. + */ + class KCONFIGCORE_EXPORT ItemPath:public ItemString + { + public: + /** @copydoc KConfigSkeletonGenericItem::KConfigSkeletonGenericItem */ + ItemPath(const QString & _group, const QString & _key, + QString & reference, + const QString & defaultValue = QString()); + }; + + /** + * Class for handling a url preferences item. + */ + class KCONFIGCORE_EXPORT ItemUrl:public KConfigSkeletonGenericItem < QUrl > + { + public: + + /** @copydoc KConfigSkeletonGenericItem::KConfigSkeletonGenericItem + */ + ItemUrl(const QString & _group, const QString & _key, + QUrl & reference, + const QUrl & defaultValue = QUrl()); + + /** @copydoc KConfigSkeletonItem::writeConfig(KConfig*) */ + void writeConfig(KConfig * config); + + /** @copydoc KConfigSkeletonItem::readConfig(KConfig*) */ + void readConfig(KConfig * config); + + /** @copydoc KConfigSkeletonItem::setProperty(const QVariant&) */ + void setProperty(const QVariant & p); + + /** @copydoc KConfigSkeletonItem::isEqual(const QVariant &) const */ + bool isEqual(const QVariant &p) const; + + /** @copydoc KConfigSkeletonItem::property() const */ + QVariant property() const; + }; + + /** + * Class for handling a QVariant preferences item. + */ + class KCONFIGCORE_EXPORT ItemProperty:public KConfigSkeletonGenericItem < QVariant > + { + public: + /** @copydoc KConfigSkeletonGenericItem::KConfigSkeletonGenericItem */ + ItemProperty(const QString & _group, const QString & _key, + QVariant & reference, const QVariant & defaultValue = 0); + + void readConfig(KConfig * config); + void setProperty(const QVariant & p); + + /** @copydoc KConfigSkeletonItem::isEqual(const QVariant &) const */ + bool isEqual(const QVariant &p) const; + + /** @copydoc KConfigSkeletonItem::property() const */ + QVariant property() const; + }; + + + /** + * Class for handling a bool preferences item. + */ + class KCONFIGCORE_EXPORT ItemBool:public KConfigSkeletonGenericItem < bool > + { + public: + /** @copydoc KConfigSkeletonGenericItem::KConfigSkeletonGenericItem */ + ItemBool(const QString & _group, const QString & _key, bool & reference, + bool defaultValue = true); + + /** @copydoc KConfigSkeletonItem::readConfig(KConfig*) */ + void readConfig(KConfig * config); + + /** @copydoc KConfigSkeletonItem::setProperty(const QVariant&) */ + void setProperty(const QVariant & p); + + /** @copydoc KConfigSkeletonItem::isEqual(const QVariant &) const */ + bool isEqual(const QVariant &p) const; + + /** @copydoc KConfigSkeletonItem::property() const */ + QVariant property() const; + }; + + + /** + * Class for handling a 32-bit integer preferences item. + */ + class KCONFIGCORE_EXPORT ItemInt:public KConfigSkeletonGenericItem < qint32 > + { + public: + /** @copydoc KConfigSkeletonGenericItem::KConfigSkeletonGenericItem */ + ItemInt(const QString & _group, const QString & _key, qint32 &reference, + qint32 defaultValue = 0); + + /** @copydoc KConfigSkeletonItem::readConfig(KConfig*) */ + void readConfig(KConfig * config); + + /** @copydoc KConfigSkeletonItem::setProperty(const QVariant&) */ + void setProperty(const QVariant & p); + + /** @copydoc KConfigSkeletonItem::isEqual(const QVariant &) const */ + bool isEqual(const QVariant &p) const; + + /** @copydoc KConfigSkeletonItem::property() */ + QVariant property() const; + + /** Get the minimum value that is allowed to be stored in this item */ + QVariant minValue() const; + + /** Get the maximum value this is allowed to be stored in this item */ + QVariant maxValue() const; + + /** Set the minimum value for the item + @sa minValue() + */ + void setMinValue(qint32); + + /** Set the maximum value for the item + @sa maxValue + */ + void setMaxValue(qint32); + + private: + bool mHasMin : 1; + bool mHasMax : 1; + qint32 mMin; + qint32 mMax; + }; + + /** + * Class for handling a 64-bit integer preferences item. + */ + class KCONFIGCORE_EXPORT ItemLongLong:public KConfigSkeletonGenericItem < qint64 > + { + public: + /** @copydoc KConfigSkeletonGenericItem::KConfigSkeletonGenericItem */ + ItemLongLong(const QString & _group, const QString & _key, qint64 &reference, + qint64 defaultValue = 0); + + /** @copydoc KConfigSkeletonItem::readConfig(KConfig*) */ + void readConfig(KConfig * config); + + /** @copydoc KConfigSkeletonItem::setProperty(const QVariant&) */ + void setProperty(const QVariant & p); + + /** @copydoc KConfigSkeletonItem::isEqual(const QVariant &) const */ + bool isEqual(const QVariant &p) const; + + /** @copydoc KConfigSkeletonItem::property() */ + QVariant property() const; + + /** @copydoc ItemInt::minValue() */ + QVariant minValue() const; + + /** @copydoc ItemInt::maxValue() */ + QVariant maxValue() const; + + /** @copydoc ItemInt::setMinValue(qint32) */ + void setMinValue(qint64); + + /** @copydoc ItemInt::setMaxValue(qint32) */ + void setMaxValue(qint64); + + private: + bool mHasMin : 1; + bool mHasMax : 1; + qint64 mMin; + qint64 mMax; + }; +#ifndef KDE_NO_DEPRECATED + typedef KCONFIGCORE_DEPRECATED ItemLongLong ItemInt64; +#endif + + /** + * Class for handling enums. + */ + class KCONFIGCORE_EXPORT ItemEnum:public ItemInt + { + public: + struct Choice + { + QString name; + QString label; + QString toolTip; + QString whatsThis; + }; + + /** @copydoc KConfigSkeletonGenericItem::KConfigSkeletonGenericItem + @param choices The list of enums that can be stored in this item + */ + ItemEnum(const QString & _group, const QString & _key, qint32 &reference, + const QList<Choice> &choices, qint32 defaultValue = 0); + + QList<Choice> choices() const; + + /** @copydoc KConfigSkeletonItem::readConfig(KConfig*) */ + void readConfig(KConfig * config); + + /** @copydoc KConfigSkeletonItem::writeConfig(KConfig*) */ + void writeConfig(KConfig * config); + + // Source compatibility with 4.x + typedef Choice Choice2; + QList<Choice> choices2() const; + + private: + QList<Choice> mChoices; + }; + + + /** + * Class for handling an unsigned 32-bit integer preferences item. + */ + class KCONFIGCORE_EXPORT ItemUInt:public KConfigSkeletonGenericItem < quint32 > + { + public: + /** @copydoc KConfigSkeletonGenericItem::KConfigSkeletonGenericItem */ + ItemUInt(const QString & _group, const QString & _key, + quint32 &reference, quint32 defaultValue = 0); + + /** @copydoc KConfigSkeletonItem::readConfig(KConfig*) */ + void readConfig(KConfig * config); + + /** @copydoc KConfigSkeletonItem::setProperty(const QVariant&) */ + void setProperty(const QVariant & p); + + /** @copydoc KConfigSkeletonItem::isEqual(const QVariant &) const */ + bool isEqual(const QVariant &p) const; + + /** @copydoc KConfigSkeletonItem::property() */ + QVariant property() const; + + /** @copydoc ItemInt::minValue() */ + QVariant minValue() const; + + /** @copydoc ItemInt::maxValue() */ + QVariant maxValue() const; + + /** @copydoc ItemInt::setMinValue(qint32) */ + void setMinValue(quint32); + + /** @copydoc ItemInt::setMaxValue(qint32) */ + void setMaxValue(quint32); + + private: + bool mHasMin : 1; + bool mHasMax : 1; + quint32 mMin; + quint32 mMax; + }; + + /** + * Class for handling unsigned 64-bit integer preferences item. + */ + class KCONFIGCORE_EXPORT ItemULongLong:public KConfigSkeletonGenericItem < quint64 > + { + public: + /** @copydoc KConfigSkeletonGenericItem::KConfigSkeletonGenericItem */ + ItemULongLong(const QString & _group, const QString & _key, quint64 &reference, + quint64 defaultValue = 0); + + /** @copydoc KConfigSkeletonItem::readConfig(KConfig*) */ + void readConfig(KConfig * config); + + /** @copydoc KConfigSkeletonItem::setProperty(const QVariant&) */ + void setProperty(const QVariant & p); + + /** @copydoc KConfigSkeletonItem::isEqual(const QVariant &) const */ + bool isEqual(const QVariant &p) const; + + /** @copydoc KConfigSkeletonItem::property() */ + QVariant property() const; + + /** @copydoc ItemInt::minValue() */ + QVariant minValue() const; + + /** @copydoc ItemInt::maxValue() */ + QVariant maxValue() const; + + /** @copydoc ItemInt::setMinValue(qint32) */ + void setMinValue(quint64); + + /** @copydoc ItemInt::setMaxValue(qint32) */ + void setMaxValue(quint64); + + private: + bool mHasMin : 1; + bool mHasMax : 1; + quint64 mMin; + quint64 mMax; + }; +#ifndef KDE_NO_DEPRECATED + typedef KCONFIGCORE_DEPRECATED ItemULongLong ItemUInt64; +#endif + + /** + * Class for handling a floating point preference item. + */ + class KCONFIGCORE_EXPORT ItemDouble:public KConfigSkeletonGenericItem < double > + { + public: + /** @copydoc KConfigSkeletonGenericItem::KConfigSkeletonGenericItem */ + ItemDouble(const QString & _group, const QString & _key, + double &reference, double defaultValue = 0); + + /** @copydoc KConfigSkeletonItem::readConfig(KConfig*) */ + void readConfig(KConfig * config); + + /** @copydoc KConfigSkeletonItem::setProperty(const QVariant&) */ + void setProperty(const QVariant & p); + + /** @copydoc KConfigSkeletonItem::isEqual(const QVariant &) const */ + bool isEqual(const QVariant &p) const; + + /** @copydoc KConfigSkeletonItem::property() */ + QVariant property() const; + + /** @copydoc ItemInt::minValue() */ + QVariant minValue() const; + + /** @copydoc ItemInt::maxValue() */ + QVariant maxValue() const; + + /** @copydoc ItemInt::setMinValue() */ + void setMinValue(double); + + /** @copydoc ItemInt::setMaxValue() */ + void setMaxValue(double); + + private: + bool mHasMin : 1; + bool mHasMax : 1; + double mMin; + double mMax; + }; + + + /** + * Class for handling a QRect preferences item. + */ + class KCONFIGCORE_EXPORT ItemRect:public KConfigSkeletonGenericItem < QRect > + { + public: + /** @copydoc KConfigSkeletonGenericItem::KConfigSkeletonGenericItem */ + ItemRect(const QString & _group, const QString & _key, QRect & reference, + const QRect & defaultValue = QRect()); + + /** @copydoc KConfigSkeletonItem::readConfig(KConfig*) */ + void readConfig(KConfig * config); + + /** @copydoc KConfigSkeletonItem::setProperty(const QVariant&) */ + void setProperty(const QVariant & p); + + /** @copydoc KConfigSkeletonItem::isEqual(const QVariant &) const */ + bool isEqual(const QVariant &p) const; + + /** @copydoc KConfigSkeletonItem::property() */ + QVariant property() const; + }; + + + /** + * Class for handling a QPoint preferences item. + */ + class KCONFIGCORE_EXPORT ItemPoint:public KConfigSkeletonGenericItem < QPoint > + { + public: + /** @copydoc KConfigSkeletonGenericItem::KConfigSkeletonGenericItem */ + ItemPoint(const QString & _group, const QString & _key, QPoint & reference, + const QPoint & defaultValue = QPoint()); + + /** @copydoc KConfigSkeletonItem::readConfig(KConfig*) */ + void readConfig(KConfig * config); + + /** @copydoc KConfigSkeletonItem::setProperty(const QVariant&) */ + void setProperty(const QVariant & p); + + /** @copydoc KConfigSkeletonItem::isEqual(const QVariant &) const */ + bool isEqual(const QVariant &p) const; + + /** @copydoc KConfigSkeletonItem::property() */ + QVariant property() const; + }; + + + /** + * Class for handling a QSize preferences item. + */ + class KCONFIGCORE_EXPORT ItemSize:public KConfigSkeletonGenericItem < QSize > + { + public: + /** @copydoc KConfigSkeletonGenericItem::KConfigSkeletonGenericItem */ + ItemSize(const QString & _group, const QString & _key, QSize & reference, + const QSize & defaultValue = QSize()); + + /** @copydoc KConfigSkeletonItem::readConfig(KConfig*) */ + void readConfig(KConfig * config); + + /** @copydoc KConfigSkeletonItem::setProperty(const QVariant&) */ + void setProperty(const QVariant & p); + + /** @copydoc KConfigSkeletonItem::isEqual(const QVariant &) const */ + bool isEqual(const QVariant &p) const; + + /** @copydoc KConfigSkeletonItem::property() */ + QVariant property() const; + }; + + + /** + * Class for handling a QDateTime preferences item. + */ + class KCONFIGCORE_EXPORT ItemDateTime:public KConfigSkeletonGenericItem < QDateTime > + { + public: + /** @copydoc KConfigSkeletonGenericItem::KConfigSkeletonGenericItem */ + ItemDateTime(const QString & _group, const QString & _key, + QDateTime & reference, + const QDateTime & defaultValue = QDateTime()); + + /** @copydoc KConfigSkeletonItem::readConfig(KConfig*) */ + void readConfig(KConfig * config); + + /** @copydoc KConfigSkeletonItem::setProperty(const QVariant&) */ + void setProperty(const QVariant & p); + + /** @copydoc KConfigSkeletonItem::isEqual(const QVariant &) const */ + bool isEqual(const QVariant &p) const; + + /** @copydoc KConfigSkeletonItem::property() */ + QVariant property() const; + }; + + + /** + * Class for handling a string list preferences item. + */ + class KCONFIGCORE_EXPORT ItemStringList:public KConfigSkeletonGenericItem < QStringList > + { + public: + /** @copydoc KConfigSkeletonGenericItem::KConfigSkeletonGenericItem */ + ItemStringList(const QString & _group, const QString & _key, + QStringList & reference, + const QStringList & defaultValue = QStringList()); + + /** @copydoc KConfigSkeletonItem::readConfig(KConfig*) */ + void readConfig(KConfig * config); + + /** @copydoc KConfigSkeletonItem::setProperty(const QVariant&) */ + void setProperty(const QVariant & p); + + /** @copydoc KConfigSkeletonItem::isEqual(const QVariant &) const */ + bool isEqual(const QVariant &p) const; + + /** @copydoc KConfigSkeletonItem::property() */ + QVariant property() const; + }; + + + /** + * Class for handling a path list preferences item. + */ + class KCONFIGCORE_EXPORT ItemPathList:public ItemStringList + { + public: + /** @copydoc KConfigSkeletonGenericItem::KConfigSkeletonGenericItem */ + ItemPathList(const QString & _group, const QString & _key, + QStringList & reference, + const QStringList & defaultValue = QStringList()); + + /** @copydoc KConfigSkeletonItem::readConfig */ + void readConfig(KConfig * config); + /** @copydoc KConfigSkeletonItem::writeConfig */ + void writeConfig(KConfig * config); + }; + + /** + * Class for handling a url list preferences item. + */ + class KCONFIGCORE_EXPORT ItemUrlList:public KConfigSkeletonGenericItem < QList<QUrl> > + { + public: + /** @copydoc KConfigSkeletonGenericItem::KConfigSkeletonGenericItem */ + ItemUrlList(const QString & _group, const QString & _key, + QList<QUrl> & reference, + const QList<QUrl> & defaultValue = QList<QUrl>()); + + /** @copydoc KConfigSkeletonItem::readConfig(KConfig*) */ + void readConfig(KConfig * config); + + /** @copydoc KConfigSkeletonItem::writeConfig(KConfig*) */ + void writeConfig(KConfig * config); + + /** @copydoc KConfigSkeletonItem::setProperty(const QVariant&) */ + void setProperty(const QVariant & p); + + /** @copydoc KConfigSkeletonItem::isEqual(const QVariant &) const */ + bool isEqual(const QVariant &p) const; + + /** @copydoc KConfigSkeletonItem::property() */ + QVariant property() const; + }; + + /** + * Class for handling an integer list preferences item. + */ + class KCONFIGCORE_EXPORT ItemIntList:public KConfigSkeletonGenericItem < QList < int > > + { + public: + /** @copydoc KConfigSkeletonGenericItem::KConfigSkeletonGenericItem */ + ItemIntList(const QString & _group, const QString & _key, + QList < int >&reference, + const QList < int >&defaultValue = QList < int >()); + + /** @copydoc KConfigSkeletonItem::readConfig(KConfig*) */ + void readConfig(KConfig * config); + + /** @copydoc KConfigSkeletonItem::setProperty(const QVariant&) */ + void setProperty(const QVariant & p); + + /** @copydoc KConfigSkeletonItem::isEqual(const QVariant &) const */ + bool isEqual(const QVariant &p) const; + + /** @copydoc KConfigSkeletonItem::property() */ + QVariant property() const; + }; + + +public: + /** + * Constructor. + * + * @param configname name of config file. If no name is given, the default + * config file as returned by KSharedConfig::openConfig() is used + * @param parent the parent object (see QObject documentation) + */ + explicit KCoreConfigSkeleton(const QString & configname = QString(), QObject* parent = 0); + + /** + * Constructor. + * + * @param config configuration object to use + * @param parent the parent object (see QObject documentation) + */ + explicit KCoreConfigSkeleton(KSharedConfig::Ptr config, QObject* parent = 0); + + /** + * Destructor + */ + virtual ~KCoreConfigSkeleton(); + + /** + * Set all registered items to their default values. + * This method calls usrSetDefaults() after setting the defaults for the + * registered items. You can overridde usrSetDefaults() in derived classes + * if you have special requirements. + * If you need more fine-grained control of setting the default values of + * the registered items you can override setDefaults() in a derived class. + */ + virtual void setDefaults(); + + /** + * Read preferences from config file. All registered items are set to the + * values read from disk. + * This method calls usrReadConfig() after reading the settings of the + * registered items from the KConfig. You can overridde usrReadConfig() + * in derived classes if you have special requirements. + * If you need more fine-grained control of storing the settings from + * the registered items you can override readConfig() in a derived class. + */ + virtual void readConfig(); + + /** + * Set the config file group for subsequent addItem() calls. It is valid + * until setCurrentGroup() is called with a new argument. Call this before + * you add any items. The default value is "No Group". + */ + void setCurrentGroup(const QString & group); + + /** + * Returns the current group used for addItem() calls. + */ + QString currentGroup() const; + + /** + * Register a custom @ref KConfigSkeletonItem with a given name. + * + * If the name parameter is null, take the name from KConfigSkeletonItem::key(). + * Note that all names must be unique but that multiple entries can have + * the same key if they reside in different groups. + * + * KCoreConfigSkeleton takes ownership of the KConfigSkeletonItem. + */ + void addItem(KConfigSkeletonItem *, const QString & name = QString() ); + + /** + * Register an item of type QString. + * + * @param name Name used to identify this setting. Names must be unique. + * @param reference Pointer to the variable, which is set by readConfig() + * calls and read by writeConfig() calls. + * @param defaultValue Default value, which is used when the config file + * does not yet contain the key of this item. + * @param key Key used in config file. If key is null, name is used as key. + * @return The created item + */ + ItemString *addItemString(const QString & name, QString & reference, + const QString & defaultValue = QLatin1String(""), // NOT QString() !! + const QString & key = QString()); + + /** + * Register a password item of type QString. The string value is written + * encrypted to the config file. Note that the current encryption scheme + * is very weak. + * + * @param name Name used to identify this setting. Names must be unique. + * @param reference Pointer to the variable, which is set by readConfig() + * calls and read by writeConfig() calls. + * @param defaultValue Default value, which is used when the config file + * does not yet contain the key of this item. + * @param key Key used in config file. If key is null, name is used as key. + * @return The created item + */ + ItemPassword *addItemPassword(const QString & name, QString & reference, + const QString & defaultValue = QLatin1String(""), + const QString & key = QString()); + + /** + * Register a path item of type QString. The string value is interpreted + * as a path. This means, dollar expension is activated for this value, so + * that e.g. $HOME gets expanded. + * + * @param name Name used to identify this setting. Names must be unique. + * @param reference Pointer to the variable, which is set by readConfig() + * calls and read by writeConfig() calls. + * @param defaultValue Default value, which is used when the config file + * does not yet contain the key of this item. + * @param key Key used in config file. If key is null, name is used as key. + * @return The created item + */ + ItemPath *addItemPath(const QString & name, QString & reference, + const QString & defaultValue = QLatin1String(""), + const QString & key = QString()); + + /** + * Register a property item of type QVariant. Note that only the following + * QVariant types are allowed: String, StringList, Font, Point, Rect, Size, + * Color, Int, UInt, Bool, Double, DateTime and Date. + * + * @param name Name used to identify this setting. Names must be unique. + * @param reference Pointer to the variable, which is set by readConfig() + * calls and read by writeConfig() calls. + * @param defaultValue Default value, which is used when the config file + * does not yet contain the key of this item. + * @param key Key used in config file. If key is null, name is used as key. + * @return The created item + */ + ItemProperty *addItemProperty(const QString & name, QVariant & reference, + const QVariant & defaultValue = QVariant(), + const QString & key = QString()); + /** + * Register an item of type bool. + * + * @param name Name used to identify this setting. Names must be unique. + * @param reference Pointer to the variable, which is set by readConfig() + * calls and read by writeConfig() calls. + * @param defaultValue Default value, which is used when the config file + * does not yet contain the key of this item. + * @param key Key used in config file. If key is null, name is used as key. + * @return The created item + */ + ItemBool *addItemBool(const QString & name, bool & reference, + bool defaultValue = false, + const QString & key = QString()); + + /** + * Register an item of type qint32. + * + * @param name Name used to identify this setting. Names must be unique. + * @param reference Pointer to the variable, which is set by readConfig() + * calls and read by writeConfig() calls. + * @param defaultValue Default value, which is used when the config file + * does not yet contain the key of this item. + * @param key Key used in config file. If key is null, name is used as key. + * @return The created item + */ + ItemInt *addItemInt(const QString & name, qint32 &reference, qint32 defaultValue = 0, + const QString & key = QString()); + + /** + * Register an item of type quint32. + * + * @param name Name used to identify this setting. Names must be unique. + * @param reference Pointer to the variable, which is set by readConfig() + * calls and read by writeConfig() calls. + * @param defaultValue Default value, which is used when the config file + * does not yet contain the key of this item. + * @param key Key used in config file. If key is null, name is used as key. + * @return The created item + */ + ItemUInt *addItemUInt(const QString & name, quint32 &reference, + quint32 defaultValue = 0, + const QString & key = QString()); + + /** + * Register an item of type qint64. + * + * @param name Name used to identify this setting. Names must be unique. + * @param reference Pointer to the variable, which is set by readConfig() + * calls and read by writeConfig() calls. + * @param defaultValue Default value, which is used when the config file + * does not yet contain the key of this item. + * @param key Key used in config file. If key is null, name is used as key. + * @return The created item + */ + ItemLongLong *addItemLongLong(const QString & name, qint64 &reference, + qint64 defaultValue = 0, + const QString & key = QString()); + + /** + * @deprecated + * Use addItemLongLong(). + */ +#ifndef KDE_NO_DEPRECATED + KCONFIGCORE_DEPRECATED ItemLongLong *addItemInt64( const QString& name, qint64 &reference, + qint64 defaultValue = 0, + const QString & key = QString()); +#endif + + /** + * Register an item of type quint64 + * + * @param name Name used to identify this setting. Names must be unique. + * @param reference Pointer to the variable, which is set by readConfig() + * calls and read by writeConfig() calls. + * @param defaultValue Default value, which is used when the config file + * does not yet contain the key of this item. + * @param key Key used in config file. If key is null, name is used as key. + * @return The created item + */ + ItemULongLong *addItemULongLong(const QString & name, quint64 &reference, + quint64 defaultValue = 0, + const QString & key = QString()); + + /** + * @deprecated + * Use addItemULongLong(). + */ +#ifndef KDE_NO_DEPRECATED + KCONFIGCORE_DEPRECATED ItemULongLong *addItemUInt64(const QString & name, quint64 &reference, + quint64 defaultValue = 0, + const QString & key = QString()); +#endif + + /** + * Register an item of type double. + * + * @param name Name used to identify this setting. Names must be unique. + * @param reference Pointer to the variable, which is set by readConfig() + * calls and read by writeConfig() calls. + * @param defaultValue Default value, which is used when the config file + * does not yet contain the key of this item. + * @param key Key used in config file. If key is null, name is used as key. + * @return The created item + */ + ItemDouble *addItemDouble(const QString & name, double &reference, + double defaultValue = 0.0, + const QString & key = QString()); + + /** + * Register an item of type QRect. + * + * @param name Name used to identify this setting. Names must be unique. + * @param reference Pointer to the variable, which is set by readConfig() + * calls and read by writeConfig() calls. + * @param defaultValue Default value, which is used when the config file + * does not yet contain the key of this item. + * @param key Key used in config file. If key is null, name is used as key. + * @return The created item + */ + ItemRect *addItemRect(const QString & name, QRect & reference, + const QRect & defaultValue = QRect(), + const QString & key = QString()); + + /** + * Register an item of type QPoint. + * + * @param name Name used to identify this setting. Names must be unique. + * @param reference Pointer to the variable, which is set by readConfig() + * calls and read by writeConfig() calls. + * @param defaultValue Default value, which is used when the config file + * does not yet contain the key of this item. + * @param key Key used in config file. If key is null, name is used as key. + * @return The created item + */ + ItemPoint *addItemPoint(const QString & name, QPoint & reference, + const QPoint & defaultValue = QPoint(), + const QString & key = QString()); + + /** + * Register an item of type QSize. + * + * @param name Name used to identify this setting. Names must be unique. + * @param reference Pointer to the variable, which is set by readConfig() + * calls and read by writeConfig() calls. + * @param defaultValue Default value, which is used when the config file + * does not yet contain the key of this item. + * @param key Key used in config file. If key is null, name is used as key. + * @return The created item + */ + ItemSize *addItemSize(const QString & name, QSize & reference, + const QSize & defaultValue = QSize(), + const QString & key = QString()); + + /** + * Register an item of type QDateTime. + * + * @param name Name used to identify this setting. Names must be unique. + * @param reference Pointer to the variable, which is set by readConfig() + * calls and read by writeConfig() calls. + * @param defaultValue Default value, which is used when the config file + * does not yet contain the key of this item. + * @param key Key used in config file. If key is null, name is used as key. + * @return The created item + */ + ItemDateTime *addItemDateTime(const QString & name, QDateTime & reference, + const QDateTime & defaultValue = QDateTime(), + const QString & key = QString()); + + /** + * Register an item of type QStringList. + * + * @param name Name used to identify this setting. Names must be unique. + * @param reference Pointer to the variable, which is set by readConfig() + * calls and read by writeConfig() calls. + * @param defaultValue Default value, which is used when the config file + * does not yet contain the key of this item. + * @param key Key used in config file. If key is null, name is used as key. + * @return The created item + */ + ItemStringList *addItemStringList(const QString & name, QStringList & reference, + const QStringList & defaultValue = QStringList(), + const QString & key = QString()); + + /** + * Register an item of type QList<int>. + * + * @param name Name used to identify this setting. Names must be unique. + * @param reference Pointer to the variable, which is set by readConfig() + * calls and read by writeConfig() calls. + * @param defaultValue Default value, which is used when the config file + * does not yet contain the key of this item. + * @param key Key used in config file. If key is null, name is used as key. + * @return The created item + */ + ItemIntList *addItemIntList(const QString & name, QList < int >&reference, + const QList < int >&defaultValue = + QList < int >(), + const QString & key = QString()); + + /** + * Return the @ref KConfig object used for reading and writing the settings. + */ + KConfig *config(); + + /** + * Return the @ref KConfig object used for reading and writing the settings. + */ + const KConfig *config() const; + + /** + * Set the @ref KSharedConfig object used for reading and writing the settings. + */ + void setSharedConfig(KSharedConfig::Ptr pConfig); + + /** + * Return list of items managed by this KCoreConfigSkeleton object. + */ + KConfigSkeletonItem::List items() const; + + /** + * Removes and deletes an item by name + * @arg name the name of the item to remove + */ + void removeItem(const QString &name); + + /** + * Removes and deletes all items + */ + void clearItems(); + + /** + * Return whether a certain item is immutable + * @since 4.4 + */ + bool isImmutable(const QString & name) const; + + /** + * Lookup item by name + * @since 4.4 + */ + KConfigSkeletonItem * findItem(const QString & name) const; + + /** + * Specify whether this object should reflect the actual values or the + * default values. + * This method is implemented by usrUseDefaults(), which can be overridden + * in derived classes if you have special requirements and can call + * usrUseDefaults() directly. + * If you don't have control whether useDefaults() or usrUseDefaults() is + * called override useDefaults() directly. + * @param b true to make this object reflect the default values, + * false to make it reflect the actual values. + * @return The state prior to this call + */ + virtual bool useDefaults(bool b); + +public Q_SLOTS: + /** + * Write preferences to config file. The values of all registered items are + * written to disk. + * This method calls usrWriteConfig() after writing the settings from the + * registered items to the KConfig. You can overridde usrWriteConfig() + * in derived classes if you have special requirements. + * If you need more fine-grained control of storing the settings from + * the registered items you can override writeConfig() in a derived class. + */ + virtual bool writeConfig(); + +Q_SIGNALS: + /** + * This signal is emitted when the configuration change. + */ + void configChanged(); + +protected: + /** + * Implemented by subclasses that use special defaults. + * It replaces the default values with the actual values and + * vice versa. Called from @ref useDefaults() + * @param b true to make this object reflect the default values, + * false to make it reflect the actual values. + * @return The state prior to this call + */ + virtual bool usrUseDefaults(bool b); + + /** + * Perform the actual setting of default values. + * Override in derived classes to set special default values. + * Called from @ref setDefaults() + */ + virtual void usrSetDefaults(); + + /** + * Perform the actual reading of the configuration file. + * Override in derived classes to read special config values. + * Called from @ref readConfig() + */ + virtual void usrReadConfig(); + + /** + * Perform the actual writing of the configuration file. + * Override in derived classes to write special config values. + * Called from @ref writeConfig() + */ + virtual bool usrWriteConfig(); + +private: + class Private; + Private * const d; + friend class KConfigSkeleton; + +}; + +#endif diff --git a/tier1/kconfig/src/core/kcoreconfigskeleton_p.h b/tier1/kconfig/src/core/kcoreconfigskeleton_p.h new file mode 100644 index 00000000..0912019c --- /dev/null +++ b/tier1/kconfig/src/core/kcoreconfigskeleton_p.h @@ -0,0 +1,64 @@ +/* + This file is part of KOrganizer. + Copyright (c) 2000,2001 Cornelius Schumacher <schumacher@kde.org> + Copyright (c) 2003 Waldo Bastian <bastian@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef KCORECONFIGSKELETON_P_H +#define KCORECONFIGSKELETON_P_H + +#include "kcoreconfigskeleton.h" + +class KCoreConfigSkeleton::Private +{ +public: + Private() + : mCurrentGroup( QLatin1String("No Group") ), mUseDefaults( false ) + {} + ~Private() + { + KConfigSkeletonItem::List::ConstIterator it; + for( it = mItems.constBegin(); it != mItems.constEnd(); ++it ) + { + delete *it; + } + } + QString mCurrentGroup; + + KSharedConfig::Ptr mConfig; // pointer to KConfig object + + KConfigSkeletonItem::List mItems; + KConfigSkeletonItem::Dict mItemDict; + + bool mUseDefaults; +}; + +class KConfigSkeletonItemPrivate +{ +public: + KConfigSkeletonItemPrivate() + : mIsImmutable(true) + {} + bool mIsImmutable; ///< Indicates this item is immutable + + QString mLabel; ///< The label for this item + QString mToolTip; ///< The ToolTip text for this item + QString mWhatsThis; ///< The What's This text for this item +}; + +#endif diff --git a/tier1/kconfig/src/core/kdesktopfile.cpp b/tier1/kconfig/src/core/kdesktopfile.cpp new file mode 100644 index 00000000..0ebbb4b0 --- /dev/null +++ b/tier1/kconfig/src/core/kdesktopfile.cpp @@ -0,0 +1,366 @@ +/* + This file is part of the KDE libraries + Copyright (c) 1999 Pietro Iglio <iglio@kde.org> + Copyright (c) 1999 Preston Brown <pbrown@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +// Qt5 TODO: re-enable. No point in doing it before, it breaks on QString::fromUtf8(QByteArray), which exists in qt5. +#undef QT_NO_CAST_FROM_BYTEARRAY + +#include "kdesktopfile.h" + +#ifndef Q_OS_WIN +#include <unistd.h> +#endif + +#include <QtCore/QDir> +#include <QtCore/QFileInfo> +#include <QUrl> +#include <qstandardpaths.h> + +#include "kauthorized.h" +#include "kconfig_p.h" +#include "kconfiggroup.h" +#include "kconfigini_p.h" + +class KDesktopFilePrivate : public KConfigPrivate +{ + public: + KDesktopFilePrivate(QStandardPaths::StandardLocation resourceType, const QString &fileName); + KConfigGroup desktopGroup; +}; + +KDesktopFilePrivate::KDesktopFilePrivate(QStandardPaths::StandardLocation resourceType, const QString &fileName) + : KConfigPrivate(KConfig::NoGlobals, resourceType) +{ + mBackend = new KConfigIniBackend(); + bDynamicBackend = false; + changeFileName(fileName); +} + +KDesktopFile::KDesktopFile(QStandardPaths::StandardLocation resourceType, const QString &fileName) + : KConfig(*new KDesktopFilePrivate(resourceType, fileName)) +{ + Q_D(KDesktopFile); + reparseConfiguration(); + d->desktopGroup = KConfigGroup(this, "Desktop Entry"); +} + +KDesktopFile::KDesktopFile(const QString &fileName) + : KConfig(*new KDesktopFilePrivate(QStandardPaths::ApplicationsLocation, fileName)) +{ + Q_D(KDesktopFile); + reparseConfiguration(); + d->desktopGroup = KConfigGroup(this, "Desktop Entry"); +} + +KDesktopFile::~KDesktopFile() +{ +} + +KConfigGroup KDesktopFile::desktopGroup() const +{ + Q_D(const KDesktopFile); + return d->desktopGroup; +} + +QString KDesktopFile::locateLocal(const QString &path) +{ + QString relativePath; + // Relative to config? (e.g. for autostart) + Q_FOREACH(const QString& dir, QStandardPaths::standardLocations(QStandardPaths::GenericConfigLocation)) { + if (path.startsWith(dir) + '/') { + relativePath = dir.mid(path.length() + 1); + return QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + QLatin1Char('/') + relativePath; + } + } + // Relative to xdg data dir? (much more common) + Q_FOREACH(const QString& dir, QStandardPaths::standardLocations(QStandardPaths::GenericDataLocation)) { + if (path.startsWith(dir) + '/') + relativePath = dir.mid(path.length() + 1); + } + if (relativePath.isEmpty()) { + // What now? The desktop file doesn't come from XDG_DATA_DIRS. Use filename only and hope for the best. + relativePath = path.mid(path.lastIndexOf(QLatin1Char('/'))+1); + } + return QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QLatin1Char('/') + relativePath; +} + +bool KDesktopFile::isDesktopFile(const QString& path) +{ + return (path.length() > 8 + && path.endsWith(QLatin1String(".desktop"))); +} + +bool KDesktopFile::isAuthorizedDesktopFile(const QString& path) +{ + if (path.isEmpty()) + return false; // Empty paths are not ok. + + if (QDir::isRelativePath(path)) + return true; // Relative paths are ok. + + const QString realPath = QFileInfo(path).canonicalFilePath(); + if (realPath.isEmpty()) + return false; // File doesn't exist. + +#ifndef Q_OS_WIN + const Qt::CaseSensitivity sensitivity = Qt::CaseSensitive; +#else + const Qt::CaseSensitivity sensitivity = Qt::CaseInsensitive; +#endif + + // Check if the .desktop file is installed as part of KDE or XDG. + const QStringList appsDirs = QStandardPaths::standardLocations(QStandardPaths::ApplicationsLocation); + Q_FOREACH (const QString &prefix, appsDirs) { + if (QDir(prefix).exists() && realPath.startsWith(QFileInfo(prefix).canonicalFilePath(), sensitivity)) + return true; + } + const QString servicesDir = QLatin1String("kde5/services/"); // KGlobal::dirs()->xdgDataRelativePath("services") + Q_FOREACH (const QString &xdgDataPrefix, QStandardPaths::standardLocations(QStandardPaths::GenericDataLocation)) { + if (QDir(xdgDataPrefix).exists()) { + const QString prefix = QFileInfo(xdgDataPrefix).canonicalFilePath(); + if (realPath.startsWith(prefix + QLatin1Char('/') + servicesDir, sensitivity)) + return true; + } + } + const QString autostartDir = QLatin1String("autostart/"); + Q_FOREACH (const QString &xdgDataPrefix, QStandardPaths::standardLocations(QStandardPaths::GenericConfigLocation)) { + if (QDir(xdgDataPrefix).exists()) { + const QString prefix = QFileInfo(xdgDataPrefix).canonicalFilePath(); + if (realPath.startsWith(prefix + QLatin1Char('/') + autostartDir, sensitivity)) + return true; + } + } + + // Forbid desktop files outside of standard locations if kiosk is set so + if (!KAuthorized::authorize(QLatin1String("run_desktop_files"))) { + qWarning() << "Access to '" << path << "' denied because of 'run_desktop_files' restriction." << endl; + return false; + } + + // Not otherwise permitted, so only allow if the file is executable, or if + // owned by root (uid == 0) + QFileInfo entryInfo( path ); + if (entryInfo.isExecutable() || entryInfo.ownerId() == 0) + return true; + + qWarning() << "Access to '" << path << "' denied, not owned by root, executable flag not set." << endl; + return false; +} + +QString KDesktopFile::readType() const +{ + Q_D(const KDesktopFile); + return d->desktopGroup.readEntry("Type", QString()); +} + +QString KDesktopFile::readIcon() const +{ + Q_D(const KDesktopFile); + return d->desktopGroup.readEntry("Icon", QString()); +} + +QString KDesktopFile::readName() const +{ + Q_D(const KDesktopFile); + return d->desktopGroup.readEntry("Name", QString()); +} + +QString KDesktopFile::readComment() const +{ + Q_D(const KDesktopFile); + return d->desktopGroup.readEntry("Comment", QString()); +} + +QString KDesktopFile::readGenericName() const +{ + Q_D(const KDesktopFile); + return d->desktopGroup.readEntry("GenericName", QString()); +} + +QString KDesktopFile::readPath() const +{ + Q_D(const KDesktopFile); + // NOT readPathEntry, it is not XDG-compliant. Path entries written by + // KDE4 will be still treated as such, though. + return d->desktopGroup.readEntry("Path", QString()); +} + +QString KDesktopFile::readDevice() const +{ + Q_D(const KDesktopFile); + return d->desktopGroup.readEntry("Dev", QString()); +} + +QString KDesktopFile::readUrl() const +{ + Q_D(const KDesktopFile); + if (hasDeviceType()) { + return d->desktopGroup.readEntry("MountPoint", QString()); + } else { + // NOT readPathEntry (see readPath()) + QString url = d->desktopGroup.readEntry("URL", QString()); + if ( !url.isEmpty() && !QDir::isRelativePath(url) ) + { + // Handle absolute paths as such (i.e. we need to escape them) + return QUrl::fromLocalFile(url).toString(); + } + return url; + } +} + +QStringList KDesktopFile::readActions() const +{ + Q_D(const KDesktopFile); + return d->desktopGroup.readXdgListEntry("Actions"); +} + +KConfigGroup KDesktopFile::actionGroup(const QString &group) +{ + return KConfigGroup(this, QLatin1String("Desktop Action ") + group); +} + +const KConfigGroup KDesktopFile::actionGroup(const QString& group) const +{ + return const_cast<KDesktopFile*>(this)->actionGroup(group); +} + +bool KDesktopFile::hasActionGroup(const QString &group) const +{ + return hasGroup(QString(QLatin1String("Desktop Action ") + group).toUtf8().constData()); +} + +bool KDesktopFile::hasLinkType() const +{ + return readType() == QLatin1String("Link"); +} + +bool KDesktopFile::hasApplicationType() const +{ + return readType() == QLatin1String("Application"); +} + +bool KDesktopFile::hasDeviceType() const +{ + return readType() == QLatin1String("FSDevice"); +} + +bool KDesktopFile::tryExec() const +{ + Q_D(const KDesktopFile); + // Test for TryExec and "X-KDE-AuthorizeAction" + // NOT readPathEntry (see readPath()) + QString te = d->desktopGroup.readEntry("TryExec", QString()); + + if (!te.isEmpty()) { + return !QStandardPaths::findExecutable(te).isEmpty(); + } + const QStringList list = d->desktopGroup.readEntry("X-KDE-AuthorizeAction", QStringList()); + if (!list.isEmpty()) + { + for(QStringList::ConstIterator it = list.begin(); + it != list.end(); + ++it) + { + if (!KAuthorized::authorize((*it).trimmed())) + return false; + } + } + + // See also KService::username() + bool su = d->desktopGroup.readEntry("X-KDE-SubstituteUID", false); + if (su) + { + QString user = d->desktopGroup.readEntry("X-KDE-Username", QString()); + if (user.isEmpty()) + user = QString::fromLocal8Bit(qgetenv("ADMIN_ACCOUNT")); + if (user.isEmpty()) + user = QString::fromLatin1("root"); + if (!KAuthorized::authorize(QString::fromLatin1("user/")+user)) + return false; + } + + return true; +} + +/** + * @return the filename as passed to the constructor. + */ +//QString KDesktopFile::fileName() const { return backEnd->fileName(); } + +/** + * @return the resource type as passed to the constructor. + */ +//QString +//KDesktopFile::resource() const { return backEnd->resource(); } + +QStringList +KDesktopFile::sortOrder() const +{ + Q_D(const KDesktopFile); + return d->desktopGroup.readEntry("SortOrder", QStringList()); +} + +//void KDesktopFile::virtual_hook( int id, void* data ) +//{ KConfig::virtual_hook( id, data ); } + +QString KDesktopFile::readDocPath() const +{ + Q_D(const KDesktopFile); + //legacy entry in kde3 apps + if(d->desktopGroup.hasKey( "DocPath" )) + return d->desktopGroup.readPathEntry( "DocPath", QString() ); + return d->desktopGroup.readPathEntry( "X-DocPath", QString() ); +} + +KDesktopFile* KDesktopFile::copyTo(const QString &file) const +{ + KDesktopFile *config = new KDesktopFile(QString()); + this->KConfig::copyTo(file, config); +// config->setDesktopGroup(); + return config; +} + +QStandardPaths::StandardLocation KDesktopFile::resource() const +{ + Q_D(const KDesktopFile); + return d->resourceType; +} + +QString KDesktopFile::fileName() const +{ + return name(); +} + +bool KDesktopFile::noDisplay() const +{ + Q_D(const KDesktopFile); + if (d->desktopGroup.readEntry("NoDisplay", false)) { + return true; + } + if (d->desktopGroup.hasKey("OnlyShowIn")) { + if (!d->desktopGroup.readXdgListEntry("OnlyShowIn").contains(QLatin1String("KDE"))) + return true; + } + if (d->desktopGroup.hasKey("NotShowIn")) { + if (d->desktopGroup.readXdgListEntry("NotShowIn").contains(QLatin1String("KDE"))) + return true; + } + return false; +} diff --git a/tier1/kconfig/src/core/kdesktopfile.h b/tier1/kconfig/src/core/kdesktopfile.h new file mode 100644 index 00000000..f3c5fe8f --- /dev/null +++ b/tier1/kconfig/src/core/kdesktopfile.h @@ -0,0 +1,252 @@ +/* This file is part of the KDE libraries + Copyright (c) 1999 Pietro Iglio <iglio@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ +#ifndef KDESKTOPFILE_H +#define KDESKTOPFILE_H + +#include <kconfig.h> + +class KConfigGroup; +class KDesktopFilePrivate; + +/** + * \class KDesktopFile kdesktopfile.h <KDesktopFile> + * + * %KDE Desktop File Management. + * This class implements %KDE's support for the freedesktop.org + * <em>Desktop Entry Spec</em>. + * + * @author Pietro Iglio <iglio@kde.org> + * @see KConfigBase KConfig + * @see <a href="http://standards.freedesktop.org/desktop-entry-spec/latest/">Desktop Entry Spec</a> + */ +class KCONFIGCORE_EXPORT KDesktopFile : public KConfig +{ +public: + /** + * Constructs a KDesktopFile object. + * + * See QStandardPaths for more information on resources. + * + * @param resourceType Allows you to change what sort of resource + * to search for if @p fileName is not absolute. + * For instance, you might want to specify GenericConfigLocation. + * @param fileName The name or path of the desktop file. If it + * is not absolute, it will be located + * using the resource type @p resType. + */ + explicit KDesktopFile(QStandardPaths::StandardLocation resourceType, const QString &fileName); + + /** + * Constructs a KDesktopFile object. + * + * See QStandardPaths for more information on resources. + * + * @param fileName The name or path of the desktop file. If it + * is not absolute, it will be located + * using the resource type ApplicationsLocation + */ + explicit KDesktopFile(const QString &fileName); + + /** + * Destructs the KDesktopFile object. + * + * Writes back any dirty configuration entries. + */ + virtual ~KDesktopFile(); + + /** + * Checks whether this is really a desktop file. + * + * The check is performed looking at the file extension (the file is not + * opened). + * Currently, the only valid extension is ".desktop". + * @param path the path of the file to check + * @return true if the file appears to be a desktop file. + */ + static bool isDesktopFile(const QString& path); + + /** + * Checks whether the user is authorized to run this desktop file. + * By default users are authorized to run all desktop files but + * the KIOSK framework can be used to activate certain restrictions. + * See README.kiosk for more information. + * + * Note: Since KDE 4.3, there are more restrictions on authorized + * desktop files to prevent users from inadvertently running trojan + * desktop files. Your application launchers should have the executable + * bit set to prevent issues. To see if a restriction is due to + * KIOSK, see KAuthorized. + * + * @param path the file to check + * @return true if the user is authorized to run the file + */ + static bool isAuthorizedDesktopFile(const QString& path); + + /** + * Returns the location where changes for the .desktop file @p path + * should be written to. + */ + static QString locateLocal(const QString &path); + + KConfigGroup desktopGroup() const; + + /** + * Returns the value of the "Type=" entry. + * @return the type or QString() if not specified + */ + QString readType() const; + + /** + * Returns the value of the "Icon=" entry. + * @return the icon or QString() if not specified + */ + QString readIcon() const; + + /** + * Returns the value of the "Name=" entry. + * @return the name or QString() if not specified + */ + QString readName() const; + + /** + * Returns the value of the "Comment=" entry. + * @return the comment or QString() if not specified + */ + QString readComment() const; + + /** + * Returns the value of the "GenericName=" entry. + * @return the generic name or QString() if not specified + */ + QString readGenericName() const; + + /** + * Returns the value of the "Path=" entry. + * @return the path or QString() if not specified + */ + QString readPath() const; + + /** + * Returns the value of the "Dev=" entry. + * @return the device or QString() if not specified + */ + QString readDevice() const; + + /** + * Returns the value of the "URL=" entry. + * @return the URL or QString() if not specified + */ + QString readUrl() const; + + /** + * Returns a list of the "Actions=" entries. + * @return the list of actions + */ + QStringList readActions() const; + + /** + * Sets the desktop action group. + * @param group the new action group + */ + KConfigGroup actionGroup(const QString &group); + + const KConfigGroup actionGroup(const QString &group) const; + + /** + * Returns true if the action group exists, false otherwise + * @param group the action group to test + * @return true if the action group exists + */ + bool hasActionGroup(const QString &group) const; + + /** + * Checks whether there is a "Type=Link" entry. + * + * The link points to the "URL=" entry. + * @return true if there is a "Type=Link" entry + */ + bool hasLinkType() const; + + /** + * Checks whether there is an entry "Type=Application". + * @return true if there is a "Type=Application" entry + */ + bool hasApplicationType() const; + + /** + * Checks whether there is an entry "Type=FSDevice". + * @return true if there is a "Type=FSDevice" entry + */ + bool hasDeviceType() const; + + /** + * Checks whether the TryExec field contains a binary + * which is found on the local system. + * @return true if TryExec contains an existing binary + */ + bool tryExec() const; + + /** + * Returns the value of the "X-DocPath=" Or "DocPath=" entry. + * @return The value of the "X-DocPath=" Or "DocPath=" entry. + */ + QString readDocPath() const; + + /** + * Returns the entry of the "SortOrder=" entry. + * @return the value of the "SortOrder=" entry. + */ + QStringList sortOrder() const; + + /** + * Whether the entry should be suppressed in menus. + * This handles the NoDisplay key, but also OnlyShowIn / NotShowIn. + * @return true to suppress this service + * @since 4.1 + */ + bool noDisplay() const; + + /** + * Copies all entries from this config object to a new + * KDesktopFile object that will save itself to @p file. + * + * Actual saving to @p file happens when the returned object is + * destructed or when sync() is called upon it. + * + * @param file the new KDesktopFile object it will save itself to. + */ + KDesktopFile* copyTo(const QString &file) const; + + QString fileName() const; + + QStandardPaths::StandardLocation resource() const; + +protected: + /** Virtual hook, used to add new "virtual" functions while maintaining + binary compatibility. Unused in this class. + */ +// virtual void virtual_hook( int id, void* data ); +private: + + Q_DISABLE_COPY(KDesktopFile) + + Q_DECLARE_PRIVATE(KDesktopFile) +}; + +#endif diff --git a/tier1/kconfig/src/core/kemailsettings.cpp b/tier1/kconfig/src/core/kemailsettings.cpp new file mode 100644 index 00000000..6a1f9448 --- /dev/null +++ b/tier1/kconfig/src/core/kemailsettings.cpp @@ -0,0 +1,269 @@ +/* + * Copyright (c) 2000 Alex Zepeda <zipzippy@sonic.net> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "kemailsettings.h" + +#include <kconfig.h> +#include <kconfiggroup.h> + +class KEMailSettingsPrivate { +public: + KEMailSettingsPrivate() : m_pConfig( 0 ) {} + ~KEMailSettingsPrivate() { delete m_pConfig; } + KConfig *m_pConfig; + QStringList profiles; + QString m_sDefaultProfile, m_sCurrentProfile; +}; + +QString KEMailSettings::defaultProfileName() const +{ + return p->m_sDefaultProfile; +} + +QString KEMailSettings::getSetting(KEMailSettings::Setting s) const +{ + KConfigGroup cg(p->m_pConfig, QStringLiteral("PROFILE_") + p->m_sCurrentProfile); + switch (s) { + case ClientProgram: { + return cg.readEntry("EmailClient"); + break; + } + case ClientTerminal: { + return cg.readEntry("TerminalClient", QVariant(false)).toString(); + break; + } + case RealName: { + return cg.readEntry("FullName"); + break; + } + case EmailAddress: { + return cg.readEntry("EmailAddress"); + break; + } + case ReplyToAddress: { + return cg.readEntry("ReplyAddr"); + break; + } + case Organization: { + return cg.readEntry("Organization"); + break; + } + case OutServer: { + return cg.readEntry("OutgoingServer"); + break; + } + case OutServerLogin: { + return cg.readEntry("OutgoingUserName"); + break; + } + case OutServerPass: { + return cg.readEntry("OutgoingPassword"); + break; + } + case OutServerType: { + return cg.readEntry("OutgoingServerType"); + break; + } + case OutServerCommand: { + return cg.readEntry("OutgoingCommand"); + break; + } + case OutServerTLS: { + return cg.readEntry("OutgoingServerTLS", QVariant(false)).toString(); + break; + } + case InServer: { + return cg.readEntry("IncomingServer"); + break; + } + case InServerLogin: { + return cg.readEntry("IncomingUserName"); + break; + } + case InServerPass: { + return cg.readEntry("IncomingPassword"); + break; + } + case InServerType: { + return cg.readEntry("IncomingServerType"); + break; + } + case InServerMBXType: { + return cg.readEntry("IncomingServerMBXType"); + break; + } + case InServerTLS: { + return cg.readEntry("IncomingServerTLS", QVariant(false)).toString(); + break; + } + }; + return QString(); +} +void KEMailSettings::setSetting(KEMailSettings::Setting s, const QString &v) +{ + KConfigGroup cg(p->m_pConfig, QStringLiteral("PROFILE_") + p->m_sCurrentProfile); + switch (s) { + case ClientProgram: { + cg.writePathEntry("EmailClient", v); + break; + } + case ClientTerminal: { + cg.writeEntry("TerminalClient", (v == QLatin1String("true"))); + break; + } + case RealName: { + cg.writeEntry("FullName", v); + break; + } + case EmailAddress: { + cg.writeEntry("EmailAddress", v); + break; + } + case ReplyToAddress: { + cg.writeEntry("ReplyAddr", v); + break; + } + case Organization: { + cg.writeEntry("Organization", v); + break; + } + case OutServer: { + cg.writeEntry("OutgoingServer", v); + break; + } + case OutServerLogin: { + cg.writeEntry("OutgoingUserName", v); + break; + } + case OutServerPass: { + cg.writeEntry("OutgoingPassword", v); + break; + } + case OutServerType: { + cg.writeEntry("OutgoingServerType", v); + break; + } + case OutServerCommand: { + cg.writeEntry("OutgoingCommand", v); + break; + } + case OutServerTLS: { + cg.writeEntry("OutgoingServerTLS", (v == QLatin1String("true"))); + break; + } + case InServer: { + cg.writeEntry("IncomingServer", v); + break; + } + case InServerLogin: { + cg.writeEntry("IncomingUserName", v); + break; + } + case InServerPass: { + cg.writeEntry("IncomingPassword", v); + break; + } + case InServerType: { + cg.writeEntry("IncomingServerType", v); + break; + } + case InServerMBXType: { + cg.writeEntry("IncomingServerMBXType", v); + break; + } + case InServerTLS: { + cg.writeEntry("IncomingServerTLS", (v == QLatin1String("true"))); + break; + } + }; + cg.sync(); +} + +void KEMailSettings::setDefault(const QString &s) +{ + p->m_pConfig->group("Defaults").writeEntry("Profile", s); + p->m_pConfig->sync(); + p->m_sDefaultProfile=s; + +} + +void KEMailSettings::setProfile (const QString &s) +{ + QString groupname = QStringLiteral("PROFILE_"); + groupname.append(s); + p->m_sCurrentProfile=s; + if (!p->m_pConfig->hasGroup(groupname)) { // Create a group if it doesn't exist + KConfigGroup cg(p->m_pConfig, groupname); + cg.writeEntry("ServerType", QString()); + p->profiles+=s; + } +} + +#ifndef KDE_NO_DEPRECATED +QString KEMailSettings::currentProfileName() const +{ + return p->m_sCurrentProfile; +} +#endif + +QStringList KEMailSettings::profiles() const +{ + return p->profiles; +} + +KEMailSettings::KEMailSettings() + :p(new KEMailSettingsPrivate()) +{ + p->m_sCurrentProfile.clear(); + + p->m_pConfig = new KConfig(QStringLiteral("emaildefaults")); + + const QStringList groups = p->m_pConfig->groupList(); + for (QStringList::ConstIterator it = groups.begin(); it != groups.end(); ++it) { + if ( (*it).startsWith( QLatin1String( "PROFILE_" ) ) ) + p->profiles+= (*it).mid(8, (*it).length()); + } + + KConfigGroup cg( p->m_pConfig, "Defaults"); + p->m_sDefaultProfile = cg.readEntry("Profile", tr("Default")); + if (!p->m_sDefaultProfile.isNull()) { + if (!p->m_pConfig->hasGroup(QStringLiteral("PROFILE_") + p->m_sDefaultProfile)) + setDefault(tr("Default")); + else + setDefault(p->m_sDefaultProfile); + } else { + if (p->profiles.count()) { + setDefault(p->profiles[0]); + } else + setDefault(tr("Default")); + } + setProfile(defaultProfileName()); +} + +KEMailSettings::~KEMailSettings() +{ + delete p; +} diff --git a/tier1/kconfig/src/core/kemailsettings.h b/tier1/kconfig/src/core/kemailsettings.h new file mode 100644 index 00000000..32610d61 --- /dev/null +++ b/tier1/kconfig/src/core/kemailsettings.h @@ -0,0 +1,176 @@ +/*- + * Copyright (c) 2000 Alex Zepeda <zipzippy@sonic.net> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#ifndef _KEMAILSETTINGS_H +#define _KEMAILSETTINGS_H + +#include <QtCore/QCoreApplication> // Q_DECLARE_TR_FUNCTIONS +#include <QtCore/QStringList> + +#include <kconfigcore_export.h> + +class KEMailSettingsPrivate; + + +/** + * This is just a small class to facilitate accessing e-mail settings in + * a sane way, and allowing any program to manage multiple e-mail + * profiles effortlessly + * + * The default profile is automatically selected in the constructor. + * + * @author Alex Zepeda zipzippy@sonic.net + **/ +class KCONFIGCORE_EXPORT KEMailSettings { + Q_DECLARE_TR_FUNCTIONS(KEMailSettings) +public: + /** + * The list of settings that I thought of when I wrote this + * class. Any extra settings thought of later can be accessed + * easily with getExtendedSetting and setExtendedSetting. + * @see getSetting() + * @see setSetting() + * @see getExtendedSetting() + * @see setExtendedSetting() + **/ + enum Setting { + ClientProgram, + ClientTerminal, + RealName, + EmailAddress, + ReplyToAddress, + Organization, + OutServer, + OutServerLogin, + OutServerPass, +#ifndef KDE_NO_DEPRECATED + /** + * @deprecated since Frameworks 5.0 + */ + OutServerType, + /** + * @deprecated since Frameworks 5.0 + */ + OutServerCommand, + /** + * @deprecated since Frameworks 5.0 + */ + OutServerTLS, +#endif + InServer, + InServerLogin, + InServerPass, +#ifndef KDE_NO_DEPRECATED + /** + * @deprecated since Frameworks 5.0 + */ + InServerType, + /** + * @deprecated since Frameworks 5.0 + */ + InServerMBXType, + /** + * @deprecated since Frameworks 5.0 + */ + InServerTLS +#endif + }; + + /** + * The various extensions allowed. + **/ + enum Extension { + POP3, + SMTP, + OTHER + }; + + /** + * Default constructor, just sets things up and sets the default profile + * as the current profile + **/ + KEMailSettings(); + + /** + * Default destructor, nothing to see here. + **/ + ~KEMailSettings(); + + /** + * List of profiles available. + * @return the list of profiles + **/ + QStringList profiles() const; + +#ifndef KDE_NO_DEPRECATED + /** + * @deprecated since Frameworks 5.0 + * Returns the name of the current profile. + * @returns what profile we're currently using + **/ + KCONFIGCORE_DEPRECATED QString currentProfileName() const; +#endif + + /** + * Change the current profile. + * @param s the name of the new profile + **/ + void setProfile (const QString &s); + + /** + * Returns the name of the default profile. + * @returns the name of the one that's currently default QString() if none + **/ + QString defaultProfileName() const; + + /** + * Sets a new default. + * @param def the new default + **/ + void setDefault(const QString &def); + + /** + * Get one of the predefined "basic" settings. + * @param s the setting to get + * @return the value of the setting, or QString() if not + * set + **/ + QString getSetting(KEMailSettings::Setting s) const; + + /** + * Set one of the predefined "basic" settings. + * @param s the setting to set + * @param v the new value of the setting, or QString() to + * unset + **/ + void setSetting(KEMailSettings::Setting s, const QString &v); + +private: + KEMailSettingsPrivate* const p; +}; + +#endif diff --git a/tier1/kconfig/src/core/ksharedconfig.cpp b/tier1/kconfig/src/core/ksharedconfig.cpp new file mode 100644 index 00000000..0e5d1959 --- /dev/null +++ b/tier1/kconfig/src/core/ksharedconfig.cpp @@ -0,0 +1,122 @@ +/* + This file is part of the KDE libraries + Copyright (c) 1999 Preston Brown <pbrown@kde.org> + Copyright (C) 1997-1999 Matthias Kalle Dalheimer (kalle@kde.org) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "ksharedconfig.h" +#include "kconfigbackend.h" +#include "kconfiggroup.h" +#include "kconfig_p.h" +#include <QCoreApplication> + +void _k_globalMainConfigSync(); + +class GlobalSharedConfigList : public QList<KSharedConfig*> +{ +public: + GlobalSharedConfigList() + { + // We want to force the sync() before the QCoreApplication + // instance is gone. Otherwise we trigger a QLockFile::lock() + // after QCoreApplication is gone, calling qAppName() for a non + // existent app... + qAddPostRoutine(&_k_globalMainConfigSync); + } + + // in addition to the list, we need to hold the main config, + // so that it's not created and destroyed all the time. + KSharedConfigPtr mainConfig; +}; + + +Q_GLOBAL_STATIC(GlobalSharedConfigList, globalSharedConfigList) + +void _k_globalMainConfigSync() +{ + if (globalSharedConfigList->mainConfig) + globalSharedConfigList->mainConfig->sync(); +} + + +KSharedConfigPtr KSharedConfig::openConfig(const QString& _fileName, + OpenFlags flags, + QStandardPaths::StandardLocation resType) +{ + QString fileName(_fileName); + GlobalSharedConfigList *list = globalSharedConfigList(); + if (fileName.isEmpty() && !flags.testFlag(KConfig::SimpleConfig)) { + // Determine the config file name that KConfig will make up (see KConfigPrivate::changeFileName) + fileName = KConfig::mainConfigName(); + } + + if (list) { + for(QList<KSharedConfig*>::ConstIterator it = list->constBegin(); it != list->constEnd(); ++it) { + if ( (*it)->name() == fileName && + (*it)->d_ptr->openFlags == flags && + (*it)->locationType() == resType +// (*it)->backEnd()->type() == backEnd + ) { + return KSharedConfigPtr(*it); + } + } + } + KSharedConfigPtr ptr(new KSharedConfig(fileName, flags, resType)); + if (_fileName.isEmpty() && flags == FullConfig && resType == QStandardPaths::GenericConfigLocation) { + list->mainConfig = ptr; + + static bool userWarned = false; + if (!userWarned) { + userWarned = true; + QByteArray readOnly = qgetenv("KDE_HOME_READONLY"); + if (readOnly.isEmpty() && QCoreApplication::applicationName() != QLatin1String("kdialog")) { + if (ptr->group("General").readEntry(QLatin1String("warn_unwritable_config"), true)) + ptr->isConfigWritable(true); + } + } + } + + return ptr; +} + + +KSharedConfig::KSharedConfig(const QString &fileName, + OpenFlags flags, + QStandardPaths::StandardLocation resType) + : KConfig(fileName, flags, resType) +{ + globalSharedConfigList()->append(this); +} + +KSharedConfig::~KSharedConfig() +{ + if (!globalSharedConfigList.isDestroyed()) + globalSharedConfigList()->removeAll(this); +} + +KConfigGroup KSharedConfig::groupImpl(const QByteArray &groupName) +{ + KSharedConfigPtr ptr(this); + return KConfigGroup( ptr, groupName.constData()); +} + +const KConfigGroup KSharedConfig::groupImpl(const QByteArray &groupName) const +{ + const KSharedConfigPtr ptr(const_cast<KSharedConfig*>(this)); + return KConfigGroup( ptr, groupName.constData()); +} diff --git a/tier1/kconfig/src/core/ksharedconfig.h b/tier1/kconfig/src/core/ksharedconfig.h new file mode 100644 index 00000000..42f7440e --- /dev/null +++ b/tier1/kconfig/src/core/ksharedconfig.h @@ -0,0 +1,88 @@ +/* + This file is part of the KDE libraries + Copyright (c) 1999 Preston Brown <pbrown@kde.org> + Copyright (C) 1997-1999 Matthias Kalle Dalheimer (kalle@kde.org) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef KSHAREDCONFIG_H +#define KSHAREDCONFIG_H + +#include <kconfig.h> +#include <QExplicitlySharedDataPointer> + +/** + * \class KSharedConfig ksharedconfig.h <KSharedConfig> + * + * KConfig variant using shared memory + * + * KSharedConfig provides a reference counted, shared memory variant + * of KConfig. This allows you to use manipulate the same configuration + * files from different places in your code without worrying about + * accidentally overwriting changes. + * + * Note that, as with most of kdelibs, this is @b NOT threadsafe. + */ +class KCONFIGCORE_EXPORT KSharedConfig : public KConfig, public QSharedData //krazy:exclude=dpointer (only for refcounting) +{ +public: + typedef QExplicitlySharedDataPointer<KSharedConfig> Ptr; + +public: + /** + * Creates a KSharedConfig object to manipulate a configuration file + * + * If an absolute path is specified for @p fileName, that file will be used + * as the store for the configuration settings. If a non-absolute path + * is provided, the file will be looked for in the standard directory + * specified by resourceType. If no path is provided, a default + * configuration file will be used based on the name of the main + * application component. + * + * @p mode determines whether the user or global settings will be allowed + * to influence the values returned by this object. See KConfig::OpenFlags for + * more details. + * + * @param fileName the configuration file to open. If empty, it will be determined + * automatically (from --config on the command line, otherwise + * from the application name + "rc") + * @param mode how global settings should affect the configuration + * options exposed by this KConfig object + * @param resourceType The standard directory to look for the configuration + * file in (see KStandardDirs) + * + * @sa KConfig + */ + static KSharedConfig::Ptr openConfig(const QString& fileName = QString(), + OpenFlags mode = FullConfig, + QStandardPaths::StandardLocation type = QStandardPaths::GenericConfigLocation); + + virtual ~KSharedConfig(); + +private: + Q_DISABLE_COPY(KSharedConfig) + virtual KConfigGroup groupImpl(const QByteArray& aGroup); + virtual const KConfigGroup groupImpl(const QByteArray& aGroup) const; + + KSharedConfig(const QString& file, OpenFlags mode, + QStandardPaths::StandardLocation resourceType); + +}; + +typedef KSharedConfig::Ptr KSharedConfigPtr; + +#endif // multiple inclusion guard diff --git a/tier1/kconfig/src/gui/CMakeLists.txt b/tier1/kconfig/src/gui/CMakeLists.txt new file mode 100644 index 00000000..974b05cc --- /dev/null +++ b/tier1/kconfig/src/gui/CMakeLists.txt @@ -0,0 +1,41 @@ + +find_package(Qt5Widgets 5.2.0 REQUIRED NO_MODULE) +find_package(Qt5Xml 5.2.0 REQUIRED NO_MODULE) + +set(libkconfiggui_SRCS + kconfiggui.cpp + kconfiggroupgui.cpp + kconfigloader.cpp + kconfigskeleton.cpp + kstandardshortcut.cpp + kwindowconfig.cpp +) + +add_library(KF5ConfigGui ${libkconfiggui_SRCS}) +generate_export_header(KF5ConfigGui BASE_NAME KConfigGui) +add_library(KF5::ConfigGui ALIAS KF5ConfigGui) + +target_link_libraries(KF5ConfigGui PUBLIC Qt5::Gui Qt5::Xml KF5::ConfigCore) + +if(IS_ABSOLUTE "${INCLUDE_INSTALL_DIR}") + target_include_directories(KF5ConfigGui INTERFACE "$<INSTALL_INTERFACE:${INCLUDE_INSTALL_DIR}>" ) +else() + target_include_directories(KF5ConfigGui INTERFACE "$<INSTALL_INTERFACE:${CMAKE_INSTALL_PREFIX}/${INCLUDE_INSTALL_DIR}>" ) +endif() + +set_target_properties(KF5ConfigGui PROPERTIES VERSION ${KCONFIG_VERSION_STRING} + SOVERSION ${KCONFIG_SOVERSION} + EXPORT_NAME ConfigGui +) + +install(TARGETS KF5ConfigGui EXPORT KF5ConfigTargets ${INSTALL_TARGETS_DEFAULT_ARGS}) + +install( FILES + ${CMAKE_CURRENT_BINARY_DIR}/kconfiggui_export.h + kconfiggui.h + kconfigloader.h + kconfigskeleton.h + kstandardshortcut.h + kwindowconfig.h + DESTINATION ${INCLUDE_INSTALL_DIR} COMPONENT Devel +) diff --git a/tier1/kconfig/src/gui/kconfiggroupgui.cpp b/tier1/kconfig/src/gui/kconfiggroupgui.cpp new file mode 100644 index 00000000..22706e77 --- /dev/null +++ b/tier1/kconfig/src/gui/kconfiggroupgui.cpp @@ -0,0 +1,197 @@ +/* + This file is part of the KDE libraries + Copyright (c) 2007 Thiago Macieira <thiago@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include <kconfiggroup.h> + +#include <QtCore/QMutableStringListIterator> +#include <QColor> +#include <QDebug> +#include <QFont> + +#include <kconfiggroup_p.h> + +/** + * Try to read a GUI type from config group @p cg at key @p key. + * @p input is the default value and also indicates the type to be read. + * @p output is to be set with the value that has been read. + * + * @returns true if something was handled (even if output was set to clear or default) + * or false if nothing was handled (e.g., Core type) + */ +static bool readEntryGui(const QByteArray& data, const char* key, const QVariant &input, + QVariant &output) +{ + const QString errString = QString::fromLatin1("\"%1\" - conversion from \"%3\" to %2 failed") + .arg(QLatin1String(key)) + .arg(QLatin1String(QVariant::typeToName(input.type()))) + .arg(QLatin1String(data.constData())); + const QString formatError = QString::fromLatin1(" (wrong format: expected '%1' items, read '%2')"); + + // set in case of failure + output = input; + + switch (input.type()) { + case QVariant::Color: { + if (data.isEmpty() || data == "invalid") { + output = QColor(); // return what was stored + return true; + } else if (data.at(0) == '#') { + QColor col; + col.setNamedColor(QString::fromUtf8(data.constData(), data.length())); + output = col; + return true; + } else if (!data.contains(',')) { + QColor col; + col.setNamedColor(QString::fromUtf8(data.constData(), data.length())); + if (!col.isValid()) + qCritical() << qPrintable(errString); + output = col; + return true; + } else { + const QList<QByteArray> list = data.split(','); + const int count = list.count(); + + if (count != 3 && count != 4) { + qCritical() << qPrintable(errString) << qPrintable(formatError.arg(QLatin1String("3' or '4")).arg(count)); + return true; // return default + } + + int temp[4]; + // bounds check components + for(int i = 0; i < count; i++) { + bool ok; + const int j = temp[i] = list.at(i).toInt(&ok); + if (!ok) { // failed to convert to int + qCritical() << qPrintable(errString) << " (integer conversion failed)"; + return true; // return default + } + if (j < 0 || j > 255) { + static const char *const components[6] = { + "red", "green", "blue", "alpha" + }; + const QString boundsError = QLatin1String(" (bounds error: %1 component %2)"); + qCritical() << qPrintable(errString) + << qPrintable(boundsError.arg(QLatin1String(components[i])).arg(j < 0? QLatin1String("< 0"): QLatin1String("> 255"))); + return true; // return default + } + } + QColor aColor(temp[0], temp[1], temp[2]); + if (count == 4) + aColor.setAlpha(temp[3]); + + if (aColor.isValid()) + output = aColor; + else + qCritical() << qPrintable(errString); + return true; + } + } + + case QVariant::Font: { + QVariant tmp = QString::fromUtf8(data.constData(), data.length()); + if (tmp.convert(QVariant::Font)) + output = tmp; + else + qCritical() << qPrintable(errString); + return true; + } + case QVariant::Pixmap: + case QVariant::Image: + case QVariant::Brush: + case QVariant::Palette: + case QVariant::Icon: + case QVariant::Region: + case QVariant::Bitmap: + case QVariant::Cursor: + case QVariant::SizePolicy: + case QVariant::Pen: + // we may want to handle these in the future + + default: + break; + } + + return false; // not handled +} + +/** + * Try to write a GUI type @p prop to config group @p cg at key @p key. + * + * @returns true if something was handled (even if an empty value was written) + * or false if nothing was handled (e.g., Core type) + */ +static bool writeEntryGui(KConfigGroup *cg, const char* key, const QVariant &prop, + KConfigGroup::WriteConfigFlags pFlags) +{ + switch (prop.type()) { + case QVariant::Color: { + const QColor rColor = prop.value<QColor>(); + + if (!rColor.isValid()) { + cg->writeEntry(key, "invalid", pFlags); + return true; + } + + QList<int> list; + list.insert(0, rColor.red()); + list.insert(1, rColor.green()); + list.insert(2, rColor.blue()); + if (rColor.alpha() != 255) + list.insert(3, rColor.alpha()); + + cg->writeEntry( key, list, pFlags ); + return true; + } + case QVariant::Font: + cg->writeEntry( key, prop.toString().toUtf8(), pFlags ); + return true; + + case QVariant::Pixmap: + case QVariant::Image: + case QVariant::Brush: + case QVariant::Palette: + case QVariant::Icon: + case QVariant::Region: + case QVariant::Bitmap: + case QVariant::Cursor: + case QVariant::SizePolicy: + case QVariant::Pen: + // we may want to handle one of these in the future + break; + + default: + break; + } + + return false; +} + +static int initKConfigGroupGui() +{ + _kde_internal_KConfigGroupGui.readEntryGui = readEntryGui; + _kde_internal_KConfigGroupGui.writeEntryGui = writeEntryGui; + return 42; // because 42 is nicer than 1 or 0 +} + +#ifdef Q_CONSTRUCTOR_FUNCTION +Q_CONSTRUCTOR_FUNCTION(initKConfigGroupGui) +#else +static int dummyKConfigGroupGui = initKConfigGroupGui(); +#endif diff --git a/tier1/kconfig/src/gui/kconfiggui.cpp b/tier1/kconfig/src/gui/kconfiggui.cpp new file mode 100644 index 00000000..88da6b56 --- /dev/null +++ b/tier1/kconfig/src/gui/kconfiggui.cpp @@ -0,0 +1,51 @@ +/* + This file is part of the KDE libraries + Copyright (c) 1999 Matthias Ettrich <ettrich@kde.org> + + 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) version 3, or any + later version 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 defined in Section 6 of version 3 of the license. + + 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, see <http://www.gnu.org/licenses/>. +*/ + +#include "kconfiggui.h" + +#include <QGuiApplication> + +#include <kconfig.h> + +static KConfig* s_sessionConfig = 0; + +KConfig* KConfigGui::sessionConfig() +{ + if (!s_sessionConfig) // create an instance specific config object + s_sessionConfig = new KConfig( sessionConfigName(), KConfig::SimpleConfig ); + return s_sessionConfig; +} + +bool KConfigGui::hasSessionConfig() +{ + return s_sessionConfig != 0; +} + +QString KConfigGui::sessionConfigName() +{ +#ifdef QT_NO_SESSIONMANAGER +#error QT_NO_SESSIONMANAGER was set, this will not compile. Reconfigure Qt with Session management support. +#endif + const QString sessionKey = qApp->sessionKey(); + const QString sessionId = qApp->sessionId(); + return QString(QLatin1String("session/%1_%2_%3")).arg(QGuiApplication::applicationName()).arg(sessionId).arg(sessionKey); +} + diff --git a/tier1/kconfig/src/gui/kconfiggui.h b/tier1/kconfig/src/gui/kconfiggui.h new file mode 100644 index 00000000..4e2313f3 --- /dev/null +++ b/tier1/kconfig/src/gui/kconfiggui.h @@ -0,0 +1,58 @@ +/* + This file is part of the KDE libraries + Copyright (c) 1999 Matthias Ettrich <ettrich@kde.org> + + 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) version 3, or any + later version 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 defined in Section 6 of version 3 of the license. + + 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, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef KCONFIGGUI_H +#define KCONFIGGUI_H + +#include <kconfiggui_export.h> + +#include <QString> + +class KConfig; + +namespace KConfigGui +{ + /** + * Returns the application session config object. + * + * @return A pointer to the application's instance specific + * KConfig object. + * @see KConfig + */ + KCONFIGGUI_EXPORT KConfig* sessionConfig(); + + /** + * Indicates if a session config has been created for that application + * (ie. if sessionConfig() got called at least once) + * + * @return true if a sessionConfig object was created, false otherwise + */ + KCONFIGGUI_EXPORT bool hasSessionConfig(); + + /** + * Returns the name of the application session + * + * @return the application session name + */ + KCONFIGGUI_EXPORT QString sessionConfigName(); +} + +#endif // KCONFIGGUI_H diff --git a/tier1/kconfig/src/gui/kconfigloader.cpp b/tier1/kconfig/src/gui/kconfigloader.cpp new file mode 100644 index 00000000..150c6b69 --- /dev/null +++ b/tier1/kconfig/src/gui/kconfigloader.cpp @@ -0,0 +1,442 @@ +/* + * Copyright 2007 Aaron Seigo <aseigo@kde.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "kconfigloader.h" +#include "kconfigloader_p.h" +#include "kconfigloaderhandler_p.h" + +#include <QColor> +#include <QFont> +#include <QHash> +#include <QXmlContentHandler> +#include <QXmlInputSource> +#include <QXmlSimpleReader> +#include <QUrl> + +#include <QDebug> + +void ConfigLoaderPrivate::parse(KConfigLoader *loader, QIODevice *xml) +{ + clearData(); + loader->clearItems(); + + if (xml) { + QXmlInputSource source(xml); + QXmlSimpleReader reader; + ConfigLoaderHandler handler(loader, this); + reader.setContentHandler(&handler); + reader.parse(&source, false); + } +} + +ConfigLoaderHandler::ConfigLoaderHandler(KConfigLoader *config, ConfigLoaderPrivate *d) + : QXmlDefaultHandler(), + m_config(config), + d(d) +{ + resetState(); +} + +bool ConfigLoaderHandler::startElement(const QString &namespaceURI, const QString &localName, + const QString &qName, const QXmlAttributes &attrs) +{ + Q_UNUSED(namespaceURI) + Q_UNUSED(qName) + +// qDebug() << "ConfigLoaderHandler::startElement(" << localName << qName; + int numAttrs = attrs.count(); + QString tag = localName.toLower(); + if (tag == QStringLiteral("group")) { + QString group; + for (int i = 0; i < numAttrs; ++i) { + QString name = attrs.localName(i).toLower(); + if (name == QStringLiteral("name")) { + //qDebug() << "set group to" << attrs.value(i); + group = attrs.value(i); + } + } + if (group.isEmpty()) { + group = d->baseGroup; + } else { + d->groups.append(group); + if (!d->baseGroup.isEmpty()) { + group = d->baseGroup + QStringLiteral("\x1d") + group; + } + } + m_currentGroup = group; + if (m_config) { + m_config->setCurrentGroup(group); + } + } else if (tag == QStringLiteral("entry")) { + for (int i = 0; i < numAttrs; ++i) { + QString name = attrs.localName(i).toLower(); + if (name == QStringLiteral("name")) { + m_name = attrs.value(i).trimmed(); + } else if (name == QStringLiteral("type")) { + m_type = attrs.value(i).toLower(); + } else if (name == QStringLiteral("key")) { + m_key = attrs.value(i).trimmed(); + } + } + } else if (tag == QStringLiteral("choice")) { + m_choice.name.clear(); + m_choice.label.clear(); + m_choice.whatsThis.clear(); + for (int i = 0; i < numAttrs; ++i) { + QString name = attrs.localName(i).toLower(); + if (name == QStringLiteral("name")) { + m_choice.name = attrs.value(i); + } + } + m_inChoice = true; + } + + return true; +} + +bool ConfigLoaderHandler::characters(const QString &ch) +{ + m_cdata.append(ch); + return true; +} + +QString ConfigLoaderHandler::name() const +{ + return m_name; +} + +void ConfigLoaderHandler::setName(const QString &name) +{ + m_name = name; +} + +QString ConfigLoaderHandler::key() const +{ + return m_key; +} + +void ConfigLoaderHandler::setKey(const QString &key) +{ + m_key = key; +} + +QString ConfigLoaderHandler::type() const +{ + return m_type; +} + +QString ConfigLoaderHandler::currentGroup() const +{ + return m_currentGroup; +} + +QString ConfigLoaderHandler::defaultValue() const +{ + return m_default; +} + +bool ConfigLoaderHandler::endElement(const QString &namespaceURI, + const QString &localName, const QString &qName) +{ + Q_UNUSED(namespaceURI) + Q_UNUSED(qName) + +// qDebug() << "ConfigLoaderHandler::endElement(" << localName << qName; + const QString tag = localName.toLower(); + if (tag == QStringLiteral("entry")) { + addItem(); + resetState(); + } else if (tag == QStringLiteral("label")) { + if (m_inChoice) { + m_choice.label = m_cdata.trimmed(); + } else { + m_label = m_cdata.trimmed(); + } + } else if (tag == QStringLiteral("whatsthis")) { + if (m_inChoice) { + m_choice.whatsThis = m_cdata.trimmed(); + } else { + m_whatsThis = m_cdata.trimmed(); + } + } else if (tag == QStringLiteral("default")) { + m_default = m_cdata.trimmed(); + } else if (tag == QStringLiteral("min")) { + m_min = m_cdata.toInt(&m_haveMin); + } else if (tag == QStringLiteral("max")) { + m_max = m_cdata.toInt(&m_haveMax); + } else if (tag == QStringLiteral("choice")) { + m_enumChoices.append(m_choice); + m_inChoice = false; + } + + m_cdata.clear(); + return true; +} + +void ConfigLoaderHandler::addItem() +{ + if (m_name.isEmpty()) { + if (m_key.isEmpty()) { + return; + } + + m_name = m_key; + } + + m_name.remove(QStringLiteral(" ")); + + KConfigSkeletonItem *item = 0; + + if (m_type == QStringLiteral("bool")) { + bool defaultValue = m_default.toLower() == QStringLiteral("true"); + item = m_config->addItemBool(m_name, *d->newBool(), defaultValue, m_key); + } else if (m_type == QStringLiteral("color")) { + item = m_config->addItemColor(m_name, *d->newColor(), QColor(m_default), m_key); + } else if (m_type == QStringLiteral("datetime")) { + item = m_config->addItemDateTime(m_name, *d->newDateTime(), + QDateTime::fromString(m_default), m_key); + } else if (m_type == QStringLiteral("enum")) { + m_key = (m_key.isEmpty()) ? m_name : m_key; + KConfigSkeleton::ItemEnum *enumItem = + new KConfigSkeleton::ItemEnum(m_config->currentGroup(), + m_key, *d->newInt(), + m_enumChoices, + m_default.toUInt()); + m_config->addItem(enumItem, m_name); + item = enumItem; + } else if (m_type == QStringLiteral("font")) { + item = m_config->addItemFont(m_name, *d->newFont(), QFont(m_default), m_key); + } else if (m_type == QStringLiteral("int")) { + KConfigSkeleton::ItemInt *intItem = m_config->addItemInt(m_name, *d->newInt(), + m_default.toInt(), m_key); + + if (m_haveMin) { + intItem->setMinValue(m_min); + } + + if (m_haveMax) { + intItem->setMaxValue(m_max); + } + + item = intItem; + } else if (m_type == QStringLiteral("password")) { + item = m_config->addItemPassword(m_name, *d->newString(), m_default, m_key); + } else if (m_type == QStringLiteral("path")) { + item = m_config->addItemPath(m_name, *d->newString(), m_default, m_key); + } else if (m_type == QStringLiteral("string")) { + item = m_config->addItemString(m_name, *d->newString(), m_default, m_key); + } else if (m_type == QStringLiteral("stringlist")) { + //FIXME: the split() is naive and will break on lists with ,'s in them + item = m_config->addItemStringList(m_name, *d->newStringList(), + m_default.split(QStringLiteral(",")), m_key); + } else if (m_type == QStringLiteral("uint")) { + KConfigSkeleton::ItemUInt *uintItem = + m_config->addItemUInt(m_name, *d->newUint(), m_default.toUInt(), m_key); + if (m_haveMin) { + uintItem->setMinValue(m_min); + } + if (m_haveMax) { + uintItem->setMaxValue(m_max); + } + item = uintItem; + } else if (m_type == QStringLiteral("url")) { + m_key = (m_key.isEmpty()) ? m_name : m_key; + KConfigSkeleton::ItemUrl *urlItem = + new KConfigSkeleton::ItemUrl(m_config->currentGroup(), + m_key, *d->newUrl(), + QUrl::fromUserInput(m_default)); + m_config->addItem(urlItem, m_name); + item = urlItem; + } else if (m_type == QStringLiteral("double")) { + KConfigSkeleton::ItemDouble *doubleItem = m_config->addItemDouble(m_name, + *d->newDouble(), m_default.toDouble(), m_key); + if (m_haveMin) { + doubleItem->setMinValue(m_min); + } + if (m_haveMax) { + doubleItem->setMaxValue(m_max); + } + item = doubleItem; + } else if (m_type == QStringLiteral("intlist")) { + QStringList tmpList = m_default.split(QStringLiteral(",")); + QList<int> defaultList; + foreach (const QString &tmp, tmpList) { + defaultList.append(tmp.toInt()); + } + item = m_config->addItemIntList(m_name, *d->newIntList(), defaultList, m_key); + } else if (m_type == QStringLiteral("longlong")) { + KConfigSkeleton::ItemLongLong *longlongItem = m_config->addItemLongLong(m_name, + *d->newLongLong(), m_default.toLongLong(), m_key); + if (m_haveMin) { + longlongItem->setMinValue(m_min); + } + if (m_haveMax) { + longlongItem->setMaxValue(m_max); + } + item = longlongItem; + /* No addItemPathList in KConfigSkeleton ? + } else if (m_type == "PathList") { + //FIXME: the split() is naive and will break on lists with ,'s in them + item = m_config->addItemPathList(m_name, *d->newStringList(), m_default.split(","), m_key); + */ + } else if (m_type == QStringLiteral("point")) { + QPoint defaultPoint; + QStringList tmpList = m_default.split(QStringLiteral(",")); + if (tmpList.size() >= 2) { + defaultPoint.setX(tmpList[0].toInt()); + defaultPoint.setY(tmpList[1].toInt()); + } + item = m_config->addItemPoint(m_name, *d->newPoint(), defaultPoint, m_key); + } else if (m_type == QStringLiteral("rect")) { + QRect defaultRect; + QStringList tmpList = m_default.split(QStringLiteral(",")); + if (tmpList.size() >= 4) { + defaultRect.setCoords(tmpList[0].toInt(), tmpList[1].toInt(), + tmpList[2].toInt(), tmpList[3].toInt()); + } + item = m_config->addItemRect(m_name, *d->newRect(), defaultRect, m_key); + } else if (m_type == QStringLiteral("size")) { + QSize defaultSize; + QStringList tmpList = m_default.split(QStringLiteral(",")); + if (tmpList.size() >= 2) { + defaultSize.setWidth(tmpList[0].toInt()); + defaultSize.setHeight(tmpList[1].toInt()); + } + item = m_config->addItemSize(m_name, *d->newSize(), defaultSize, m_key); + } else if (m_type == QStringLiteral("ulonglong")) { + KConfigSkeleton::ItemULongLong *ulonglongItem = + m_config->addItemULongLong(m_name, *d->newULongLong(), m_default.toULongLong(), m_key); + if (m_haveMin) { + ulonglongItem->setMinValue(m_min); + } + if (m_haveMax) { + ulonglongItem->setMaxValue(m_max); + } + item = ulonglongItem; + /* No addItemUrlList in KConfigSkeleton ? + } else if (m_type == "urllist") { + //FIXME: the split() is naive and will break on lists with ,'s in them + QStringList tmpList = m_default.split(","); + QList<QUrl> defaultList; + foreach (const QString& tmp, tmpList) { + defaultList.append(QUrl(tmp)); + } + item = m_config->addItemUrlList(m_name, *d->newUrlList(), defaultList, m_key);*/ + } + + if (item) { + item->setLabel(m_label); + item->setWhatsThis(m_whatsThis); + d->keysToNames.insert(item->group() + item->key(), item->name()); + } +} + +void ConfigLoaderHandler::resetState() +{ + m_haveMin = false; + m_min = 0; + m_haveMax = false; + m_max = 0; + m_name.clear(); + m_type.clear(); + m_label.clear(); + m_default.clear(); + m_key.clear(); + m_whatsThis.clear(); + m_enumChoices.clear(); + m_inChoice = false; +} + +KConfigLoader::KConfigLoader(const QString &configFile, QIODevice *xml, QObject *parent) + : KConfigSkeleton(configFile, parent), + d(new ConfigLoaderPrivate) +{ + d->parse(this, xml); +} + +KConfigLoader::KConfigLoader(KSharedConfigPtr config, QIODevice *xml, QObject *parent) + : KConfigSkeleton(config, parent), + d(new ConfigLoaderPrivate) +{ + d->parse(this, xml); +} + +//FIXME: obviously this is broken and should be using the group as the root, +// but KConfigSkeleton does not currently support this. it will eventually though, +// at which point this can be addressed properly +KConfigLoader::KConfigLoader(const KConfigGroup &config, QIODevice *xml, QObject *parent) + : KConfigSkeleton(KSharedConfig::openConfig(config.config()->name()), parent), + d(new ConfigLoaderPrivate) +{ + KConfigGroup group = config.parent(); + d->baseGroup = config.name(); + while (group.isValid() && group.name() != QStringLiteral("<default>")) { + d->baseGroup = group.name() + QStringLiteral("\x1d") + d->baseGroup; + group = group.parent(); + } + d->parse(this, xml); +} + +KConfigLoader::~KConfigLoader() +{ + delete d; +} + +KConfigSkeletonItem *KConfigLoader::findItem(const QString &group, const QString &key) const +{ + return KConfigSkeleton::findItem(d->keysToNames[group + key]); +} + +KConfigSkeletonItem *KConfigLoader::findItemByName(const QString &name) const +{ + return KConfigSkeleton::findItem(name); +} + +QVariant KConfigLoader::property(const QString &name) const +{ + KConfigSkeletonItem *item = KConfigSkeleton::findItem(name); + + if (item) { + return item->property(); + } + + return QVariant(); +} + +bool KConfigLoader::hasGroup(const QString &group) const +{ + return d->groups.contains(group); +} + +QStringList KConfigLoader::groupList() const +{ + return d->groups; +} + +bool KConfigLoader::usrWriteConfig() +{ + if (d->saveDefaults) { + KConfigSkeletonItem::List itemList = items(); + for(int i = 0; i < itemList.size(); i++) { + KConfigGroup cg(config(), itemList.at(i)->group()); + cg.writeEntry(itemList.at(i)->key(), ""); + } + } + return true; +} diff --git a/tier1/kconfig/src/gui/kconfigloader.h b/tier1/kconfig/src/gui/kconfigloader.h new file mode 100644 index 00000000..df38ce79 --- /dev/null +++ b/tier1/kconfig/src/gui/kconfigloader.h @@ -0,0 +1,176 @@ +/* + * Copyright 2007 Aaron Seigo <aseigo@kde.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KCONFIGLOADER_H +#define KCONFIGLOADER_H + +#include <kconfiggroup.h> +#include <kconfigskeleton.h> +#include <ksharedconfig.h> + +#include <kconfiggui_export.h> + +class ConfigLoaderPrivate; + +/** + * @class KConfigLoader kconfigloader.h <KConfigLoader> + * + * @short A KConfigSkeleton that populates itself based on KConfigXT XML + * + * This class allows one to ship an XML file and reconstitute it into a + * KConfigSkeleton object at runtime. Common usage might look like this: + * + * \code + * QFile file(xmlFilePath); + * KConfigLoader appletConfig(configFilePath, &file); + * \endcode + * + * Alternatively, any QIODevice may be used in place of QFile in the + * example above. + * + * KConfigLoader is useful if it is not possible to use compiled code + * and by that the kconfig compiler cannot be used. Common examples are + * scripted plugins which want to provide a configuration interface. + * With the help of KConfigLoader a dynamically loaded ui file can be + * populated with the stored values and also stored back to the config + * file. + * + * An example for populating a QDialog with a dynamically populated UI + * with the help of a KConfigDialogManager: + * \code + * QDialog *dialog = new QDialog(); + * QFile xmlFile("path/to/kconfigxt.xml"); + * KConfigGroup cg = KSharedConfig::openConfig()->group(QString()); + * KConfigLoader *configLoader = new KConfigLoader(cg, &xmlFile, this); + * + * // load the ui file + * QUiLoader *loader = new QUiLoader(this); + * QFile uiFile("path/to/userinterface.ui"); + * uiFile.open(QFile::ReadOnly); + * QWidget *customConfigForm = loader->load(&uiFile, dialog); + * uiFile.close(); + * + * KConfigDialogManager *manager = new KConfigDialogManager(customConfigForm, configLoader); + * if (dialog->exec() == QDialog::Accepted) { + * manager->updateSettings(); + * } + * \endcode + * + * Currently the following data types are supported: + * + * @li bools + * @li colors + * @li datetimes + * @li enumerations + * @li fonts + * @li ints + * @li passwords + * @li paths + * @li strings + * @li stringlists + * @li uints + * @li urls + * @li doubles + * @li int lists + * @li longlongs + * @li path lists + * @li points + * @li rects + * @li sizes + * @li ulonglongs + * @li url lists + **/ +class KCONFIGGUI_EXPORT KConfigLoader : public KConfigSkeleton +{ +public: + /** + * Creates a KConfigSkeleton populated using the definition found in + * the XML data passed in. + * + * @param configFile path to the configuration file to use + * @param xml the xml data; must be valid KConfigXT data + * @param parent optional QObject parent + **/ + KConfigLoader(const QString &configFile, QIODevice *xml, QObject *parent = 0); + + /** + * Creates a KConfigSkeleton populated using the definition found in + * the XML data passed in. + * + * @param config the configuration object to use + * @param xml the xml data; must be valid KConfigXT data + * @param parent optional QObject parent + **/ + KConfigLoader(KSharedConfigPtr config, QIODevice *xml, QObject *parent = 0); + + /** + * Creates a KConfigSkeleton populated using the definition found in + * the XML data passed in. + * + * @param config the group to use as the root for configuration items + * @param xml the xml data; must be valid KConfigXT data + * @param parent optional QObject parent + **/ + KConfigLoader(const KConfigGroup &config, QIODevice *xml, QObject *parent = 0); + + ~KConfigLoader(); + + /** + * Finds the item for the given group and key. + * + * @param group the group in the config file to look in + * @param key the configuration key to find + * @return the associated KConfigSkeletonItem, or 0 if none + */ + KConfigSkeletonItem *findItem(const QString &group, const QString &key) const; + + /** + * Finds an item by its name + */ + KConfigSkeletonItem *findItemByName(const QString &name) const; + + /** + * Returns the property (variantized value) of the named item + */ + QVariant property(const QString &name) const; + + /** + * Check to see if a group exists + * + * @param group the name of the group to check for + * @return true if the group exists, or false if it does not + */ + bool hasGroup(const QString &group) const; + + /** + * @return the list of groups defined by the XML + */ + QStringList groupList() const; + +protected: + /** + * Hack used to force writing when no default exists in config file. + */ + bool usrWriteConfig(); + +private: + ConfigLoaderPrivate * const d; +}; + +#endif //multiple inclusion guard diff --git a/tier1/kconfig/src/gui/kconfigloader_p.h b/tier1/kconfig/src/gui/kconfigloader_p.h new file mode 100644 index 00000000..f9aa9191 --- /dev/null +++ b/tier1/kconfig/src/gui/kconfigloader_p.h @@ -0,0 +1,222 @@ +/* + * Copyright 2007-2008 Aaron Seigo <aseigo@kde.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KCONFIGLOADER_P_H +#define KCONFIGLOADER_P_H + +#include <QUrl> + +class ConfigLoaderPrivate +{ + public: + ConfigLoaderPrivate() + : saveDefaults(false) + { + } + + ~ConfigLoaderPrivate() + { + clearData(); + } + + void clearData() + { + qDeleteAll(bools); + qDeleteAll(strings); + qDeleteAll(stringlists); + qDeleteAll(colors); + qDeleteAll(fonts); + qDeleteAll(ints); + qDeleteAll(uints); + qDeleteAll(urls); + qDeleteAll(dateTimes); + qDeleteAll(doubles); + qDeleteAll(intlists); + qDeleteAll(longlongs); + qDeleteAll(points); + qDeleteAll(rects); + qDeleteAll(sizes); + qDeleteAll(ulonglongs); + qDeleteAll(urllists); + } + + bool *newBool() + { + bool *v = new bool; + bools.append(v); + return v; + } + + QString *newString() + { + QString *v = new QString; + strings.append(v); + return v; + } + + QStringList *newStringList() + { + QStringList *v = new QStringList; + stringlists.append(v); + return v; + } + + QColor *newColor() + { + QColor *v = new QColor; + colors.append(v); + return v; + } + + QFont *newFont() + { + QFont *v = new QFont; + fonts.append(v); + return v; + } + + qint32 *newInt() + { + qint32 *v = new qint32; + ints.append(v); + return v; + } + + quint32 *newUint() + { + quint32 *v = new quint32; + uints.append(v); + return v; + } + + QUrl *newUrl() + { + QUrl *v = new QUrl; + urls.append(v); + return v; + } + + QDateTime *newDateTime() + { + QDateTime *v = new QDateTime; + dateTimes.append(v); + return v; + } + + double *newDouble() + { + double *v = new double; + doubles.append(v); + return v; + } + + QList<qint32>* newIntList() + { + QList<qint32> *v = new QList<qint32>; + intlists.append(v); + return v; + } + + qint64 *newLongLong() + { + qint64 *v = new qint64; + longlongs.append(v); + return v; + } + + QPoint *newPoint() + { + QPoint *v = new QPoint; + points.append(v); + return v; + } + + QRect *newRect() + { + QRect *v = new QRect; + rects.append(v); + return v; + } + + QSize *newSize() + { + QSize *v = new QSize; + sizes.append(v); + return v; + } + + quint64 *newULongLong() + { + quint64 *v = new quint64; + ulonglongs.append(v); + return v; + } + + QList<QUrl> *newUrlList() + { + QList<QUrl> *v = new QList<QUrl>(); + urllists.append(v); + return v; + } + + void parse(KConfigLoader *loader, QIODevice *xml); + + /** + * Whether or not to write out default values. + * + * @param writeDefaults true if defaults should be written out + */ + void setWriteDefaults(bool writeDefaults) + { + saveDefaults = writeDefaults; + } + + /** + * @return true if default values will also be written out + */ + bool writeDefaults() const + { + return saveDefaults; + } + + + QList<bool *> bools; + QList<QString *> strings; + QList<QStringList *> stringlists; + QList<QColor *> colors; + QList<QFont *> fonts; + QList<qint32 *> ints; + QList<quint32 *> uints; + QList<QUrl *> urls; + QList<QDateTime *> dateTimes; + QList<double *> doubles; + QList<QList<qint32> *> intlists; + QList<qint64 *> longlongs; + QList<QPoint *> points; + QList<QRect *> rects; + QList<QSize *> sizes; + QList<quint64 *> ulonglongs; + QList<QList<QUrl> *> urllists; + QString baseGroup; + QStringList groups; + QHash<QString, QString> keysToNames; + bool saveDefaults; +}; + +#endif diff --git a/tier1/kconfig/src/gui/kconfigloaderhandler_p.h b/tier1/kconfig/src/gui/kconfigloaderhandler_p.h new file mode 100644 index 00000000..f0766346 --- /dev/null +++ b/tier1/kconfig/src/gui/kconfigloaderhandler_p.h @@ -0,0 +1,68 @@ +/* + * Copyright 2007-2008 Aaron Seigo <aseigo@kde.org> + * Copyright 2013 Marco Martin <mart@kde.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KCONFIGLOADERHANDLER_P_H +#define KCONFIGLOADERHANDLER_P_H + +#include <QXmlDefaultHandler> + +class ConfigLoaderHandler : public QXmlDefaultHandler +{ +public: + ConfigLoaderHandler(KConfigLoader *config, ConfigLoaderPrivate *d); + bool startElement(const QString &namespaceURI, const QString &localName, + const QString &qName, const QXmlAttributes &atts); + bool endElement(const QString &namespaceURI, const QString &localName, + const QString &qName); + bool characters(const QString &ch); + + QString name() const; + void setName(const QString &name); + QString key() const; + void setKey(const QString &name); + QString type() const; + QString currentGroup() const; + QString defaultValue() const; + +private: + virtual void addItem(); + void resetState(); + + KConfigLoader *m_config; + ConfigLoaderPrivate *d; + int m_min; + int m_max; + QString m_currentGroup; + QString m_name; + QString m_key; + QString m_type; + QString m_label; + QString m_default; + QString m_cdata; + QString m_whatsThis; + KConfigSkeleton::ItemEnum::Choice m_choice; + QList<KConfigSkeleton::ItemEnum::Choice> m_enumChoices; + bool m_haveMin; + bool m_haveMax; + bool m_inChoice; +}; + +#endif + diff --git a/tier1/kconfig/src/gui/kconfigskeleton.cpp b/tier1/kconfig/src/gui/kconfigskeleton.cpp new file mode 100644 index 00000000..7704d36e --- /dev/null +++ b/tier1/kconfig/src/gui/kconfigskeleton.cpp @@ -0,0 +1,121 @@ +/* + This file is part of KOrganizer. + Copyright (c) 2000,2001 Cornelius Schumacher <schumacher@kde.org> + Copyright (c) 2003 Waldo Bastian <bastian@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "kconfigskeleton.h" + +#include <kcoreconfigskeleton_p.h> + +KConfigSkeleton::KConfigSkeleton(const QString &configname, QObject* parent) + : KCoreConfigSkeleton(configname, parent) +{ +} + +KConfigSkeleton::KConfigSkeleton(KSharedConfig::Ptr pConfig, QObject* parent) + : KCoreConfigSkeleton(pConfig, parent) +{ +} + + +KConfigSkeleton::ItemColor::ItemColor( const QString &_group, const QString &_key, + QColor &reference, + const QColor &defaultValue ) + : KConfigSkeletonGenericItem<QColor>( _group, _key, reference, defaultValue ) +{ +} + +void KConfigSkeleton::ItemColor::readConfig( KConfig *config ) +{ + KConfigGroup cg(config, mGroup ); + mReference = cg.readEntry( mKey, mDefault ); + mLoadedValue = mReference; + + readImmutability( cg ); +} + +void KConfigSkeleton::ItemColor::setProperty(const QVariant & p) +{ + mReference = qvariant_cast<QColor>(p); +} + +bool KConfigSkeleton::ItemColor::isEqual(const QVariant &v) const +{ + return mReference == qvariant_cast<QColor>(v); +} + +QVariant KConfigSkeleton::ItemColor::property() const +{ + return QVariant(mReference); +} + + +KConfigSkeleton::ItemFont::ItemFont( const QString &_group, const QString &_key, + QFont &reference, + const QFont &defaultValue ) + : KConfigSkeletonGenericItem<QFont>( _group, _key, reference, defaultValue ) +{ +} + +void KConfigSkeleton::ItemFont::readConfig( KConfig *config ) +{ + KConfigGroup cg(config, mGroup ); + mReference = cg.readEntry( mKey, mDefault ); + mLoadedValue = mReference; + + readImmutability( cg ); +} + +void KConfigSkeleton::ItemFont::setProperty(const QVariant & p) +{ + mReference = qvariant_cast<QFont>(p); +} + +bool KConfigSkeleton::ItemFont::isEqual(const QVariant &v) const +{ + return mReference == qvariant_cast<QFont>(v); +} + +QVariant KConfigSkeleton::ItemFont::property() const +{ + return QVariant(mReference); +} + + +KConfigSkeleton::ItemColor *KConfigSkeleton::addItemColor( const QString &name, QColor &reference, + const QColor &defaultValue, const QString &key ) +{ + KConfigSkeleton::ItemColor *item; + item = new KConfigSkeleton::ItemColor( d->mCurrentGroup, key.isNull() ? name : key, + reference, defaultValue ); + addItem( item, name ); + return item; +} + +KConfigSkeleton::ItemFont *KConfigSkeleton::addItemFont( const QString &name, QFont &reference, + const QFont &defaultValue, const QString &key ) +{ + KConfigSkeleton::ItemFont *item; + item = new KConfigSkeleton::ItemFont( d->mCurrentGroup, key.isNull() ? name : key, + reference, defaultValue ); + addItem( item, name ); + return item; +} + + diff --git a/tier1/kconfig/src/gui/kconfigskeleton.h b/tier1/kconfig/src/gui/kconfigskeleton.h new file mode 100644 index 00000000..e62e60b4 --- /dev/null +++ b/tier1/kconfig/src/gui/kconfigskeleton.h @@ -0,0 +1,140 @@ +/* + * This file is part of KDE. + * + * Copyright (c) 2001,2002,2003 Cornelius Schumacher <schumacher@kde.org> + * Copyright (c) 2003 Waldo Bastian <bastian@kde.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef KCONFIGSKELETON_H +#define KCONFIGSKELETON_H + +#include <kconfiggui_export.h> + +#include <kcoreconfigskeleton.h> + +#include <QColor> +#include <QFont> + +/** + * @short Class for handling preferences settings for an application. + * @author Cornelius Schumacher + * + * This class extends KCoreConfigSkeleton by support for GUI types. + * + */ +class KCONFIGGUI_EXPORT KConfigSkeleton : public KCoreConfigSkeleton +{ + Q_OBJECT +public: + /** + * Class for handling a color preferences item. + */ + class KCONFIGGUI_EXPORT ItemColor:public KConfigSkeletonGenericItem < QColor > + { + public: + /** @copydoc KConfigSkeletonGenericItem::KConfigSkeletonGenericItem */ + ItemColor(const QString & _group, const QString & _key, + QColor & reference, + const QColor & defaultValue = QColor(128, 128, 128)); + + /** @copydoc KConfigSkeletonItem::readConfig(KConfig*) */ + void readConfig(KConfig * config); + + /** @copydoc KConfigSkeletonItem::setProperty(const QVariant&) */ + void setProperty(const QVariant & p); + + /** @copydoc KConfigSkeletonItem::isEqual(const QVariant &) */ + bool isEqual(const QVariant &p) const; + + /** @copydoc KConfigSkeletonItem::property() */ + QVariant property() const; + }; + + + /** + * Class for handling a font preferences item. + */ + class KCONFIGGUI_EXPORT ItemFont:public KConfigSkeletonGenericItem < QFont > + { + public: + /** @copydoc KConfigSkeletonGenericItem::KConfigSkeletonGenericItem */ + ItemFont(const QString & _group, const QString & _key, QFont & reference, + const QFont & defaultValue = QFont()); + + /** @copydoc KConfigSkeletonItem::readConfig(KConfig*) */ + void readConfig(KConfig * config); + + /** @copydoc KConfigSkeletonItem::setProperty(const QVariant&) */ + void setProperty(const QVariant & p); + + /** @copydoc KConfigSkeletonItem::isEqual(const QVariant &) */ + bool isEqual(const QVariant &p) const; + + /** @copydoc KConfigSkeletonItem::property() */ + QVariant property() const; + }; + +public: + /** + * Constructor. + * + * @param configname name of config file. If no name is given, the default + * config file as returned by KSharedConfig::openConfig() is used. + */ + explicit KConfigSkeleton(const QString & configname = QString(), QObject* parent = 0); + + /** + * Constructor. + * + * @param config configuration object to use. + */ + explicit KConfigSkeleton(KSharedConfig::Ptr config, QObject* parent = 0); + + /** + * Register an item of type QColor. + * + * @param name Name used to identify this setting. Names must be unique. + * @param reference Pointer to the variable, which is set by readConfig() + * calls and read by writeConfig() calls. + * @param defaultValue Default value, which is used when the config file + * does not yet contain the key of this item. + * @param key Key used in config file. If key is null, name is used as key. + * @return The created item + */ + ItemColor *addItemColor(const QString & name, QColor & reference, + const QColor & defaultValue = QColor(128, 128, 128), + const QString & key = QString()); + + /** + * Register an item of type QFont. + * + * @param name Name used to identify this setting. Names must be unique. + * @param reference Pointer to the variable, which is set by readConfig() + * calls and read by writeConfig() calls. + * @param defaultValue Default value, which is used when the config file + * does not yet contain the key of this item. + * @param key Key used in config file. If key is null, name is used as key. + * @return The created item + */ + ItemFont *addItemFont(const QString & name, QFont & reference, + const QFont & defaultValue = QFont(), + const QString & key = QString()); + +}; + +#endif diff --git a/tier1/kconfig/src/gui/kstandardshortcut.cpp b/tier1/kconfig/src/gui/kstandardshortcut.cpp new file mode 100644 index 00000000..a377ff0f --- /dev/null +++ b/tier1/kconfig/src/gui/kstandardshortcut.cpp @@ -0,0 +1,377 @@ +/* This file is part of the KDE libraries + Copyright (C) 1997 Stefan Taferner (taferner@alpin.or.at) + Copyright (C) 2000 Nicolas Hadacek (haadcek@kde.org) + Copyright (C) 2001,2002 Ellis Whitehead (ellis@kde.org) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "kstandardshortcut.h" + +#include "kconfig.h" +#include "ksharedconfig.h" +#include <kconfiggroup.h> + +#include <QCoreApplication> +#include <QDebug> +#include <QKeySequence> + +namespace KStandardShortcut +{ + +struct KStandardShortcutInfo +{ + //! The standard shortcut id. @see StandardShortcut + StandardShortcut id; + + /** + * Unique name for the given accel. The name is used to save the user + * settings. It's not representable. Use description for that. + * @warning NEVER EVER CHANGE IT OR TRANSLATE IT! + */ + const char* name; + + //! Context for the translation + const char* translation_context; + + //! Localized label for user-visible display + const char* description; + + //! The keys for this shortcut + int cutDefault, cutDefault2; + + //! A shortcut that is created with @a cutDefault and @cutDefault2 + QList<QKeySequence> cut; + + //! If this struct is initialized. If not initialized @cut is not valid + bool isInitialized; +}; + +//! We need to remember the context to get the correct translation. +#undef I18N_NOOP2 +#define I18N_NOOP2(comment,x) comment, x + +#define CTRL(x) Qt::CTRL+Qt::Key_##x +#define SHIFT(x) Qt::SHIFT+Qt::Key_##x +#define CTRLSHIFT(x) Qt::CTRL+Qt::SHIFT+Qt::Key_##x +#define ALT(x) Qt::ALT+Qt::Key_##x +#define ALTSHIFT(x) Qt::ALT+Qt::SHIFT+Qt::Key_##x + +/** Array of predefined KStandardShortcutInfo objects, which cover all + the "standard" accelerators. Each enum value from StandardShortcut + should appear in this table. +*/ +// STUFF WILL BREAK IF YOU DON'T READ THIS!!! +// Read the comments of the big enum in kstandardshortcut.h before you change anything! +static KStandardShortcutInfo g_infoStandardShortcut[] = +{ +//Group File, + {AccelNone, 0 , 0 , 0 , 0 , 0 , QList<QKeySequence>(), false }, + { Open , "Open" , I18N_NOOP2("@action", "Open") , CTRL(O), 0 , QList<QKeySequence>(), false } , + { New , "New" , I18N_NOOP2("@action", "New") , CTRL(N), 0 , QList<QKeySequence>(), false } , + { Close , "Close", I18N_NOOP2("@action", "Close"), CTRL(W), CTRL(Escape), QList<QKeySequence>(), false } , + { Save , "Save" , I18N_NOOP2("@action", "Save") , CTRL(S), 0 , QList<QKeySequence>(), false } , + { Print , "Print", I18N_NOOP2("@action", "Print"), CTRL(P), 0 , QList<QKeySequence>(), false } , + { Quit , "Quit" , I18N_NOOP2("@action", "Quit") , CTRL(Q), 0 , QList<QKeySequence>(), false } , + +//Group Edit + { Undo , "Undo" , I18N_NOOP2("@action", "Undo") , CTRL(Z) , 0 , QList<QKeySequence>(), false }, + { Redo , "Redo" , I18N_NOOP2("@action", "Redo") , CTRLSHIFT(Z) , 0 , QList<QKeySequence>(), false }, + { Cut , "Cut" , I18N_NOOP2("@action", "Cut") , CTRL(X) , SHIFT(Delete), QList<QKeySequence>(), false }, + { Copy , "Copy" , I18N_NOOP2("@action", "Copy") , CTRL(C) , CTRL(Insert) , QList<QKeySequence>(), false }, + { Paste , "Paste" , I18N_NOOP2("@action", "Paste") , CTRL(V) , SHIFT(Insert), QList<QKeySequence>(), false }, + { PasteSelection , "Paste Selection" , I18N_NOOP2("@action", "Paste Selection") , CTRLSHIFT(Insert), 0 , QList<QKeySequence>(), false }, + + { SelectAll , "SelectAll" , I18N_NOOP2("@action", "Select All") , CTRL(A) , 0 , QList<QKeySequence>(), false }, + { Deselect , "Deselect" , I18N_NOOP2("@action", "Deselect") , CTRLSHIFT(A) , 0 , QList<QKeySequence>(), false }, + { DeleteWordBack , "DeleteWordBack" , I18N_NOOP2("@action", "Delete Word Backwards"), CTRL(Backspace) , 0 , QList<QKeySequence>(), false }, + { DeleteWordForward, "DeleteWordForward", I18N_NOOP2("@action", "Delete Word Forward") , CTRL(Delete) , 0 , QList<QKeySequence>(), false }, + + { Find , "Find" , I18N_NOOP2("@action", "Find") , CTRL(F) , 0 , QList<QKeySequence>(), false }, + { FindNext , "FindNext" , I18N_NOOP2("@action", "Find Next") , Qt::Key_F3 , 0 , QList<QKeySequence>(), false }, + { FindPrev , "FindPrev" , I18N_NOOP2("@action", "Find Prev") , SHIFT(F3) , 0 , QList<QKeySequence>(), false }, + { Replace , "Replace" , I18N_NOOP2("@action", "Replace") , CTRL(R) , 0 , QList<QKeySequence>(), false }, + +//Group Navigation + { Home , "Home" , I18N_NOOP2("@action Go to main page" , "Home") , ALT(Home) , Qt::Key_HomePage , QList<QKeySequence>(), false }, + { Begin , "Begin" , I18N_NOOP2("@action Beginning of document", "Begin") , CTRL(Home) , 0 , QList<QKeySequence>(), false }, + { End , "End" , I18N_NOOP2("@action End of document" , "End") , CTRL(End) , 0 , QList<QKeySequence>(), false }, + { Prior , "Prior" , I18N_NOOP2("@action" , "Prior") , Qt::Key_PageUp , 0 , QList<QKeySequence>(), false }, + { Next , "Next" , I18N_NOOP2("@action Opposite to Prior" , "Next") , Qt::Key_PageDown, 0 , QList<QKeySequence>(), false }, + + { Up , "Up" , I18N_NOOP2("@action" , "Up") , ALT(Up) , 0 , QList<QKeySequence>(), false }, + { Back , "Back" , I18N_NOOP2("@action" , "Back") , ALT(Left) , Qt::Key_Back , QList<QKeySequence>(), false }, + { Forward , "Forward" , I18N_NOOP2("@action" , "Forward") , ALT(Right) , Qt::Key_Forward , QList<QKeySequence>(), false }, + { Reload , "Reload" , I18N_NOOP2("@action" , "Reload") , Qt::Key_F5 , Qt::Key_Refresh , QList<QKeySequence>(), false }, + + { BeginningOfLine, "BeginningOfLine" , I18N_NOOP2("@action" , "Beginning of Line") , Qt::Key_Home , 0 , QList<QKeySequence>(), false }, + { EndOfLine , "EndOfLine" , I18N_NOOP2("@action" , "End of Line") , Qt::Key_End , 0 , QList<QKeySequence>(), false }, + { GotoLine , "GotoLine" , I18N_NOOP2("@action" , "Go to Line") , CTRL(G) , 0 , QList<QKeySequence>(), false }, + { BackwardWord , "BackwardWord" , I18N_NOOP2("@action" , "Backward Word") , CTRL(Left) , 0 , QList<QKeySequence>(), false }, + { ForwardWord , "ForwardWord" , I18N_NOOP2("@action" , "Forward Word") , CTRL(Right) , 0 , QList<QKeySequence>(), false }, + + { AddBookmark , "AddBookmark" , I18N_NOOP2("@action" , "Add Bookmark") , CTRL(B) , 0 , QList<QKeySequence>(), false }, + { ZoomIn , "ZoomIn" , I18N_NOOP2("@action" , "Zoom In") , CTRL(Plus) , CTRL(Equal) , QList<QKeySequence>(), false }, + { ZoomOut , "ZoomOut" , I18N_NOOP2("@action" , "Zoom Out") , CTRL(Minus) , 0 , QList<QKeySequence>(), false }, + { FullScreen , "FullScreen" , I18N_NOOP2("@action" , "Full Screen Mode") , CTRLSHIFT(F) , 0 , QList<QKeySequence>(), false }, + + { ShowMenubar , "ShowMenubar" , I18N_NOOP2("@action" , "Show Menu Bar") , CTRL(M) , 0 , QList<QKeySequence>(), false }, + { TabNext , "Activate Next Tab" , I18N_NOOP2("@action" , "Activate Next Tab") , CTRL(Period) , CTRL(BracketRight), QList<QKeySequence>(), false }, + { TabPrev , "Activate Previous Tab", I18N_NOOP2("@action" , "Activate Previous Tab"), CTRL(Comma) , CTRL(BracketLeft) , QList<QKeySequence>(), false }, + + //Group Help + { Help , "Help" , I18N_NOOP2("@action" , "Help") , Qt::Key_F1 , 0 , QList<QKeySequence>(), false }, + { WhatsThis , "WhatsThis" , I18N_NOOP2("@action" , "What's This") , SHIFT(F1) , 0 , QList<QKeySequence>(), false }, + +//Group TextCompletion + { TextCompletion , "TextCompletion" , I18N_NOOP2("@action", "Text Completion") , CTRL(E) , 0, QList<QKeySequence>(), false }, + { PrevCompletion , "PrevCompletion" , I18N_NOOP2("@action", "Previous Completion Match"), CTRL(Up) , 0, QList<QKeySequence>(), false }, + { NextCompletion , "NextCompletion" , I18N_NOOP2("@action", "Next Completion Match") , CTRL(Down) , 0, QList<QKeySequence>(), false }, + { SubstringCompletion , "SubstringCompletion" , I18N_NOOP2("@action", "Substring Completion") , CTRL(T) , 0, QList<QKeySequence>(), false }, + + { RotateUp , "RotateUp" , I18N_NOOP2("@action", "Previous Item in List") , Qt::Key_Up , 0, QList<QKeySequence>(), false }, + { RotateDown , "RotateDown" , I18N_NOOP2("@action", "Next Item in List") , Qt::Key_Down, 0, QList<QKeySequence>(), false }, + + { OpenRecent , "OpenRecent" , I18N_NOOP2("@action", "Open Recent") , 0 , 0, QList<QKeySequence>(), false }, + { SaveAs , "SaveAs" , I18N_NOOP2("@action", "Save As") , CTRLSHIFT(S), 0, QList<QKeySequence>(), false }, + { Revert , "Revert" , I18N_NOOP2("@action", "Revert") , 0 , 0, QList<QKeySequence>(), false }, + { PrintPreview , "PrintPreview" , I18N_NOOP2("@action", "Print Preview") , 0 , 0, QList<QKeySequence>(), false }, + { Mail , "Mail" , I18N_NOOP2("@action", "Mail") , 0 , 0, QList<QKeySequence>(), false }, + { Clear , "Clear" , I18N_NOOP2("@action", "Clear") , 0 , 0, QList<QKeySequence>(), false }, + { ActualSize , "ActualSize" , I18N_NOOP2("@action", "Actual Size") , 0 , 0, QList<QKeySequence>(), false }, + { FitToPage , "FitToPage" , I18N_NOOP2("@action", "Fit To Page") , 0 , 0, QList<QKeySequence>(), false }, + { FitToWidth , "FitToWidth" , I18N_NOOP2("@action", "Fit To Width") , 0 , 0, QList<QKeySequence>(), false }, + { FitToHeight , "FitToHeight" , I18N_NOOP2("@action", "Fit To Height") , 0 , 0, QList<QKeySequence>(), false }, + { Zoom , "Zoom" , I18N_NOOP2("@action", "Zoom") , 0 , 0, QList<QKeySequence>(), false }, + { Goto , "Goto" , I18N_NOOP2("@action", "Goto") , 0 , 0, QList<QKeySequence>(), false }, + { GotoPage , "GotoPage" , I18N_NOOP2("@action", "Goto Page") , 0 , 0, QList<QKeySequence>(), false }, + { DocumentBack , "DocumentBack" , I18N_NOOP2("@action", "Document Back") , ALTSHIFT(Left), 0, QList<QKeySequence>(), false }, + { DocumentForward , "DocumentForward" , I18N_NOOP2("@action", "Document Forward") , ALTSHIFT(Right), 0, QList<QKeySequence>(), false }, + { EditBookmarks , "EditBookmarks" , I18N_NOOP2("@action", "Edit Bookmarks") , 0 , 0, QList<QKeySequence>(), false }, + { Spelling , "Spelling" , I18N_NOOP2("@action", "Spelling") , 0 , 0, QList<QKeySequence>(), false }, + { ShowToolbar , "ShowToolbar" , I18N_NOOP2("@action", "Show Toolbar") , 0 , 0, QList<QKeySequence>(), false }, + { ShowStatusbar , "ShowStatusbar" , I18N_NOOP2("@action", "Show Statusbar") , 0 , 0, QList<QKeySequence>(), false }, + { SaveOptions , "SaveOptions" , I18N_NOOP2("@action", "Save Options") , 0 , 0, QList<QKeySequence>(), false }, + { KeyBindings , "KeyBindings" , I18N_NOOP2("@action", "Key Bindings") , 0 , 0, QList<QKeySequence>(), false }, + { Preferences , "Preferences" , I18N_NOOP2("@action", "Preferences") , 0 , 0, QList<QKeySequence>(), false }, + { ConfigureToolbars , "ConfigureToolbars" , I18N_NOOP2("@action", "Configure Toolbars") , 0 , 0, QList<QKeySequence>(), false }, + { ConfigureNotifications , "ConfigureNotifications" , I18N_NOOP2("@action", "Configure Notifications") , 0 , 0, QList<QKeySequence>(), false }, + { TipofDay , "TipofDay" , I18N_NOOP2("@action", "Tip Of Day") , 0 , 0, QList<QKeySequence>(), false }, + { ReportBug , "ReportBug" , I18N_NOOP2("@action", "Report Bug") , 0 , 0, QList<QKeySequence>(), false }, + { SwitchApplicationLanguage, "SwitchApplicationLanguage", I18N_NOOP2("@action", "Switch Application Language"), 0 , 0, QList<QKeySequence>(), false }, + { AboutApp , "AboutApp" , I18N_NOOP2("@action", "About Application") , 0 , 0, QList<QKeySequence>(), false }, + { AboutKDE , "AboutKDE" , I18N_NOOP2("@action", "About KDE") , 0 , 0, QList<QKeySequence>(), false }, + + //dummy entry to catch simple off-by-one errors. Insert new entries before this line. + { AccelNone , 0 , 0 , 0 , 0, 0, QList<QKeySequence>(), false } +}; + + +/** Search for the KStandardShortcutInfo object associated with the given @p id. + Return a dummy entry with no name and an empty shortcut if @p id is invalid. +*/ +static KStandardShortcutInfo *guardedStandardShortcutInfo(StandardShortcut id) +{ + if (id >= static_cast<int>(sizeof(g_infoStandardShortcut) / sizeof(KStandardShortcutInfo)) || + id < 0) { + qWarning() << "KStandardShortcut: id not found!"; + return &g_infoStandardShortcut[AccelNone]; + } else + return &g_infoStandardShortcut[id]; +} + +/** Initialize the accelerator @p id by checking if it is overridden + in the configuration file (and if it isn't, use the default). + On X11, if QApplication was initialized with GUI disabled, + the default will always be used. +*/ +static void initialize(StandardShortcut id) +{ + KStandardShortcutInfo *info = guardedStandardShortcutInfo(id); + + // All three are needed. + if (info->id!=AccelNone) { + Q_ASSERT(info->description); + Q_ASSERT(info->translation_context); + Q_ASSERT(info->name); + } + + KConfigGroup cg(KSharedConfig::openConfig(), "Shortcuts"); + + if (cg.hasKey(info->name)) { + QString s = cg.readEntry(info->name); + if (s != QLatin1String("none")) + info->cut = QKeySequence::listFromString(s); + else + info->cut = QList<QKeySequence>(); + } else { + info->cut = hardcodedDefaultShortcut(id); + } + + info->isInitialized = true; +} + +void saveShortcut(StandardShortcut id, const QList<QKeySequence> &newShortcut) +{ + KStandardShortcutInfo *info = guardedStandardShortcutInfo(id); + // If the action has no standard shortcut associated there is nothing to + // save + if(info->id == AccelNone) + return; + + KConfigGroup cg(KSharedConfig::openConfig(), "Shortcuts"); + + info->cut = newShortcut; + bool sameAsDefault = (newShortcut == hardcodedDefaultShortcut(id)); + + if (sameAsDefault) { + // If the shortcut is the equal to the hardcoded one we remove it from + // kdeglobal if necessary and return. + if(cg.hasKey(info->name)) + cg.deleteEntry(info->name, KConfig::Global|KConfig::Persistent); + + return; + } + + // Write the changed shortcut to kdeglobals + cg.writeEntry(info->name, QKeySequence::listToString(info->cut), KConfig::Global|KConfig::Persistent); +} + +QString name(StandardShortcut id) +{ + return QString::fromLatin1(guardedStandardShortcutInfo(id)->name); +} + +QString label(StandardShortcut id) +{ + KStandardShortcutInfo *info = guardedStandardShortcutInfo( id ); + return QCoreApplication::translate("KStandardShortcut", + info->description, + info->translation_context); +} + +// TODO: Add psWhatsThis entry to KStandardShortcutInfo +QString whatsThis( StandardShortcut /*id*/ ) +{ +// KStandardShortcutInfo* info = guardedStandardShortcutInfo( id ); +// if( info && info->whatsThis ) +// return i18n(info->whatsThis); +// else + return QString(); +} + +const QList<QKeySequence> &shortcut(StandardShortcut id) +{ + KStandardShortcutInfo *info = guardedStandardShortcutInfo(id); + + if(!info->isInitialized) + initialize(id); + + return info->cut; +} + +StandardShortcut find(const QKeySequence &seq) +{ + if( !seq.isEmpty() ) { + for(uint i = 0; i < sizeof(g_infoStandardShortcut) / sizeof(KStandardShortcutInfo); i++) { + StandardShortcut id = g_infoStandardShortcut[i].id; + if( id != AccelNone ) { + if(!g_infoStandardShortcut[i].isInitialized) + initialize(id); + if(g_infoStandardShortcut[i].cut.contains(seq)) + return id; + } + } + } + return AccelNone; +} + +StandardShortcut find(const char *keyName) +{ + for(uint i = 0; i < sizeof(g_infoStandardShortcut) / sizeof(KStandardShortcutInfo); i++) + if (qstrcmp(g_infoStandardShortcut[i].name, keyName)) + return g_infoStandardShortcut[i].id; + + return AccelNone; +} + +QList<QKeySequence> hardcodedDefaultShortcut(StandardShortcut id) +{ + QList<QKeySequence> cut; + KStandardShortcutInfo *info = guardedStandardShortcutInfo(id); + + if (info->cutDefault != 0) + cut << info->cutDefault; + + if (info->cutDefault2 != 0) { + if (cut.isEmpty()) + cut << QKeySequence(); + + cut << info->cutDefault2; + } + + return cut; +} + +const QList<QKeySequence> &open() { return shortcut( Open ); } +const QList<QKeySequence> &openNew() { return shortcut( New ); } +const QList<QKeySequence> &close() { return shortcut( Close ); } +const QList<QKeySequence> &save() { return shortcut( Save ); } +const QList<QKeySequence> &print() { return shortcut( Print ); } +const QList<QKeySequence> &quit() { return shortcut( Quit ); } +const QList<QKeySequence> &cut() { return shortcut( Cut ); } +const QList<QKeySequence> ©() { return shortcut( Copy ); } +const QList<QKeySequence> &paste() { return shortcut( Paste ); } +const QList<QKeySequence> &pasteSelection() { return shortcut( PasteSelection ); } +const QList<QKeySequence> &deleteWordBack() { return shortcut( DeleteWordBack ); } +const QList<QKeySequence> &deleteWordForward() { return shortcut( DeleteWordForward ); } +const QList<QKeySequence> &undo() { return shortcut( Undo ); } +const QList<QKeySequence> &redo() { return shortcut( Redo ); } +const QList<QKeySequence> &find() { return shortcut( Find ); } +const QList<QKeySequence> &findNext() { return shortcut( FindNext ); } +const QList<QKeySequence> &findPrev() { return shortcut( FindPrev ); } +const QList<QKeySequence> &replace() { return shortcut( Replace ); } +const QList<QKeySequence> &home() { return shortcut( Home ); } +const QList<QKeySequence> &begin() { return shortcut( Begin ); } +const QList<QKeySequence> &end() { return shortcut( End ); } +const QList<QKeySequence> &beginningOfLine() { return shortcut( BeginningOfLine ); } +const QList<QKeySequence> &endOfLine() { return shortcut( EndOfLine ); } +const QList<QKeySequence> &prior() { return shortcut( Prior ); } +const QList<QKeySequence> &next() { return shortcut( Next ); } +const QList<QKeySequence> &backwardWord() { return shortcut( BackwardWord ); } +const QList<QKeySequence> &forwardWord() { return shortcut( ForwardWord ); } +const QList<QKeySequence> &gotoLine() { return shortcut( GotoLine ); } +const QList<QKeySequence> &addBookmark() { return shortcut( AddBookmark ); } +const QList<QKeySequence> &tabNext() { return shortcut( TabNext ); } +const QList<QKeySequence> &tabPrev() { return shortcut( TabPrev ); } +const QList<QKeySequence> &fullScreen() { return shortcut( FullScreen ); } +const QList<QKeySequence> &zoomIn() { return shortcut( ZoomIn ); } +const QList<QKeySequence> &zoomOut() { return shortcut( ZoomOut ); } +const QList<QKeySequence> &help() { return shortcut( Help ); } +const QList<QKeySequence> &completion() { return shortcut( TextCompletion ); } +const QList<QKeySequence> &prevCompletion() { return shortcut( PrevCompletion ); } +const QList<QKeySequence> &nextCompletion() { return shortcut( NextCompletion ); } +const QList<QKeySequence> &rotateUp() { return shortcut( RotateUp ); } +const QList<QKeySequence> &rotateDown() { return shortcut( RotateDown ); } +const QList<QKeySequence> &substringCompletion() { return shortcut( SubstringCompletion ); } +const QList<QKeySequence> &whatsThis() { return shortcut( WhatsThis ); } +const QList<QKeySequence> &reload() { return shortcut( Reload ); } +const QList<QKeySequence> &selectAll() { return shortcut( SelectAll ); } +const QList<QKeySequence> &up() { return shortcut( Up ); } +const QList<QKeySequence> &back() { return shortcut( Back ); } +const QList<QKeySequence> &forward() { return shortcut( Forward ); } +const QList<QKeySequence> &showMenubar() { return shortcut( ShowMenubar ); } + +} diff --git a/tier1/kconfig/src/gui/kstandardshortcut.h b/tier1/kconfig/src/gui/kstandardshortcut.h new file mode 100644 index 00000000..b02a6ebf --- /dev/null +++ b/tier1/kconfig/src/gui/kstandardshortcut.h @@ -0,0 +1,482 @@ +/* This file is part of the KDE libraries + Copyright (C) 1997 Stefan Taferner (taferner@kde.org) + Copyright (C) 2000 Nicolas Hadacek (hadacek@kde.org) + Copyright (C) 2001,2002 Ellis Whitehead (ellis@kde.org) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ +#ifndef KSTANDARDSHORTCUT_H +#define KSTANDARDSHORTCUT_H + +#include <QtCore/QString> +#include <QKeySequence> + +#include <kconfiggui_export.h> + +/** + * \namespace KStandardShortcut + * Convenient methods for access to the common accelerator keys in + * the key configuration. These are the standard keybindings that should + * be used in all KDE applications. They will be configurable, + * so do not hardcode the default behavior. + */ +namespace KStandardShortcut +{ // STUFF WILL BREAK IF YOU DON'T READ THIS!!! + /* + *Always add new std-accels to the end of this enum, never in the middle! + *Don't forget to add the corresponding entries in g_infoStandardShortcut[] in kstandardshortcut.cpp, too. + *Values of elements here and positions of the corresponding entries in + *the big array g_infoStandardShortcut[] ABSOLUTELY MUST BE THE SAME. + * !!! !!!! !!!!! !!!! + * !!!! !!! !!!! !!!! + * Remember to also update kdoctools/genshortcutents.cpp. + * + * Other Rules: + * + * - Never change the name of an existing shortcut + * - Never translate the name of a shortcut + */ + + /** + * Defines the identifier of all standard accelerators. + */ + enum StandardShortcut { + //C++ requires that the value of an enum symbol be one more than the previous one. + //This means that everything will be well-ordered from here on. + AccelNone=0, + // File menu + Open, New, Close, Save, + // The Print item + Print, + Quit, + // Edit menu + Undo, Redo, Cut, Copy, Paste, PasteSelection, + SelectAll, Deselect, DeleteWordBack, DeleteWordForward, + Find, FindNext, FindPrev, Replace, + // Navigation + Home, Begin, End, Prior, Next, + Up, Back, Forward, Reload, + // Text Navigation + BeginningOfLine, EndOfLine, GotoLine, + BackwardWord, ForwardWord, + // View parameters + AddBookmark, ZoomIn, ZoomOut, FullScreen, + ShowMenubar, + // Tabular navigation + TabNext, TabPrev, + // Help menu + Help, WhatsThis, + // Text completion + TextCompletion, PrevCompletion, NextCompletion, SubstringCompletion, + + RotateUp, RotateDown, + + OpenRecent, + SaveAs, + Revert, + PrintPreview, + Mail, + Clear, + ActualSize, + FitToPage, + FitToWidth, + FitToHeight, + Zoom, + Goto, + GotoPage, + DocumentBack, + DocumentForward, + EditBookmarks, + Spelling, + ShowToolbar, + ShowStatusbar, + SaveOptions, + KeyBindings, + Preferences, + ConfigureToolbars, + ConfigureNotifications, + TipofDay, + ReportBug, + SwitchApplicationLanguage, + AboutApp, + AboutKDE, + + // Insert new items here! + + StandardShortcutCount // number of standard shortcuts + }; + + /** + * Returns the keybinding for @p accel. + * On X11, if QApplication was initialized with GUI disabled, the + * default keybinding will always be returned. + * @param id the id of the accelerator + */ + KCONFIGGUI_EXPORT const QList<QKeySequence> &shortcut(StandardShortcut id); + + /** + * Returns a unique name for the given accel. + * @param id the id of the accelerator + * @return the unique name of the accelerator + */ + KCONFIGGUI_EXPORT QString name(StandardShortcut id); + + /** + * Returns a localized label for user-visible display. + * @param id the id of the accelerator + * @return a localized label for the accelerator + */ + KCONFIGGUI_EXPORT QString label(StandardShortcut id); + + /** + * Returns an extended WhatsThis description for the given accelerator. + * @param id the id of the accelerator + * @return a localized description of the accelerator + */ + KCONFIGGUI_EXPORT QString whatsThis(StandardShortcut id); + + /** + * Return the StandardShortcut id of the standard accel action which + * uses this key sequence, or AccelNone if none of them do. + * This is used by class KKeyChooser. + * @param keySeq the key sequence to search + * @return the id of the standard accelerator, or AccelNone if there + * is none + */ + KCONFIGGUI_EXPORT StandardShortcut find(const QKeySequence &keySeq); + + /** + * Return the StandardShortcut id of the standard accel action which + * has \a keyName as its name, or AccelNone if none of them do. + * This is used by class KKeyChooser. + * @param keyName the key sequence to search + * @return the id of the standard accelerator, or AccelNone if there + * is none + */ + KCONFIGGUI_EXPORT StandardShortcut find(const char *keyName); + + /** + * Returns the hardcoded default shortcut for @p id. + * This does not take into account the user's configuration. + * @param id the id of the accelerator + * @return the default shortcut of the accelerator + */ + KCONFIGGUI_EXPORT QList<QKeySequence> hardcodedDefaultShortcut(StandardShortcut id); + + /** + * Saves the new shortcut \a cut for standard accel \a id. + */ + KCONFIGGUI_EXPORT void saveShortcut(StandardShortcut id, const QList<QKeySequence> &newShortcut); + + /** + * Open file. Default: Ctrl-o + * @return the shortcut of the standard accelerator + */ + KCONFIGGUI_EXPORT const QList<QKeySequence> &open(); + + /** + * Create a new document (or whatever). Default: Ctrl-n + * @return the shortcut of the standard accelerator + */ + KCONFIGGUI_EXPORT const QList<QKeySequence> &openNew(); + + /** + * Close current document. Default: Ctrl-w + * @return the shortcut of the standard accelerator + */ + KCONFIGGUI_EXPORT const QList<QKeySequence> &close(); + + /** + * Save current document. Default: Ctrl-s + * @return the shortcut of the standard accelerator + */ + KCONFIGGUI_EXPORT const QList<QKeySequence> &save(); + + /** + * Print current document. Default: Ctrl-p + * @return the shortcut of the standard accelerator + */ + KCONFIGGUI_EXPORT const QList<QKeySequence> &print(); + + /** + * Quit the program. Default: Ctrl-q + * @return the shortcut of the standard accelerator + */ + KCONFIGGUI_EXPORT const QList<QKeySequence> &quit(); + + /** + * Undo last operation. Default: Ctrl-z + * @return the shortcut of the standard accelerator + */ + KCONFIGGUI_EXPORT const QList<QKeySequence> &undo(); + + /** + * Redo. Default: Shift-Ctrl-z + * @return the shortcut of the standard accelerator + */ + KCONFIGGUI_EXPORT const QList<QKeySequence> &redo(); + + /** + * Cut selected area and store it in the clipboard. Default: Ctrl-x + * @return the shortcut of the standard accelerator + */ + KCONFIGGUI_EXPORT const QList<QKeySequence> &cut(); + + /** + * Copy selected area into the clipboard. Default: Ctrl-c + * @return the shortcut of the standard accelerator + */ + KCONFIGGUI_EXPORT const QList<QKeySequence> ©(); + + /** + * Paste contents of clipboard at mouse/cursor position. Default: Ctrl-v + * @return the shortcut of the standard accelerator + */ + KCONFIGGUI_EXPORT const QList<QKeySequence> &paste(); + + /** + * Paste the selection at mouse/cursor position. Default: Ctrl-Shift-Insert + * @return the shortcut of the standard accelerator + */ + KCONFIGGUI_EXPORT const QList<QKeySequence> &pasteSelection(); + + /** + * Select all. Default: Ctrl-A + * @return the shortcut of the standard accelerator + **/ + KCONFIGGUI_EXPORT const QList<QKeySequence> &selectAll(); + + /** + * Delete a word back from mouse/cursor position. Default: Ctrl-Backspace + * @return the shortcut of the standard accelerator + */ + KCONFIGGUI_EXPORT const QList<QKeySequence> &deleteWordBack(); + + /** + * Delete a word forward from mouse/cursor position. Default: Ctrl-Delete + * @return the shortcut of the standard accelerator + */ + KCONFIGGUI_EXPORT const QList<QKeySequence> &deleteWordForward(); + + /** + * Find, search. Default: Ctrl-f + * @return the shortcut of the standard accelerator + */ + KCONFIGGUI_EXPORT const QList<QKeySequence> &find(); + + /** + * Find/search next. Default: F3 + * @return the shortcut of the standard accelerator + */ + KCONFIGGUI_EXPORT const QList<QKeySequence> &findNext(); + + /** + * Find/search previous. Default: Shift-F3 + * @return the shortcut of the standard accelerator + */ + KCONFIGGUI_EXPORT const QList<QKeySequence> &findPrev(); + + /** + * Find and replace matches. Default: Ctrl-r + * @return the shortcut of the standard accelerator + */ + KCONFIGGUI_EXPORT const QList<QKeySequence> &replace(); + + /** + * Zoom in. Default: Ctrl-Plus + * @return the shortcut of the standard accelerator + */ + KCONFIGGUI_EXPORT const QList<QKeySequence> &zoomIn(); + + /** + * Zoom out. Default: Ctrl-Minus + * @return the shortcut of the standard accelerator + */ + KCONFIGGUI_EXPORT const QList<QKeySequence> &zoomOut(); + + /** + * Toggle insert/overwrite (with visual feedback, e.g. in the statusbar). Default: Insert + * @return the shortcut of the standard accelerator + */ + KCONFIGGUI_EXPORT const QList<QKeySequence> &insert(); + + /** + * Goto home page. Default: Alt-Home + * @return the shortcut of the standard accelerator + */ + KCONFIGGUI_EXPORT const QList<QKeySequence> &home(); + + /** + * Goto beginning of the document. Default: Ctrl-Home + * @return the shortcut of the standard accelerator + */ + KCONFIGGUI_EXPORT const QList<QKeySequence> &begin(); + + /** + * Goto end of the document. Default: Ctrl-End + * @return the shortcut of the standard accelerator + */ + KCONFIGGUI_EXPORT const QList<QKeySequence> &end(); + + /** + * Goto beginning of current line. Default: Home + * @return the shortcut of the standard accelerator + */ + KCONFIGGUI_EXPORT const QList<QKeySequence> &beginningOfLine(); + + /** + * Goto end of current line. Default: End + * @return the shortcut of the standard accelerator + */ + KCONFIGGUI_EXPORT const QList<QKeySequence> &endOfLine(); + + /** + * Scroll up one page. Default: Prior + * @return the shortcut of the standard accelerator + */ + KCONFIGGUI_EXPORT const QList<QKeySequence> &prior(); + + /** + * Scroll down one page. Default: Next + * @return the shortcut of the standard accelerator + */ + KCONFIGGUI_EXPORT const QList<QKeySequence> &next(); + + /** + * Go to line. Default: Ctrl+G + * @return the shortcut of the standard accelerator + */ + KCONFIGGUI_EXPORT const QList<QKeySequence> &gotoLine(); + + /** + * Add current page to bookmarks. Default: Ctrl+B + * @return the shortcut of the standard accelerator + */ + KCONFIGGUI_EXPORT const QList<QKeySequence> &addBookmark(); + + /** + * Next Tab. Default: Ctrl-< + * @return the shortcut of the standard accelerator + */ + KCONFIGGUI_EXPORT const QList<QKeySequence> &tabNext(); + + /** + * Previous Tab. Default: Ctrl-> + * @return the shortcut of the standard accelerator + */ + KCONFIGGUI_EXPORT const QList<QKeySequence> &tabPrev(); + + /** + * Full Screen Mode. Default: Ctrl+Shift+F + * @return the shortcut of the standard accelerator + */ + KCONFIGGUI_EXPORT const QList<QKeySequence> &fullScreen(); + + /** + * Help the user in the current situation. Default: F1 + * @return the shortcut of the standard accelerator + */ + KCONFIGGUI_EXPORT const QList<QKeySequence> &help(); + + /** + * Complete text in input widgets. Default Ctrl+E + * @return the shortcut of the standard accelerator + **/ + KCONFIGGUI_EXPORT const QList<QKeySequence> &completion(); + + /** + * Iterate through a list when completion returns + * multiple items. Default: Ctrl+Up + * @return the shortcut of the standard accelerator + */ + KCONFIGGUI_EXPORT const QList<QKeySequence> &prevCompletion(); + + /** + * Iterate through a list when completion returns + * multiple items. Default: Ctrl+Down + * @return the shortcut of the standard accelerator + */ + KCONFIGGUI_EXPORT const QList<QKeySequence> &nextCompletion(); + + /** + * Find a string within another string or list of strings. + * Default: Ctrl-T + * @return the shortcut of the standard accelerator + */ + KCONFIGGUI_EXPORT const QList<QKeySequence> &substringCompletion(); + + /** + * Help users iterate through a list of entries. Default: Up + * @return the shortcut of the standard accelerator + */ + KCONFIGGUI_EXPORT const QList<QKeySequence> &rotateUp(); + + /** + * Help users iterate through a list of entries. Default: Down + * @return the shortcut of the standard accelerator + */ + KCONFIGGUI_EXPORT const QList<QKeySequence> &rotateDown(); + + /** + * What's This button. Default: Shift+F1 + * @return the shortcut of the standard accelerator + */ + KCONFIGGUI_EXPORT const QList<QKeySequence> &whatsThis(); + + /** + * Reload. Default: F5 + * @return the shortcut of the standard accelerator + */ + KCONFIGGUI_EXPORT const QList<QKeySequence> &reload(); + + /** + * Up. Default: Alt+Up + * @return the shortcut of the standard accelerator + */ + KCONFIGGUI_EXPORT const QList<QKeySequence> &up(); + + /** + * Back. Default: Alt+Left + * @return the shortcut of the standard accelerator + */ + KCONFIGGUI_EXPORT const QList<QKeySequence> &back(); + + /** + * Forward. Default: ALT+Right + * @return the shortcut of the standard accelerator + */ + KCONFIGGUI_EXPORT const QList<QKeySequence> &forward(); + + /** + * BackwardWord. Default: Ctrl+Left + * @return the shortcut of the standard accelerator + */ + KCONFIGGUI_EXPORT const QList<QKeySequence> &backwardWord(); + + /** + * ForwardWord. Default: Ctrl+Right + * @return the shortcut of the standard accelerator + */ + KCONFIGGUI_EXPORT const QList<QKeySequence> &forwardWord(); + + /** + * Show Menu Bar. Default: Ctrl-M + * @return the shortcut of the standard accelerator + */ + KCONFIGGUI_EXPORT const QList<QKeySequence> &showMenubar(); + +} + +#endif // KSTANDARDSHORTCUT_H diff --git a/tier1/kconfig/src/gui/kwindowconfig.cpp b/tier1/kconfig/src/gui/kwindowconfig.cpp new file mode 100644 index 00000000..6b7ae5f0 --- /dev/null +++ b/tier1/kconfig/src/gui/kwindowconfig.cpp @@ -0,0 +1,83 @@ +/* + This file is part of the KDE libraries + Copyright (c) 2012 Benjamin Port <benjamin.port@ben2367.fr> + + 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) version 3, or any + later version 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 defined in Section 6 of version 3 of the license. + + 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, see <http://www.gnu.org/licenses/>. +*/ + +#include "kwindowconfig.h" + +#include <QScreen> +#include <QWindow> + +static const char* s_initialSizePropertyName = "_kconfig_initial_size"; +static const char* s_initialScreenSizePropertyName = "_kconfig_initial_screen_size"; + +void KWindowConfig::saveWindowSize(const QWindow *window, KConfigGroup &config, KConfigGroup::WriteConfigFlags options) +{ + if (!window) + return; + const QRect desk = window->screen()->geometry(); + + const QSize sizeToSave = window->size(); + const bool isMaximized = window->windowState() & Qt::WindowMaximized; + + const QString screenMaximizedString(QString::fromLatin1("Window-Maximized %1x%2").arg(desk.height()).arg(desk.width())); + // Save size only if window is not maximized + if (!isMaximized) { + const QSize defaultSize(window->property(s_initialSizePropertyName).toSize()); + const QSize defaultScreenSize(window->property(s_initialScreenSizePropertyName).toSize()); + const bool sizeValid = defaultSize.isValid() && defaultScreenSize.isValid(); + if (!sizeValid || (sizeValid && (defaultSize != sizeToSave || defaultScreenSize != desk.size()))) { + const QString wString(QString::fromLatin1("Width %1").arg(desk.width())); + const QString hString(QString::fromLatin1("Height %1").arg(desk.height())); + config.writeEntry(wString, sizeToSave.width(), options); + config.writeEntry(hString, sizeToSave.height(), options); + } + } + if ( (isMaximized == false) && !config.hasDefault(screenMaximizedString) ) + config.revertToDefault(screenMaximizedString); + else + config.writeEntry(screenMaximizedString, isMaximized, options); + +} + +void KWindowConfig::restoreWindowSize(QWindow* window, const KConfigGroup& config) +{ + if (!window) + return; + + const QRect desk = window->screen()->geometry(); + + const int width = config.readEntry(QString::fromLatin1("Width %1").arg(desk.width()), window->size().width()); + const int height = config.readEntry(QString::fromLatin1("Height %1").arg(desk.height()), window->size().height()); + const bool isMaximized = config.readEntry(QString::fromLatin1("Window-Maximized %1x%2").arg(desk.height()).arg(desk.width()), false); + + // Check default size + const QSize defaultSize(window->property(s_initialSizePropertyName).toSize()); + const QSize defaultScreenSize(window->property(s_initialScreenSizePropertyName).toSize()); + if (!defaultSize.isValid() || !defaultScreenSize.isValid()) { + window->setProperty(s_initialSizePropertyName, window->size()); + window->setProperty(s_initialScreenSizePropertyName, desk.size()); + } + + // If window is maximized set maximized state and in all case set the size + window->resize(width, height); + if (isMaximized) { + window->setWindowState(Qt::WindowMaximized); + } +} diff --git a/tier1/kconfig/src/gui/kwindowconfig.h b/tier1/kconfig/src/gui/kwindowconfig.h new file mode 100644 index 00000000..2c70571d --- /dev/null +++ b/tier1/kconfig/src/gui/kwindowconfig.h @@ -0,0 +1,58 @@ +/* + This file is part of the KDE libraries + Copyright (c) 2012 Benjamin Port <benjamin.port@ben2367.fr> + + 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) version 3, or any + later version 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 defined in Section 6 of version 3 of the license. + + 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, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef KWINDOWCONFIG_H +#define KWINDOWCONFIG_H + +#include <kconfiggroup.h> +#include <kconfiggui_export.h> + +class QWindow; + +namespace KWindowConfig +{ + /** + * Saves the window's size dependent on the screen dimension either to the + * global or application config file. + * + * @note the group must be set before calling + * + * @param window The window to save size. + * @param config The config group to read from. + * @param options passed to KConfigGroup::writeEntry() + * @since 5.0 + */ + KCONFIGGUI_EXPORT void saveWindowSize( const QWindow* window, KConfigGroup& config, KConfigGroup::WriteConfigFlags options = KConfigGroup::Normal ); + + /** + * Restores the dialog's size from the configuration according to + * the screen size. + * + * @note the group must be set before calling + * + * @param dialog The dialog to restore size. + * @param config The config group to read from. + * @since 5.0. + */ + KCONFIGGUI_EXPORT void restoreWindowSize( QWindow* window, const KConfigGroup& config ); +} + +#endif // KWINDOWCONFIG_H diff --git a/tier1/kconfig/src/kconf_update/CMakeLists.txt b/tier1/kconfig/src/kconf_update/CMakeLists.txt new file mode 100644 index 00000000..e4e37ba9 --- /dev/null +++ b/tier1/kconfig/src/kconf_update/CMakeLists.txt @@ -0,0 +1,17 @@ +find_package(Qt5Core 5.2.0 REQUIRED NO_MODULE) + +remove_definitions(-DQT_NO_CAST_FROM_ASCII) + +configure_file(config-kconf.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-kconf.h ) + +########### next target ############### + +set(kconf_update_SRCS + kconf_update.cpp + kconfigutils.cpp + ) + +add_executable(kconf_update ${kconf_update_SRCS}) +target_link_libraries(kconf_update Qt5::Core KF5::ConfigCore) + +install(TARGETS kconf_update DESTINATION ${LIBEXEC_INSTALL_DIR}) diff --git a/tier1/kconfig/src/kconf_update/Mainpage.dox b/tier1/kconfig/src/kconf_update/Mainpage.dox new file mode 100644 index 00000000..77d486ce --- /dev/null +++ b/tier1/kconfig/src/kconf_update/Mainpage.dox @@ -0,0 +1,31 @@ +/** @mainpage ./kconf_update + +kconf_update is a tool designed to update config files. Over time applications +sometimes need to rearrange the way configuration options are stored. Since +such an update shouldn't influence the configuration options that the user +has selected, the application must take care that the options stored in the +old way will still be honored. + +What used to happen is that the application looks up both the old and the +new configuration option and then decides which one to use. This method has +several drawbacks: +- The application may need to read more configuration files than strictly + needed, resulting in a slower startup. +- The application becomes bigger with code that will only be used once. + +kconf_update addresses these problems by offering a framework to update +configuration files without adding code to the application itself. + +See the <a href="http://websvn.kde.org/trunk/KDE/kdelibs/kconf_update/README.kconf_update?view=markup">README file</a> for more information. + +@authors +Waldo Bastian \<bastian@kde.org\> + +@maintainers +[Unknown/None] + +@licenses +@lgpl + +*/ +// vim:ts=4:sw=4:expandtab:filetype=doxygen diff --git a/tier1/kconfig/src/kconf_update/README.kconf_update b/tier1/kconfig/src/kconf_update/README.kconf_update new file mode 100644 index 00000000..281fb9e5 --- /dev/null +++ b/tier1/kconfig/src/kconf_update/README.kconf_update @@ -0,0 +1,248 @@ +README kconf_update + +Version: 1.1 +Author: Waldo Bastian <bastian@kde.org>, <bastian@suse.com> + +What it does +============ + +kconf_update is a tool designed to update config files. Over time applications +sometimes need to rearrange the way configuration options are stored. Since +such an update shouldn't influence the configuration options that the user +has selected, the application must take care that the options stored in the +old way will still be honored. + +What used to happen is that the application looks up both the old and the +new configuration option and then decides which one to use. This method has +several drawbacks: +* The application may need to read more configuration files than strictly +needed, resulting in a slower startup. +* The application becomes bigger with code that will only be used once. + +kconf_update addresses these problems by offering a framework to update +configuration files without adding code to the application itself. + + +How it works +============ + +Applications can install so called "update files" under +$KDEDIR/share/apps/kconf_update. An update file has ".upd" as extension and +contains instructions for transferring/converting configuration information +from one place to another. + +Updating the configuration happens automatically, either when KDE gets started +or when kded detects a new update file in the above mentioned location. + +Update files are separated into sections. Each section has an Id. When a +section describing a configuration change has been applied, the Id will be +stored in the file "kconf_updaterc". This information is used to make sure +that a configuration update is only performed once. + +If you overwrite an existing update file with a new version that contains a +new section, only the update instructions from this extra section will be +performed. + +File format of the update file +============================== + +Empty lines or lines that start with '#' are considered comments. +Commas (,) are used to seperate fields and may not occur as part +of any field and all of the keywords are case-sensitive, i.e. you +cannot say "key" instead of "Key" for example. + +For the rest the file is parsed and executed sequentially from top to bottom. +Each line can contain one entry. The following entries are recognized: + + +Id=<id> + +With <id> identifying the group of update entries that follows. Once a group +of entries have been applied, their <id> is stored and this group of entries +will not be applied again. + + +File=<oldfile>,<newfile> +File=<oldfile> + +Specifies that configuration information is read from <oldfile> and written +to <newfile>. If you only specify <oldfile>, the information is read from +as well as written to <oldfile>. Note that if the file does not exist +at the time kconf_update first checks, no related update will be performed +(script won't be run at all, etc.). + + +Script=<script>[,<interpreter>] + +All entries from <oldfile> are piped into <script>. The output of script +is used as new entries for <newfile>. Existing entries can be deleted by +adding lines with "# DELETE [group]key" in the output of the script. +To delete a whole group use "# DELETEGROUP [group]". + +<script> should be installed into $(kde_datadir)/kconf_update, or +kconf_update will not be able to find it. It's also possible to install +kconf_update applications in $(kde_bindir)/kconf_update_bin, which opens the +door to kconf_update applications that are written in C++ and use Qt's +powerful string API instead. + +If Script was issued after a "Group" command the behavior is slightly +different: +All entries from <oldfile>/<oldgroup> are piped into <script>. The output +of script is used as new entries for <newfile>/<newgroup>, unless a different +group is specified with "[group]". Existing entries can be deleted from +<oldgroup> by adding lines with "# DELETE key" in the output of the script. +To delete <oldgroup> use "# DELETEGROUP". + +<interpreter> can be something like "perl". + +It is also possible to have a Script without specifying <oldfile> or +<newfile>. In that case the script is run but it will not be fed any input +and its output will simply be discarded. + +ScriptArguments=<arguments> + +If specified, the arguments will be passed to <script>. +IMPORTANT: It has to be specified before Script=. + +Group=<oldgroup>,<newgroup> +Group=<oldgroup> + +Specifies that configuration information is read from the group <oldgroup> +and written to <newgroup>. If you only specify <oldgroup>, the information +is read from as well as written to <oldgroup>. You can use <default> to +specify keys that are not under any group. +A group may be written either as "group" or as "[group]". The latter syntax +makes it possible to specify subgroups: "[group][subgroup]". + +RemoveGroup=<oldgroup> + +Specifies that <oldgroup> is removed entirely. This can be used +to remove obsolete entries or to force a revert to default values. + +Options=<option1>, <option2>, .... + +With this entry you can specify options that apply to the next "Script", +"Key" or "AllKeys" entry (only to the first!). Possible options are: + +- "copy" Copy the configuration item instead of moving it. This means that + the configuration item will not be deleted from <oldfile>/<oldgroup>. + +- "overwrite" Normally, a configuration item is not moved if an item with the + new name already exists. When this option is specified the old + configuration item will overwrite any existing item. + + +Key=<oldkey>,<newkey> +Key=<oldkey> + +Specifies that configuration information is read from the key <oldkey> +and written to <newkey>. If you only specify <oldkey>, the information +is read from as well as written to <oldkey>. + + +AllKeys + +Specifies that all configuration information in the selected group should +be moved (All keys). + +AllGroups + +Specifies that all configuration information from all keys in ALL +groups should be moved. + + +RemoveKey=<oldkey> + +Specifies that <oldkey> is removed from the selected group. This can be used +to remove obsolete entries or to force a revert to default values. + + +Example update file +=================== + +# This is comment +Id=kde2.2 +File=kioslaverc,kio_httprc +Group=Proxy Settings +Key=NoProxyFor +Key=UseProxy +Key=httpProxy,Proxy +Group=Cache Settings,Cache +Key=MaxCacheSize +Key=UseCache +Group=UserAgent +AllKeys +RemoveGroup=KDE +# End of file + + +The above update file extracts config information from the file "kioslaverc" +and stores it into the file "kio_httprc". + +It reads the keys "NoProxyFor", "UseProxy" and "httpProxy" from the group +"Proxy Settings" in the "kioslaverc" file. If any of these options are present +they are written to the keys "NoProxyFor", "UseProxy" and "Proxy" (!) in +the group "Proxy Settings" in the "kio_httprc" file. + +It also reads the keys "MaxCacheSize" and "UseCache" from the group +"Cache Settings" in the "kioslaverc" file and writes this information to the +keys "MaxCacheSize" and "UseCache" in the group "Cache" (!) in the +"kio_httprc" file. + +Then it takes all keys in the "UserAgent" group of the file "kioslaverc" +and moves then to the "UserAgent" group in the "kio_httprc" file. + +Finally it removes the entire "KDE" group in the kioslaverc file. + + +Debugging and testing +===================== + +If you are developing a kconf_update script and want to test or debug it you +need to make sure kconf_update runs again after each of your changes. There +are a number of ways to achieve this. + +The easiest is to not install the kconf_update script in the first place, but +manually call it through a pipe. If you want to test the update script for +your application KHello's config file khellorc, you can test by using + + cat ~/.kde/share/config/khellorc | khello_conf_update.sh + +(assuming khello_conf_update.sh is the kconf_update script and ~/.kde is your +$KDEHOME). This is easier than making install every time, but has the obvious +downside that you need to 'parse' your script's output yourself instead of +letting kconf_update do it and check the resulting output file. + +After 'make install' the kconf_update script is run by kded, but it does so +only once. This is of course the idea behind it, but while developing it can +be a problem. You can increase the revision number for each subsequent run +of 'make install' to force a new kconf_update run, but there's a better +approach that doesn't skyrocket the version number for a mediocre debug +session. + +kded doesn't really ignore scripts that it has already run right away. +Instead it checks the affected config file every time a .upd file is added +or changed. The reason it still doesn't run again on your config file lies +in the traces kconf_update leaves behind: it adds a special config group +'[$Version]' with a key 'update_info'. This key lists all kconf_update +scripts that have already been run on this config file. It also adds a group +for the script to $KDEHOME/share/config/kconf_updaterc. Just remove your +script entries from both your rcfile and kconf_updaterc, 'make install', +and kconf_update will happily run your script again, without you having to +increase the version number. + +If you want to know what kconf_update has been up to lately, have a look +at $KDEHOME/share/apps/kconf_update/log/update.log + + +Common Problems +=============== + +* kconf_update refuses to update an entry +If you change the value of an entry without changing the key or file, +make sure to tell kconf_update that it should overwrite the old entry +by adding "Options=overwrite". + + +Have fun, +Waldo diff --git a/tier1/kconfig/src/kconf_update/config-kconf.h.cmake b/tier1/kconfig/src/kconf_update/config-kconf.h.cmake new file mode 100644 index 00000000..0f70f8c8 --- /dev/null +++ b/tier1/kconfig/src/kconf_update/config-kconf.h.cmake @@ -0,0 +1,4 @@ +#define CMAKE_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}" +#define LIBEXEC_INSTALL_DIR "${LIBEXEC_INSTALL_DIR}" +#define LIB_INSTALL_DIR "${LIB_INSTALL_DIR}" +#define KCONF_UPDATE_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}" diff --git a/tier1/kconfig/src/kconf_update/kconf_update.cpp b/tier1/kconfig/src/kconf_update/kconf_update.cpp new file mode 100644 index 00000000..60a61db3 --- /dev/null +++ b/tier1/kconfig/src/kconf_update/kconf_update.cpp @@ -0,0 +1,967 @@ +/* + * + * This file is part of the KDE libraries + * Copyright (c) 2001 Waldo Bastian <bastian@kde.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License version 2 as published by the Free Software Foundation. + * + * 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + **/ + +#include <config-kconf.h> // CMAKE_INSTALL_PREFIX + +#include <QtCore/QDate> +#include <QtCore/QFile> +#include <QtCore/QTextStream> +#include <QtCore/QTextCodec> +#include <QUrl> +#include <QTemporaryFile> +#include <QCoreApplication> +#include <QtCore/QDir> + +#include <kconfig.h> +#include <kconfiggroup.h> + +#include <qstandardpaths.h> +#include <qcommandlineparser.h> +#include <qcommandlineoption.h> + +#include "kconfigutils.h" + +class KonfUpdate +{ +public: + KonfUpdate(QCommandLineParser *parser); + ~KonfUpdate(); + QStringList findUpdateFiles(bool dirtyOnly); + + QTextStream &log(); + QTextStream &logFileError(); + + bool checkFile(const QString &filename); + void checkGotFile(const QString &_file, const QString &id); + + bool updateFile(const QString &filename); + + void gotId(const QString &_id); + void gotFile(const QString &_file); + void gotGroup(const QString &_group); + void gotRemoveGroup(const QString &_group); + void gotKey(const QString &_key); + void gotRemoveKey(const QString &_key); + void gotAllKeys(); + void gotAllGroups(); + void gotOptions(const QString &_options); + void gotScript(const QString &_script); + void gotScriptArguments(const QString &_arguments); + void resetOptions(); + + void copyGroup(const KConfigBase *cfg1, const QString &group1, + KConfigBase *cfg2, const QString &group2); + void copyGroup(const KConfigGroup &cg1, KConfigGroup &cg2); + void copyOrMoveKey(const QStringList &srcGroupPath, const QString &srcKey, const QStringList &dstGroupPath, const QString &dstKey); + void copyOrMoveGroup(const QStringList &srcGroupPath, const QStringList &dstGroupPath); + + QStringList parseGroupString(const QString &_str); + +protected: + KConfig *m_config; + QString m_currentFilename; + bool m_skip; + bool m_skipFile; + bool m_debug; + QString m_id; + + QString m_oldFile; + QString m_newFile; + QString m_newFileName; + KConfig *m_oldConfig1; // Config to read keys from. + KConfig *m_oldConfig2; // Config to delete keys from. + KConfig *m_newConfig; + + QStringList m_oldGroup; + QStringList m_newGroup; + + bool m_bCopy; + bool m_bOverwrite; + bool m_bUseConfigInfo; + QString m_arguments; + QTextStream *m_textStream; + QFile *m_file; + QString m_line; + int m_lineCount; +}; + +KonfUpdate::KonfUpdate(QCommandLineParser * parser) + : m_textStream(0), m_file(0) +{ + bool updateAll = false; + m_oldConfig1 = 0; + m_oldConfig2 = 0; + m_newConfig = 0; + + m_config = new KConfig("kconf_updaterc"); + KConfigGroup cg(m_config, QString()); + + QStringList updateFiles; + + m_debug = parser->isSet("debug"); + + m_bUseConfigInfo = false; + if (parser->isSet("check")) { + m_bUseConfigInfo = true; + QString file = QStandardPaths::locate(QStandardPaths::GenericDataLocation, "kconf_update/" + parser->value("check")); + if (file.isEmpty()) { + qWarning("File '%s' not found.", parser->value("check").toLocal8Bit().data()); + log() << "File '" << parser->value("check") << "' passed on command line not found" << endl; + return; + } + updateFiles.append(file); + } else if (parser->positionalArguments().count()) { + updateFiles += parser->positionalArguments(); + } else { + if (cg.readEntry("autoUpdateDisabled", false)) + return; + updateFiles = findUpdateFiles(true); + updateAll = true; + } + + for (QStringList::ConstIterator it = updateFiles.constBegin(); + it != updateFiles.constEnd(); + ++it) { + updateFile(*it); + } + + if (updateAll && !cg.readEntry("updateInfoAdded", false)) { + cg.writeEntry("updateInfoAdded", true); + updateFiles = findUpdateFiles(false); + + for (QStringList::ConstIterator it = updateFiles.constBegin(); + it != updateFiles.constEnd(); + ++it) { + checkFile(*it); + } + updateFiles.clear(); + } +} + +KonfUpdate::~KonfUpdate() +{ + delete m_config; + delete m_file; + delete m_textStream; +} + +QTextStream & operator<<(QTextStream & stream, const QStringList & lst) +{ + stream << lst.join(", "); + return stream; +} + +QTextStream & +KonfUpdate::log() +{ + if (!m_textStream) { + QString dir = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QLatin1Char('/') + "kconf_update/log"; + QDir().mkpath(dir); + QString file = dir + "/update.log"; + m_file = new QFile(file); + if (m_file->open(QIODevice::WriteOnly | QIODevice::Append)) { + m_textStream = new QTextStream(m_file); + } else { + // Error + m_textStream = new QTextStream(stderr, QIODevice::WriteOnly); + } + } + + (*m_textStream) << QDateTime::currentDateTime().toString(Qt::ISODate) << " "; + + return *m_textStream; +} + +QTextStream & +KonfUpdate::logFileError() +{ + return log() << m_currentFilename << ':' << m_lineCount << ":'" << m_line << "': "; +} + +QStringList KonfUpdate::findUpdateFiles(bool dirtyOnly) +{ + QStringList result; + + const QStringList dirs = QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, "kconf_update", QStandardPaths::LocateDirectory); + Q_FOREACH(const QString& dir, dirs) { + const QStringList fileNames = QDir(dir).entryList(QStringList() << QStringLiteral("*.upd")); + Q_FOREACH(const QString& fileName, fileNames) { + const QString file = dir + '/' + fileName; + QFileInfo info(file); + + KConfigGroup cg(m_config, fileName); + const QDateTime ctime = QDateTime::fromTime_t(cg.readEntry("ctime", 0)); + const QDateTime mtime = QDateTime::fromTime_t(cg.readEntry("mtime", 0)); + if (!dirtyOnly || + (ctime != info.created()) || (mtime != info.lastModified())) { + result.append(file); + } + } + } + return result; +} + +bool KonfUpdate::checkFile(const QString &filename) +{ + m_currentFilename = filename; + int i = m_currentFilename.lastIndexOf('/'); + if (i != -1) { + m_currentFilename = m_currentFilename.mid(i + 1); + } + m_skip = true; + QFile file(filename); + if (!file.open(QIODevice::ReadOnly)) { + return false; + } + + QTextStream ts(&file); + ts.setCodec(QTextCodec::codecForName("ISO-8859-1")); + int lineCount = 0; + resetOptions(); + QString id; + while (!ts.atEnd()) { + QString line = ts.readLine().trimmed(); + lineCount++; + if (line.isEmpty() || (line[0] == '#')) { + continue; + } + if (line.startsWith("Id=")) { + id = m_currentFilename + ':' + line.mid(3); + } else if (line.startsWith("File=")) { + checkGotFile(line.mid(5), id); + } + } + + return true; +} + +void KonfUpdate::checkGotFile(const QString &_file, const QString &id) +{ + QString file; + int i = _file.indexOf(','); + if (i == -1) { + file = _file.trimmed(); + } else { + file = _file.mid(i + 1).trimmed(); + } + +// qDebug("File %s, id %s", file.toLatin1().constData(), id.toLatin1().constData()); + + KConfig cfg(file, KConfig::SimpleConfig); + KConfigGroup cg(&cfg, "$Version"); + QStringList ids = cg.readEntry("update_info", QStringList()); + if (ids.contains(id)) { + return; + } + ids.append(id); + cg.writeEntry("update_info", ids); +} + +/** + * Syntax: + * # Comment + * Id=id + * File=oldfile[,newfile] + * AllGroups + * Group=oldgroup[,newgroup] + * RemoveGroup=oldgroup + * Options=[copy,][overwrite,] + * Key=oldkey[,newkey] + * RemoveKey=ldkey + * AllKeys + * Keys= [Options](AllKeys|(Key|RemoveKey)*) + * ScriptArguments=arguments + * Script=scriptfile[,interpreter] + * + * Sequence: + * (Id,(File(Group,Keys)*)*)* + **/ +bool KonfUpdate::updateFile(const QString &filename) +{ + m_currentFilename = filename; + int i = m_currentFilename.lastIndexOf('/'); + if (i != -1) { + m_currentFilename = m_currentFilename.mid(i + 1); + } + m_skip = true; + QFile file(filename); + if (!file.open(QIODevice::ReadOnly)) { + return false; + } + + log() << "Checking update-file '" << filename << "' for new updates" << endl; + + QTextStream ts(&file); + ts.setCodec(QTextCodec::codecForName("ISO-8859-1")); + m_lineCount = 0; + resetOptions(); + while (!ts.atEnd()) { + m_line = ts.readLine().trimmed(); + m_lineCount++; + if (m_line.isEmpty() || (m_line[0] == '#')) { + continue; + } + if (m_line.startsWith(QLatin1String("Id="))) { + gotId(m_line.mid(3)); + } else if (m_skip) { + continue; + } else if (m_line.startsWith(QLatin1String("Options="))) { + gotOptions(m_line.mid(8)); + } else if (m_line.startsWith(QLatin1String("File="))) { + gotFile(m_line.mid(5)); + } else if (m_skipFile) { + continue; + } else if (m_line.startsWith(QLatin1String("Group="))) { + gotGroup(m_line.mid(6)); + } else if (m_line.startsWith(QLatin1String("RemoveGroup="))) { + gotRemoveGroup(m_line.mid(12)); + resetOptions(); + } else if (m_line.startsWith(QLatin1String("Script="))) { + gotScript(m_line.mid(7)); + resetOptions(); + } else if (m_line.startsWith(QLatin1String("ScriptArguments="))) { + gotScriptArguments(m_line.mid(16)); + } else if (m_line.startsWith(QLatin1String("Key="))) { + gotKey(m_line.mid(4)); + resetOptions(); + } else if (m_line.startsWith(QLatin1String("RemoveKey="))) { + gotRemoveKey(m_line.mid(10)); + resetOptions(); + } else if (m_line == "AllKeys") { + gotAllKeys(); + resetOptions(); + } else if (m_line == "AllGroups") { + gotAllGroups(); + resetOptions(); + } else { + logFileError() << "Parse error" << endl; + } + } + // Flush. + gotId(QString()); + + QFileInfo info(filename); + KConfigGroup cg(m_config, m_currentFilename); + cg.writeEntry("ctime", info.created().toTime_t()); + cg.writeEntry("mtime", info.lastModified().toTime_t()); + cg.sync(); + return true; +} + + + +void KonfUpdate::gotId(const QString &_id) +{ + if (!m_id.isEmpty() && !m_skip) { + KConfigGroup cg(m_config, m_currentFilename); + + QStringList ids = cg.readEntry("done", QStringList()); + if (!ids.contains(m_id)) { + ids.append(m_id); + cg.writeEntry("done", ids); + cg.sync(); + } + } + + // Flush pending changes + gotFile(QString()); + KConfigGroup cg(m_config, m_currentFilename); + + QStringList ids = cg.readEntry("done", QStringList()); + if (!_id.isEmpty()) { + if (ids.contains(_id)) { + //qDebug("Id '%s' was already in done-list", _id.toLatin1().constData()); + if (!m_bUseConfigInfo) { + m_skip = true; + return; + } + } + m_skip = false; + m_skipFile = false; + m_id = _id; + if (m_bUseConfigInfo) { + log() << m_currentFilename << ": Checking update '" << _id << "'" << endl; + } else { + log() << m_currentFilename << ": Found new update '" << _id << "'" << endl; + } + } +} + +void KonfUpdate::gotFile(const QString &_file) +{ + // Reset group + gotGroup(QString()); + + if (!m_oldFile.isEmpty()) { + // Close old file. + delete m_oldConfig1; + m_oldConfig1 = 0; + + KConfigGroup cg(m_oldConfig2, "$Version"); + QStringList ids = cg.readEntry("update_info", QStringList()); + QString cfg_id = m_currentFilename + ':' + m_id; + if (!ids.contains(cfg_id) && !m_skip) { + ids.append(cfg_id); + cg.writeEntry("update_info", ids); + } + cg.sync(); + delete m_oldConfig2; + m_oldConfig2 = 0; + + QString file = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + QLatin1Char('/') + m_oldFile; + QFileInfo info(file); + if (info.exists() && info.size() == 0) { + // Delete empty file. + QFile::remove(file); + } + + m_oldFile.clear(); + } + if (!m_newFile.isEmpty()) { + // Close new file. + KConfigGroup cg(m_newConfig, "$Version"); + QStringList ids = cg.readEntry("update_info", QStringList()); + QString cfg_id = m_currentFilename + ':' + m_id; + if (!ids.contains(cfg_id) && !m_skip) { + ids.append(cfg_id); + cg.writeEntry("update_info", ids); + } + m_newConfig->sync(); + delete m_newConfig; + m_newConfig = 0; + + m_newFile.clear(); + } + m_newConfig = 0; + + int i = _file.indexOf(','); + if (i == -1) { + m_oldFile = _file.trimmed(); + } else { + m_oldFile = _file.left(i).trimmed(); + m_newFile = _file.mid(i + 1).trimmed(); + if (m_oldFile == m_newFile) { + m_newFile.clear(); + } + } + + if (!m_oldFile.isEmpty()) { + m_oldConfig2 = new KConfig(m_oldFile, KConfig::NoGlobals); + QString cfg_id = m_currentFilename + ':' + m_id; + KConfigGroup cg(m_oldConfig2, "$Version"); + QStringList ids = cg.readEntry("update_info", QStringList()); + if (ids.contains(cfg_id)) { + m_skip = true; + m_newFile.clear(); + log() << m_currentFilename << ": Skipping update '" << m_id << "'" << endl; + } + + if (!m_newFile.isEmpty()) { + m_newConfig = new KConfig(m_newFile, KConfig::NoGlobals); + KConfigGroup cg(m_newConfig, "$Version"); + ids = cg.readEntry("update_info", QStringList()); + if (ids.contains(cfg_id)) { + m_skip = true; + log() << m_currentFilename << ": Skipping update '" << m_id << "'" << endl; + } + } else { + m_newConfig = m_oldConfig2; + } + + m_oldConfig1 = new KConfig(m_oldFile, KConfig::NoGlobals); + } else { + m_newFile.clear(); + } + m_newFileName = m_newFile; + if (m_newFileName.isEmpty()) { + m_newFileName = m_oldFile; + } + + m_skipFile = false; + if (!m_oldFile.isEmpty()) { // if File= is specified, it doesn't exist, is empty or contains only kconf_update's [$Version] group, skip + if (m_oldConfig1 != NULL + && (m_oldConfig1->groupList().isEmpty() + || (m_oldConfig1->groupList().count() == 1 && m_oldConfig1->groupList().first() == "$Version"))) { + log() << m_currentFilename << ": File '" << m_oldFile << "' does not exist or empty, skipping" << endl; + m_skipFile = true; + } + } +} + +QStringList KonfUpdate::parseGroupString(const QString &str) +{ + bool ok; + QString error; + QStringList lst = KConfigUtils::parseGroupString(str, &ok, &error); + if (!ok) { + logFileError() << error; + } + return lst; +} + +void KonfUpdate::gotGroup(const QString &_group) +{ + QString group = _group.trimmed(); + if (group.isEmpty()) { + m_oldGroup = m_newGroup = QStringList(); + return; + } + + QStringList tokens = group.split(','); + m_oldGroup = parseGroupString(tokens.at(0)); + if (tokens.count() == 1) { + m_newGroup = m_oldGroup; + } else { + m_newGroup = parseGroupString(tokens.at(1)); + } +} + +void KonfUpdate::gotRemoveGroup(const QString &_group) +{ + m_oldGroup = parseGroupString(_group); + + if (!m_oldConfig1) { + logFileError() << "RemoveGroup without previous File specification" << endl; + return; + } + + KConfigGroup cg = KConfigUtils::openGroup(m_oldConfig2, m_oldGroup); + if (!cg.exists()) { + return; + } + // Delete group. + cg.deleteGroup(); + log() << m_currentFilename << ": RemoveGroup removes group " << m_oldFile << ":" << m_oldGroup << endl; +} + + +void KonfUpdate::gotKey(const QString &_key) +{ + QString oldKey, newKey; + int i = _key.indexOf(','); + if (i == -1) { + oldKey = _key.trimmed(); + newKey = oldKey; + } else { + oldKey = _key.left(i).trimmed(); + newKey = _key.mid(i + 1).trimmed(); + } + + if (oldKey.isEmpty() || newKey.isEmpty()) { + logFileError() << "Key specifies invalid key" << endl; + return; + } + if (!m_oldConfig1) { + logFileError() << "Key without previous File specification" << endl; + return; + } + copyOrMoveKey(m_oldGroup, oldKey, m_newGroup, newKey); +} + +void KonfUpdate::copyOrMoveKey(const QStringList &srcGroupPath, const QString &srcKey, const QStringList &dstGroupPath, const QString &dstKey) +{ + KConfigGroup dstCg = KConfigUtils::openGroup(m_newConfig, dstGroupPath); + if (!m_bOverwrite && dstCg.hasKey(dstKey)) { + log() << m_currentFilename << ": Skipping " << m_newFileName << ":" << dstCg.name() << ":" << dstKey << ", already exists." << endl; + return; + } + + KConfigGroup srcCg = KConfigUtils::openGroup(m_oldConfig1, srcGroupPath); + if (!srcCg.hasKey(srcKey)) + return; + QString value = srcCg.readEntry(srcKey, QString()); + log() << m_currentFilename << ": Updating " << m_newFileName << ":" << dstCg.name() << ":" << dstKey << " to '" << value << "'" << endl; + dstCg.writeEntry(dstKey, value); + + if (m_bCopy) { + return; // Done. + } + + // Delete old entry + if (m_oldConfig2 == m_newConfig + && srcGroupPath == dstGroupPath + && srcKey == dstKey) { + return; // Don't delete! + } + KConfigGroup srcCg2 = KConfigUtils::openGroup(m_oldConfig2, srcGroupPath); + srcCg2.deleteEntry(srcKey); + log() << m_currentFilename << ": Removing " << m_oldFile << ":" << srcCg2.name() << ":" << srcKey << ", moved." << endl; +} + +void KonfUpdate::copyOrMoveGroup(const QStringList &srcGroupPath, const QStringList &dstGroupPath) +{ + KConfigGroup cg = KConfigUtils::openGroup(m_oldConfig1, srcGroupPath); + + // Keys + Q_FOREACH(const QString &key, cg.keyList()) { + copyOrMoveKey(srcGroupPath, key, dstGroupPath, key); + } + + // Subgroups + Q_FOREACH(const QString &group, cg.groupList()) { + QStringList groupPath = QStringList() << group; + copyOrMoveGroup(srcGroupPath + groupPath, dstGroupPath + groupPath); + } +} + +void KonfUpdate::gotRemoveKey(const QString &_key) +{ + QString key = _key.trimmed(); + + if (key.isEmpty()) { + logFileError() << "RemoveKey specifies invalid key" << endl; + return; + } + + if (!m_oldConfig1) { + logFileError() << "Key without previous File specification" << endl; + return; + } + + KConfigGroup cg1 = KConfigUtils::openGroup(m_oldConfig1, m_oldGroup); + if (!cg1.hasKey(key)) { + return; + } + log() << m_currentFilename << ": RemoveKey removes " << m_oldFile << ":" << m_oldGroup << ":" << key << endl; + + // Delete old entry + KConfigGroup cg2 = KConfigUtils::openGroup(m_oldConfig2, m_oldGroup); + cg2.deleteEntry(key); + /*if (m_oldConfig2->deleteGroup(m_oldGroup, KConfig::Normal)) { // Delete group if empty. + log() << m_currentFilename << ": Removing empty group " << m_oldFile << ":" << m_oldGroup << endl; + } (this should be automatic)*/ +} + +void KonfUpdate::gotAllKeys() +{ + if (!m_oldConfig1) { + logFileError() << "AllKeys without previous File specification" << endl; + return; + } + + copyOrMoveGroup(m_oldGroup, m_newGroup); +} + +void KonfUpdate::gotAllGroups() +{ + if (!m_oldConfig1) { + logFileError() << "AllGroups without previous File specification" << endl; + return; + } + + const QStringList allGroups = m_oldConfig1->groupList(); + for (QStringList::ConstIterator it = allGroups.begin(); + it != allGroups.end(); ++it) { + m_oldGroup = QStringList() << *it; + m_newGroup = m_oldGroup; + gotAllKeys(); + } +} + +void KonfUpdate::gotOptions(const QString &_options) +{ + const QStringList options = _options.split(','); + for (QStringList::ConstIterator it = options.begin(); + it != options.end(); + ++it) { + if ((*it).toLower().trimmed() == "copy") { + m_bCopy = true; + } + + if ((*it).toLower().trimmed() == "overwrite") { + m_bOverwrite = true; + } + } +} + +void KonfUpdate::copyGroup(const KConfigBase *cfg1, const QString &group1, + KConfigBase *cfg2, const QString &group2) +{ + KConfigGroup cg1(cfg1, group1); + KConfigGroup cg2(cfg2, group2); + copyGroup(cg1, cg2); +} + +void KonfUpdate::copyGroup(const KConfigGroup &cg1, KConfigGroup &cg2) +{ + // Copy keys + QMap<QString, QString> list = cg1.entryMap(); + for (QMap<QString, QString>::ConstIterator it = list.constBegin(); + it != list.constEnd(); ++it) { + if (m_bOverwrite || !cg2.hasKey(it.key())) { + cg2.writeEntry(it.key(), it.value()); + } + } + + // Copy subgroups + Q_FOREACH(const QString &group, cg1.groupList()) { + copyGroup(&cg1, group, &cg2, group); + } +} + +void KonfUpdate::gotScriptArguments(const QString &_arguments) +{ + m_arguments = _arguments; +} + +void KonfUpdate::gotScript(const QString &_script) +{ + QString script, interpreter; + int i = _script.indexOf(','); + if (i == -1) { + script = _script.trimmed(); + } else { + script = _script.left(i).trimmed(); + interpreter = _script.mid(i + 1).trimmed(); + } + + + if (script.isEmpty()) { + logFileError() << "Script fails to specify filename"; + m_skip = true; + return; + } + + + + QString path = QStandardPaths::locate(QStandardPaths::GenericDataLocation, "kconf_update/" + script); + if (path.isEmpty()) { + if (interpreter.isEmpty()) { + // KDE4: this was looking into locate("lib", "kconf_update_bin/"). But QStandardPaths doesn't know the lib dirs. + // Let's look in the install prefix and in PATH. + path = CMAKE_INSTALL_PREFIX "/" LIB_INSTALL_DIR "/kconf_update_bin/" + script; + if (QFile::exists(path)) + path = QStandardPaths::findExecutable(script); + } + + if (path.isEmpty()) { + logFileError() << "Script '" << script << "' not found" << endl; + m_skip = true; + return; + } + } + + if (!m_arguments.isNull()) { + log() << m_currentFilename << ": Running script '" << script << "' with arguments '" << m_arguments << "'" << endl; + } else { + log() << m_currentFilename << ": Running script '" << script << "'" << endl; + } + + QString cmd; + if (interpreter.isEmpty()) { + cmd = path; + } else { + cmd = interpreter + ' ' + path; + } + + if (!m_arguments.isNull()) { + cmd += ' '; + cmd += m_arguments; + } + + QTemporaryFile scriptIn; + scriptIn.open(); + QTemporaryFile scriptOut; + scriptOut.open(); + QTemporaryFile scriptErr; + scriptErr.open(); + + int result; + if (m_oldConfig1) { + if (m_debug) { + scriptIn.setAutoRemove(false); + log() << "Script input stored in " << scriptIn.fileName() << endl; + } + KConfig cfg(scriptIn.fileName(), KConfig::SimpleConfig); + + if (m_oldGroup.isEmpty()) { + // Write all entries to tmpFile; + const QStringList grpList = m_oldConfig1->groupList(); + for (QStringList::ConstIterator it = grpList.begin(); + it != grpList.end(); + ++it) { + copyGroup(m_oldConfig1, *it, &cfg, *it); + } + } else { + KConfigGroup cg1 = KConfigUtils::openGroup(m_oldConfig1, m_oldGroup); + KConfigGroup cg2(&cfg, QString()); + copyGroup(cg1, cg2); + } + cfg.sync(); +#ifndef _WIN32_WCE + result = system(QFile::encodeName(QString("%1 < %2 > %3 2> %4").arg(cmd, scriptIn.fileName(), scriptOut.fileName(), scriptErr.fileName())).constData()); +#else + QString path_ = QDir::convertSeparators ( QFileInfo ( cmd ).absoluteFilePath() ); + QString file_ = QFileInfo ( cmd ).fileName(); + SHELLEXECUTEINFO execInfo; + memset ( &execInfo,0,sizeof ( execInfo ) ); + execInfo.cbSize = sizeof ( execInfo ); + execInfo.fMask = SEE_MASK_FLAG_NO_UI; + execInfo.lpVerb = L"open"; + execInfo.lpFile = (LPCWSTR) path_.utf16(); + execInfo.lpDirectory = (LPCWSTR) file_.utf16(); + execInfo.lpParameters = (LPCWSTR) QString(" < %1 > %2 2> %3").arg( scriptIn.fileName(), scriptOut.fileName(), scriptErr.fileName()).utf16(); + result = ShellExecuteEx ( &execInfo ); + if (result != 0) + { + result = 0; + } + else + { + result = -1; + } +#endif + } else { + // No config file +#ifndef _WIN32_WCE + result = system(QFile::encodeName(QString("%1 2> %2").arg(cmd, scriptErr.fileName())).constData()); +#else + QString path_ = QDir::convertSeparators ( QFileInfo ( cmd ).absoluteFilePath() ); + QString file_ = QFileInfo ( cmd ).fileName(); + SHELLEXECUTEINFO execInfo; + memset ( &execInfo,0,sizeof ( execInfo ) ); + execInfo.cbSize = sizeof ( execInfo ); + execInfo.fMask = SEE_MASK_FLAG_NO_UI; + execInfo.lpVerb = L"open"; + execInfo.lpFile = (LPCWSTR) path_.utf16(); + execInfo.lpDirectory = (LPCWSTR) file_.utf16(); + execInfo.lpParameters = (LPCWSTR) QString(" 2> %1").arg( scriptErr.fileName()).utf16(); + result = ShellExecuteEx ( &execInfo ); + if (result != 0) + { + result = 0; + } + else + { + result = -1; + } +#endif + } + + // Copy script stderr to log file + { + QFile output(scriptErr.fileName()); + if (output.open(QIODevice::ReadOnly)) { + QTextStream ts(&output); + ts.setCodec(QTextCodec::codecForName("UTF-8")); + while (!ts.atEnd()) { + QString line = ts.readLine(); + log() << "[Script] " << line << endl; + } + } + } + + if (result) { + log() << m_currentFilename << ": !! An error occurred while running '" << cmd << "'" << endl; + return; + } + + if (!m_oldConfig1) { + return; // Nothing to merge + } + + if (m_debug) { + scriptOut.setAutoRemove(false); + log() << "Script output stored in " << scriptOut.fileName() << endl; + } + + // Deleting old entries + { + QStringList group = m_oldGroup; + QFile output(scriptOut.fileName()); + if (output.open(QIODevice::ReadOnly)) { + QTextStream ts(&output); + ts.setCodec(QTextCodec::codecForName("UTF-8")); + while (!ts.atEnd()) { + QString line = ts.readLine(); + if (line.startsWith('[')) { + group = parseGroupString(line); + } else if (line.startsWith(QLatin1String("# DELETE "))) { + QString key = line.mid(9); + if (key[0] == '[') { + int j = key.lastIndexOf(']') + 1; + if (j > 0) { + group = parseGroupString(key.left(j)); + key = key.mid(j); + } + } + KConfigGroup cg = KConfigUtils::openGroup(m_oldConfig2, group); + cg.deleteEntry(key); + log() << m_currentFilename << ": Script removes " << m_oldFile << ":" << group << ":" << key << endl; + /*if (m_oldConfig2->deleteGroup(group, KConfig::Normal)) { // Delete group if empty. + log() << m_currentFilename << ": Removing empty group " << m_oldFile << ":" << group << endl; + } (this should be automatic)*/ + } else if (line.startsWith(QLatin1String("# DELETEGROUP"))) { + QString str = line.mid(13).trimmed(); + if (!str.isEmpty()) { + group = parseGroupString(str); + } + KConfigGroup cg = KConfigUtils::openGroup(m_oldConfig2, group); + cg.deleteGroup(); + log() << m_currentFilename << ": Script removes group " << m_oldFile << ":" << group << endl; + } + } + } + } + + // Merging in new entries. + KConfig scriptOutConfig(scriptOut.fileName(), KConfig::NoGlobals); + if (m_newGroup.isEmpty()) { + // Copy "default" keys as members of "default" keys + copyGroup(&scriptOutConfig, QString(), m_newConfig, QString()); + } else { + // Copy default keys as members of m_newGroup + KConfigGroup srcCg = KConfigUtils::openGroup(&scriptOutConfig, QStringList()); + KConfigGroup dstCg = KConfigUtils::openGroup(m_newConfig, m_newGroup); + copyGroup(srcCg, dstCg); + } + Q_FOREACH(const QString &group, scriptOutConfig.groupList()) { + copyGroup(&scriptOutConfig, group, m_newConfig, group); + } +} + +void KonfUpdate::resetOptions() +{ + m_bCopy = false; + m_bOverwrite = false; + m_arguments.clear(); +} + + +int main(int argc, char **argv) +{ + QCoreApplication app(argc, argv); + app.setApplicationVersion("1.1"); + + QCommandLineParser parser; + parser.addVersionOption(); + parser.setApplicationDescription(QCoreApplication::translate("main", "KDE Tool for updating user configuration files")); + parser.addHelpOption(); + parser.addOption(QCommandLineOption(QStringList() << "debug", QCoreApplication::translate("main", "Keep output results from scripts"))); + parser.addOption(QCommandLineOption(QStringList() << "check", QCoreApplication::translate("main", "Check whether config file itself requires updating"), "update-file")); + //parser.addOption(QCommandLineOption(QStringList() << "+[file]", QCoreApplication::translate("main", "File to read update instructions from"))); + + // TODO aboutData.addAuthor(ki18n("Waldo Bastian"), KLocalizedString(), "bastian@kde.org"); + + parser.process(app); + KonfUpdate konfUpdate(&parser); + + return 0; +} diff --git a/tier1/kconfig/src/kconf_update/kconfigutils.cpp b/tier1/kconfig/src/kconf_update/kconfigutils.cpp new file mode 100644 index 00000000..f2663e13 --- /dev/null +++ b/tier1/kconfig/src/kconf_update/kconfigutils.cpp @@ -0,0 +1,127 @@ +/* This file is part of the KDE libraries + Copyright 2010 Canonical Ltd + Author: Aurélien Gâteau <aurelien.gateau@canonical.com> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License (LGPL) as published by the Free Software Foundation; + either version 2 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ +#include "kconfigutils.h" + +// KDE +#include <kconfig.h> +#include <kconfiggroup.h> + +namespace KConfigUtils +{ + +bool hasGroup(KConfig *config, const QStringList &lst) +{ + KConfigGroup group = openGroup(config, lst); + return group.exists(); +} + +KConfigGroup openGroup(KConfig *config, const QStringList &_lst) +{ + if (_lst.isEmpty()) { + return KConfigGroup(config, QString()); + } + + QStringList lst = _lst; + + KConfigGroup cg; + for (cg = KConfigGroup(config, lst.takeFirst()); !lst.isEmpty(); cg = KConfigGroup(&cg, lst.takeFirst())) {} + return cg; +} + +QStringList parseGroupString(const QString &_str, bool *ok, QString *error) +{ + QString str = unescapeString(_str.trimmed(), ok, error); + if (!ok) { + return QStringList(); + } + + *ok = true; + if (str[0] != '[') { + // Simplified notation, no '[' + return QStringList() << str; + } + + if (!str.endsWith(']')) { + *ok = false; + *error = QString("Missing closing ']' in %1").arg(_str); + return QStringList(); + } + // trim outer brackets + str.chop(1); + str.remove(0, 1); + + return str.split("]["); +} + +QString unescapeString(const QString &src, bool *ok, QString *error) +{ + QString dst; + int length = src.length(); + for (int pos = 0; pos < length; ++pos) { + QChar ch = src.at(pos); + if (ch != '\\') { + dst += ch; + } else { + ++pos; + if (pos == length) { + *ok = false; + *error = QString("Unfinished escape sequence in %1").arg(src); + return QString(); + } + ch = src.at(pos); + if (ch == 's') { + dst += ' '; + } else if (ch == 't') { + dst += '\t'; + } else if (ch == 'n') { + dst += '\n'; + } else if (ch == 'r') { + dst += '\r'; + } else if (ch == '\\') { + dst += '\\'; + } else if (ch == 'x') { + if (pos + 2 < length) { + char value = src.mid(pos + 1, 2).toInt(ok, 16); + if (*ok) { + dst += QChar::fromLatin1(value); + pos += 2; + } else { + *error = QString("Invalid hex escape sequence at column %1 in %2").arg(pos).arg(src); + return QString(); + } + } else { + *ok = false; + *error = QString("Unfinished hex escape sequence at column %1 in %2").arg(pos).arg(src); + return QString(); + } + } else { + *ok = false; + *error = QString("Invalid escape sequence at column %1 in %2").arg(pos).arg(src); + return QString(); + } + } + } + + *ok = true; + return dst; +} + +} // namespace diff --git a/tier1/kconfig/src/kconf_update/kconfigutils.h b/tier1/kconfig/src/kconf_update/kconfigutils.h new file mode 100644 index 00000000..606495e6 --- /dev/null +++ b/tier1/kconfig/src/kconf_update/kconfigutils.h @@ -0,0 +1,43 @@ +/* This file is part of the KDE libraries + Copyright 2010 Canonical Ltd + Author: Aurélien Gâteau <aurelien.gateau@canonical.com> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License (LGPL) as published by the Free Software Foundation; + either version 2 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ +#ifndef KCONFIGUTILS_H +#define KCONFIGUTILS_H + +class QString; +class QStringList; + +class KConfig; +class KConfigGroup; + +namespace KConfigUtils +{ + +bool hasGroup(KConfig *, const QStringList &); + +KConfigGroup openGroup(KConfig *, const QStringList &); + +QStringList parseGroupString(const QString &str, bool *ok, QString *error); + +QString unescapeString(const QString &str, bool *ok, QString *error); + +} // namespace + +#endif /* KCONFIGUTILS_H */ diff --git a/tier1/kconfig/src/kconfig_compiler/CMakeLists.txt b/tier1/kconfig/src/kconfig_compiler/CMakeLists.txt new file mode 100644 index 00000000..31726df1 --- /dev/null +++ b/tier1/kconfig/src/kconfig_compiler/CMakeLists.txt @@ -0,0 +1,15 @@ + + +set(kconfig_compiler_SRCS kconfig_compiler.cpp) + + +add_executable(kconfig_compiler ${kconfig_compiler_SRCS}) +add_executable(KF5::kconfig_compiler ALIAS kconfig_compiler) + +find_package(Qt5Xml 5.2.0 REQUIRED NO_MODULE) + +target_link_libraries(kconfig_compiler Qt5::Xml) + +# "export" this target too so we can use the LOCATION property of the imported target in +# FindKDE4Internal.cmake to get the full path to the installed executable instead of using FIND_PROGRAM(), Alex +install(TARGETS kconfig_compiler EXPORT KF5ConfigTargets ${INSTALL_TARGETS_DEFAULT_ARGS} ) diff --git a/tier1/kconfig/src/kconfig_compiler/README.dox b/tier1/kconfig/src/kconfig_compiler/README.dox new file mode 100644 index 00000000..b9606f1d --- /dev/null +++ b/tier1/kconfig/src/kconfig_compiler/README.dox @@ -0,0 +1,446 @@ +/** +\page kconfig_compiler The KDE Configuration Compiler + +kconfig_compiler generates C++ source code from an XML file containing +information about configuration options (.kcfg) and a file that provides +the code generation options (.kcfgc) The generated class is based on +KConfigSkeleton and provides an API for the application to access its +configuration data. + +The generated C++ source code is output to a .h and a .cpp file, whose base +name is the same as that of the .kcfgc file. + +<h2>XML description of the configuration options</h2> + +The structure of the .kcfg file is described by its DTD kcfg.xsd. + +The \<kcfgfile\> tag may contain either the "name" attribute, which should be the name +of the configuration file described, or the "arg" attribute, which, if set to +"true", will allow you to pass the KSharedConfig::Ptr object to use. + +If neither "name" nor "arg" is set, the default configuration file +("\<appname\>rc") will be used. + +The \<include\> tags are optional and may contain C++ header files that +are needed to compile the code needed to compute default values. To generate +a \#include "..." statement instead of \#include \<...\>, enclose the header +file name in double quotes (e.g. \<include\>"header.h"\</include\>). + +The remaining entries in the XML file are grouped by the tag \<group\> +which describes the corresponding group in the configuration file. + +The individual entries must have at least a name or a key. The key is used +as the key in the config file, while the name is used to create accessor and +modifier functions. If \<key\> is given, but not \<name\>, the name is +constructed by removing all spaces from \<key\>. If \<name\> is given, but +not \<key\>, the key is the same as \<name\>. + +An entry must also have a type. The list of allowable types is +specified in the DTD and loosely follows the list of types supported +by the QVariant with exception of the clearly binary types +(e.g. Pixmap, Image...) which are not supported. Besides those basic +types the following special types are supported: + +- Path This is a string that is specially treated as a file-path. + In particular paths in the home directory are prefixed with $HOME in + when being stored in the configuration file. + +- Enum This indicates an enumeration. The possible enum values and optional + enum name should be provided via the \<choices\> tag. Enum values are + accessed as integers by the application but stored as strings in the + configuration file. This makes it possible to add more values at a later + date without breaking compatibility. + +- IntList This indicates a list of integers. This information is provided + to the application as QValueList<int>. Useful for storing QSplitter + geometries. + +An entry can optionally have a default value which is used as default when +the value isn't specified in any config file. Default values are interpreted +as literal constant values. If a default value needs to be computed +or if it needs to be obtained from a function call, the \<default\> tag +should contain the code="true" attribute. The contents of the \<default\> +tag is then considered to be a C++ expression. Note that in this case you +might have to add an \<include\> tag as described above, or a +SourceIncludeFiles entry in the .kcfgc file as described below, so that the +code which computes the default value can be compiled. + +Additional code for computing default values can be provided outside any +entry definition via the \<code\> tag. The contents of the \<code\> tag is +inserted as-is. A typical use for this is to compute a common default value +which can then be referenced by multiple entries that follow. + +<h2>Code generation options</h2> + +The options for generating the C++ sources are read from the file with the +extension .kcfgc. To generate a class add the corresponding kcfgc file to the +SOURCES line in the Makefile.am. + +The following options are read from the kcfgc file: + +<table> +<tr> + <td><b><i>Name</i></b></td> + <td><b><i>Type</i></b></td> + <td><b><i>Default</i></b></td> + <td><b><i>Description</i></b></td> +</tr> +<tr> + <td><b>File</b></td> + <td>string</td> + <td>programname.kcfg</td> + <td>Name of kcfg file containing the options the class is generated for</td> +</tr> +<tr> + <td><b>NameSpace</b></td> + <td>string</td> + <td>-</td> + <td>Optional namespace for generated class</td> +</tr> +<tr> + <td><b>ClassName</b></td> + <td>string</td> + <td>-</td> + <td>Name of generated class (required)</td> +</tr> +<tr> + <td><b>Inherits</b></td> + <td>string</td> + <td>KConfigSkeleton</td> + <td>Class the generated class inherits from. This class must inherit + KConfigSkeleton.</td> +</tr> +<tr> + <td><b>Visibility</b></td> + <td>string</td> + <td>-</td> + <td>Inserts visibility directive (for example KDE_EXPORT) between "class" keyword and class + name in header file</td> +</tr> +<tr> + <td><b>Singleton</b></td> + <td>bool</td> + <td>false</td> + <td>Generated class is a singleton.</td> +</tr> +<tr> + <td><b>CustomAdditions</b></td> + <td>bool</td> + <td>-</td> + <td></td> +</tr> +<tr> + <td><b>MemberVariables</b></td> + <td>string: public|protected|private|dpointer</td> + <td>private</td> + <td>C++ access modifier used for member variables holding the configuration + values</td> +</tr> +<tr> + <td><b>IncludeFiles</b></td> + <td>comma separated list of strings</td> + <td>-</td> + <td>Names of files to be included in the header of the generated class. Enclose a + file name in (escaped) double quotes to generate \#include "..." instead of + \#include \<...\>.</td> +</tr> +<tr> + <td><b>SourceIncludeFiles</b></td> + <td>comma separated list of strings</td> + <td>-</td> + <td>Names of files to be included in the source file of the generated class. Enclose + a file name in (escaped) double quotes to generate \#include "..." instead of + \#include \<...\>.</td> +</tr> +<tr> + <td><b>Mutators</b></td> + <td>true, false or a comma separated list of options</td> + <td>false</td> + <td>If true, mutator functions for all configuration options are generated. + If false, no mutator functions are generated. If a list is provided, + mutator functions are generated for the options that are listed.</td> +</tr> +<tr> + <td><b>DefaultValueGetters</b></td> + <td>true, false or a comma separated list of options</td> + <td>false</td> + <td>If true, functions to return the default value of all configuration options + are generated. If false, no default value functions are generated. If a list + is provided, default value functions are generated for the options that are listed.</td> +</tr> +<tr> + <td><b>ItemAccessors</b></td> + <td>bool</td> + <td>false</td> + <td>Generate accessor functions for the KConfigSkeletonItem objects + corresponding to the configuration options. If <b>SetUserTexts</b> is set, + <b>ItemAccessors</b> also has to be set.</td> +</tr> +<tr> + <td><b>SetUserTexts</b></td> + <td>bool</td> + <td>false</td> + <td>Set the label and whatthis texts of the items from the kcfg file.If + <b>SetUserTexts</b> is set, <b>ItemAccessors</b> also has to be set.</td> +</tr> +<tr> + <td><b>GlobalEnums</b></td> + <td>bool</td> + <td>false</td> + <td>If set to true all choices of Enum items will be created in the global + scope of the generated class. If set to false, each Enum item whose enum is not + explicitly named will get its own namespace for its choices.</td> +</tr> +<tr> + <td><b>UseEnumTypes</b></td> + <td>bool</td> + <td>false</td> + <td>If set to true, all Enum items whose enums are named will use enum types for + the return value of accessor functions and for the parameter of mutator + functions. This eliminates the need to cast accessor return values to the enum + type if you want to use the enum type in your own code. If set to false, + accessor return values and mutator parameters will be of type int.</td> +</tr> +<tr> + <td><b>ForceStringFilename</b></td> + <td>bool</td> + <td>false</td> + <td>If set to true, forces the first parameter of the generated class to be a QString when using an argument for the filename. This is useful to specify at runtime the filename of the configuration class.</td> +</table> + + +<h2>Advanced options</h2> + +There are several possibilities to parameterize entries. + +- Parameterized entries + +An entry can be parameterized using a fixed range parameter specified with +the \<parameter\> tag. Such parameter can either be an Enum or an int. An Enum +parameter should specify the possible enumeration values with the \<choices\> +tag. An int parameter should specify its maximum value. Its minimum value +is always 0. + +A parameterized entry is expanded to a number of entries, one for each +value in the parameter range. The name and key should contain a reference +to the parameter in the form of $(parameter-name). When expanding the entries +the $(parameter-name) part is replaced with the value of the parameter. +In the case of an Enum parameter it is replaced with the name of the +enumuration value. In the case of an int parameter it is replaced with +the numeric value of the parameter. + +Parameterized entries all share the same default value unless different +default values have been specified for specific parameter values. +This can be done with the param= attribute of the \<default\>. When a +param attribute is specified the default value only applies to that +particular parameter value. + +Example 1: +\verbatim + <entry name="Color$(ColorIndex)" type="Color" key="color_$(ColorIndex)"> + <parameter name="ColorIndex" type="Int" max="3"/> + <default param="0">#ff0000</default> + <default param="1">#00ff00</default> + <default param="2">#0000ff</default> + <default param="3">#ffff00</default> + </entry> +\endverbatim + +The above describes 4 color configuration entries with the following defaults: + +\verbatim +color_0=#ff0000 +color_1=#00ff00 +color_2=#0000ff +color_3=#ffff00 +\endverbatim + +The configuration options will be accessible to the application via +a QColor color(int ColorIndex) and a +void setColor(int ColorIndex, const QColor &v) function. + +Example 2: +\verbatim + <entry name="Sound$(SoundEvent)" type="String" key="sound_$(SoundEvent)"> + <parameter name="SoundEvent" type="Enum"> + <values> + <value>Explosion</value> + <value>Crash</value> + <value>Missile</value> + </values> + </parameter> + <default param="Explosion">boom.wav</default> + <default param="Crash">crash.wav</default> + <default param="Missile">missile.wav</default> + </entry> +\endverbatim + +The above describes 3 string configuration entries with the following defaults: + +sound_Explosion=boom.wav +sound_Crash=crash.wav +sound_Missile=missile.wav + +The configuration options will be accessible to the application via +a QString sound(int SoundEvent) and a +void setSound(int SoundEvent, const QString &v) function. + +- Parameterized groups + +A group name can be parametrized using a parameter given to the KConfigSkeleton +instance (which means this feature cannot be used with singleton classes). + +Example 1: +\verbatim + <kcfgfile name="testrc"> + <parameter name="groupname"/> + </kcfgfile> + <group name="$(groupname)"> + <entry key="Text" type="string"> + </entry> + </group> +\endverbatim + +In this case passing "Group2" as the 'groupname' parameter to the generated class +will make it use group "Group2" for the entry "Text". + +- Enums + +By default, if <b>GlobalEnums</b> is set to false, a separate named enum will be generated +for each Enum entry. Since each enum is defined in a little enclosing class of its own, +this allows the same Enum value names to be used in different enums. For example, the +.kcfg entry + +\verbatim +<entry name="KeepData" type="Enum"> + <choices> + <choice name="Do"> + <choice name="Dont"> + </choices> +</entry> +\endverbatim + +will generate this public class containing the enum definition, inside the generated class: + +\verbatim + class EnumKeepData + { + public: + enum type { Do, Dont, COUNT }; + }; +\endverbatim + +Alternatively, if <b>GlobalEnums</b> is set to true, all Enum items are defined as +unnamed enums in the global scope of the generated class. In this case, all Enum values +must have different names to avoid clashes. However, you can use a 'prefix' argument +in \<choices\> to prevent duplicate enum member names clashing. Using this, the Enum value +names are prefixed in code with the string you specify. For example, if <b>GlobalEnums</b> +is set to true, the .kcfg entry + +\verbatim +<entry name="KeepData" type="Enum"> + <choices prefix="Keep_"> + <choice name="Do"> + <choice name="Dont"> + </choices> +</entry> +\endverbatim + +will generate config file entries of "KeepData=Do" and "KeepData=Dont", but the enum +will be declared + +\verbatim + enum { Keep_Do, Keep_Dont }; +\endverbatim + +It is possible to specify your own name for a generated enum, by including a +'name' parameter in \<choices\>. Just like unnamed enums, this enum will be defined in +the global scope of the generated class (without any enclosing class of its own). +Therefore the names of Enum values must be unique across both unnamed enums (if +<b>GlobalEnums</b> is set to true) and all specifically named enums. + +An example of a specifically named enum: + +\verbatim +<entry name="KeepData" type="Enum"> + <choices name="Types"> + <choice name="Do"> + <choice name="Dont"> + </choices> +</entry> +\endverbatim + +which results in the following enum declaration, inside the generated class: + +\verbatim + enum Types { Do, Dont }; +\endverbatim + +It is also possible to specify the use of enums external to the generated class, by +including the string "::" in the enum name - just ensure that it is sufficiently +qualified to be unambiguous in use. To specify use of an unnamed enum, append a +trailing "::". For example, to use the enum 'myEnum' defined in class ClassA, use +either of + +\verbatim +<choices name="ClassA::myEnum"> +<choices name="::ClassA::myEnum"> +\endverbatim + +To specify an unnamed enum in namespace ProgSpace, use + +\verbatim +<choices name="ProgSpace::"> +\endverbatim + +To specify a top-level unnamed enum, use + +\verbatim +<choices name="::"> +\endverbatim + +To specify the top-level enum 'anotherEnum', use + +\verbatim +<choices name="::anotherEnum"> +\endverbatim + + +- Signal support. + +An entry can emit a signal when it gets changed. First of all, you must +define a list of signals for the configuration class. The signal's name may be +any legal identifier you wish. The \<argument\> tag allows you to specify arguments +for the emitted signal. It supports all types as defined in +the KConfigXT DTD. The argument value must specify the name, without spaces, of one +of the entries defined in the .kcfg file. +A signal definition can also contain a \<label\> tag which will be +the documentation line in the generated file. + +\verbatim +<signal name="emoticonSettingsChanged" /> + +<signal name="styleChanged"> + <label>Tell when a complete style change.</label> + <argument type="String">stylePath</argument> + <argument type="String">StyleCSSVariant</argument> +</signal> +\endverbatim + +After defining the signals, you must tell which signal to emit for the entry. +A signal can be emitted by multiple entries. Also, you don't need to specify the arguments +for a signal, the signal name will suffice. + +\verbatim +<entry key="stylePath" type="String"> + <label>Absolute path to a directory containing a Adium/Kopete chat window style.</label> + <emit signal="styleChanged" /> +</entry> +\endverbatim + +You can also use the generic configChanged() signal from KConfigSkeleton to notify your application +about configuration changes. + +If you have questions or comments please contact Cornelius Schumacher +<schumacher@kde.org> or Waldo Bastian <bastian@kde.org> +*/ diff --git a/tier1/kconfig/src/kconfig_compiler/TODO b/tier1/kconfig/src/kconfig_compiler/TODO new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/tier1/kconfig/src/kconfig_compiler/TODO diff --git a/tier1/kconfig/src/kconfig_compiler/checkkcfg.pl b/tier1/kconfig/src/kconfig_compiler/checkkcfg.pl new file mode 100755 index 00000000..2eddbeee --- /dev/null +++ b/tier1/kconfig/src/kconfig_compiler/checkkcfg.pl @@ -0,0 +1,83 @@ +#!/usr/bin/perl + +if ( @ARGV != 1 ) { + print STDERR "Missing arg: filename\n"; + exit 1; +} + +$file = $ARGV[0]; + +$file =~ /^(.*)\.[^\.]*$/; +$filebase = $1; + +$file_h = "$filebase.h"; +$file_cpp = "$filebase.cpp"; + +$kcfgc = $file . "c"; + +$cmd = "./kconfig_compiler $file $kcfgc"; + +#print "CMD $cmd\n"; + +if ( system( $cmd ) != 0 ) { + print STDERR "Unable to run kconfig_compiler\n"; + exit 1; +} + +checkfile( $file_h ); +checkfile( $file_cpp ); + +exit 0; + +sub checkfile() +{ + my $file = shift; + + $file =~ /\/([^\/]*)$/; + my $filename = $1; + + print "Checking '$filename':\n"; + + my @ref; + if ( !open( REF, "$file.ref" ) ) { + print STDERR "Unable to open $file.ref\n"; + exit 1; + } + while( <REF> ) { + push @ref, $_; + } + close REF; + + if ( !open( READ, $filename ) ) { + print STDERR "Unable to open $filename\n"; + exit 1; + } + + $error = 0; + $i = 0; + $line = 1; + while( <READ> ) { + $out = $_; + $ref = @ref[$i++]; + + if ( $out ne $ref ) { + $error++; + print " Line $line: Expected : $ref"; + print " Line $line: Compiler output : $out"; + } + + $line++; + } + + close READ; + + if ( $error > 0 ) { + print "\n FAILED: $error errors found.\n"; + if ( $error > 5 ) { + system( "diff -u $file.ref $filename" ); + } + exit 1; + } else { + print " OK\n"; + } +} diff --git a/tier1/kconfig/src/kconfig_compiler/kcfg.xsd b/tier1/kconfig/src/kconfig_compiler/kcfg.xsd new file mode 100644 index 00000000..4926fb19 --- /dev/null +++ b/tier1/kconfig/src/kconfig_compiler/kcfg.xsd @@ -0,0 +1,234 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- kcfg XSD v1.0 --> +<xsd:schema + xmlns:xsd="http://www.w3.org/2001/XMLSchema" + xmlns="http://www.kde.org/standards/kcfg/1.0" + xmlns:kcfg="http://www.kde.org/standards/kcfg/1.0" + targetNamespace="http://www.kde.org/standards/kcfg/1.0" + version="1.0" + elementFormDefault="qualified" > + + <xsd:annotation> + <xsd:documentation> + + Copyright (c) 2003 Cornelius Schumacher <schumacher@kde.org> + Copyright (c) 2003 Waldo Bastian <bastian@kde.org> + Copyright (c) 2003 Zack Rusin <zack@kde.org> + Copyright (c) 2004 Frans Englich <frans.englich@telia.com> + Copyright (c) 2006 Michaël Larouche <michael.larouche@kdemail.net> + + Permission to use, copy, modify and distribute this DTD + and its accompanying documentation for any purpose and without fee + is hereby granted in perpetuity, provided that the above copyright + notice and this paragraph appear in all copies. The copyright + holders make no representation about the suitability of the DTD for + any purpose. It is provided "as is" without expressed or implied + warranty. + + </xsd:documentation> + </xsd:annotation> + <xsd:annotation> + <xsd:documentation> + + A Schema for KDE's KConfigXT XML format. It is similar to the DTD + found at: + + http://www.kde.org/standards/kcfg/1.0/kcfg.dtd + + Documents valid against the Schema version are backwards compatible + to the DTD. Validating against the Schema instead of the DTD is + recommended, since the former provides better validation. + + A document instance of this Schema should have a declaration + looking like this: + + <![CDATA[ + + <?xml version="1.0" encoding="UTF-8" ?> + <kcfg xmlns="http://www.kde.org/standards/kcfg/1.0" + 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" > + <!-- the content --> + </kcfg> + + ]]> + + </xsd:documentation> + </xsd:annotation> + + <xsd:element name="kcfg"> + <xsd:complexType> + <xsd:sequence> + <xsd:element name="include" minOccurs="0" maxOccurs="unbounded" type="xsd:string"/> + <xsd:element name="kcfgfile" > + <xsd:complexType> + <xsd:sequence> + <xsd:element name="parameter" type="kcfg:parameter" minOccurs="0" maxOccurs="unbounded" /> + <!-- FIXME: Are really unbounded occurances of parameter allowed? --> + </xsd:sequence> + <xsd:attribute name="name" type="xsd:string" use="optional"/> + <xsd:attribute name="arg" type="xsd:boolean" use="optional"/> + </xsd:complexType> + </xsd:element> + <xsd:element name="signal" type="kcfg:signal" minOccurs="0" maxOccurs="unbounded" /> + <xsd:element name="group" maxOccurs="unbounded" > + <xsd:complexType> + <xsd:sequence> + <xsd:element name="entry" maxOccurs="unbounded"> + <xsd:complexType> + <xsd:choice maxOccurs="unbounded"> + <xsd:element name="parameter" minOccurs="0" type="kcfg:parameter"/> + <xsd:element name="label" minOccurs="0" type="kcfg:translatableString"/> + <xsd:element name="whatsthis" minOccurs="0" type="kcfg:translatableString"/> + <xsd:element name="tooltip" minOccurs="0" type="kcfg:translatableString"/> + <xsd:element name="choices" minOccurs="0"> + <xsd:complexType> + <xsd:sequence> + <xsd:element name="choice" maxOccurs="unbounded"> + <xsd:complexType> + <xsd:all> + <xsd:element minOccurs="0" name="label" type="kcfg:translatableString"/> + <xsd:element minOccurs="0" name="whatsthis" type="kcfg:translatableString"/> + <xsd:element minOccurs="0" name="tooltip" type="kcfg:translatableString"/> + </xsd:all> + <xsd:attribute name="name" use="required" type="xsd:string"/> + </xsd:complexType> + </xsd:element> + </xsd:sequence> + <xsd:attribute name="name" use="optional" type="xsd:string"/> + <xsd:attribute name="prefix" use="optional" type="xsd:string"/> + + </xsd:complexType> + </xsd:element> + + <xsd:element name="code" minOccurs="0" type="kcfg:code"/> + + <xsd:element name="default" maxOccurs="unbounded" minOccurs="0" > + <xsd:complexType> + <xsd:simpleContent> + <xsd:extension base="xsd:string"> + <xsd:attribute use="optional" name="code" type="xsd:boolean"/> + <xsd:attribute use="optional" name="param" type="xsd:string"/> + </xsd:extension> + </xsd:simpleContent> + </xsd:complexType> + </xsd:element> + + <xsd:element name="min" minOccurs="0" > + <xsd:complexType> + <xsd:simpleContent> + <xsd:extension base="xsd:string"> + <xsd:attribute name="code" type="xsd:boolean"/> + </xsd:extension> + </xsd:simpleContent> + </xsd:complexType> + </xsd:element> + + <xsd:element name="max" minOccurs="0"> + <xsd:complexType> + <xsd:simpleContent> + <xsd:extension base="xsd:string"> + <xsd:attribute name="code" type="xsd:boolean"/> + </xsd:extension> + </xsd:simpleContent> + </xsd:complexType> + </xsd:element> + + <xsd:element name="emit" minOccurs="0"> + <xsd:complexType> + <xsd:simpleContent> + <xsd:extension base="xsd:string"> + <xsd:attribute name="signal" use="required" type="xsd:string"/> + </xsd:extension> + </xsd:simpleContent> + </xsd:complexType> + </xsd:element> + + </xsd:choice> + <xsd:attribute name="name" use="optional" type="xsd:string"/> + <xsd:attribute name="key" use="optional" type="xsd:string"/> + <xsd:attribute name="hidden" use="optional" type="xsd:boolean"/> + <xsd:attribute name="type" type="kcfg:datatype"/> + </xsd:complexType> + </xsd:element> + </xsd:sequence> + <xsd:attribute name="name" use="required" type="xsd:string"/> + </xsd:complexType> + </xsd:element> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + + <xsd:simpleType name="datatype"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="String"/> + <xsd:enumeration value="StringList"/> + <xsd:enumeration value="Font"/> + <xsd:enumeration value="Rect"/> + <xsd:enumeration value="Size"/> + <xsd:enumeration value="Color"/> + <xsd:enumeration value="Point"/> + <xsd:enumeration value="Int"/> + <xsd:enumeration value="UInt"/> + <xsd:enumeration value="Bool"/> + <xsd:enumeration value="Double"/> + <xsd:enumeration value="DateTime"/> + <xsd:enumeration value="LongLong"/> + <xsd:enumeration value="ULongLong"/> + <xsd:enumeration value="IntList"/> + <xsd:enumeration value="Enum"/> + <xsd:enumeration value="Path"/> + <xsd:enumeration value="PathList"/> + <xsd:enumeration value="Password"/> + <xsd:enumeration value="Url"/> + <xsd:enumeration value="UrlList"/> + </xsd:restriction> + </xsd:simpleType> + + <xsd:complexType name="parameter"> + <xsd:sequence> + <xsd:element minOccurs="0" name="values"> + <xsd:complexType> + <xsd:sequence> + <xsd:element name="value" maxOccurs="unbounded" type="xsd:string"/> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + </xsd:sequence> + <xsd:attribute name="name" use="required" type="xsd:string"/> + <xsd:attribute name="type" use="optional" type="kcfg:datatype" /> + <xsd:attribute name="max" use="optional" type="xsd:positiveInteger"/> + </xsd:complexType> + + <xsd:complexType name="code"> + <xsd:simpleContent> + <xsd:extension base="xsd:string"/> + </xsd:simpleContent> + </xsd:complexType> + + <xsd:complexType name="signal"> + <xsd:sequence> + <xsd:element name="label" minOccurs="0" type="xsd:string"/> + <xsd:element name="argument" maxOccurs="unbounded" minOccurs="0" > + <xsd:complexType> + <xsd:simpleContent> + <xsd:extension base="xsd:string"> + <xsd:attribute use="required" name="type" type="kcfg:datatype"/> + </xsd:extension> + </xsd:simpleContent> + </xsd:complexType> + </xsd:element> + </xsd:sequence> + <xsd:attribute name="name" use="required" type="xsd:string" /> + </xsd:complexType> + + <xsd:complexType name="translatableString"> + <xsd:simpleContent> + <xsd:extension base="xsd:string"> + <xsd:attribute use="optional" name="context" type="xsd:string"/> + </xsd:extension> + </xsd:simpleContent> + </xsd:complexType> +</xsd:schema> + diff --git a/tier1/kconfig/src/kconfig_compiler/kconfig_compiler.cpp b/tier1/kconfig/src/kconfig_compiler/kconfig_compiler.cpp new file mode 100644 index 00000000..ae192eec --- /dev/null +++ b/tier1/kconfig/src/kconfig_compiler/kconfig_compiler.cpp @@ -0,0 +1,2338 @@ +// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; -*- +/* + This file is part of KDE. + + Copyright (c) 2003 Cornelius Schumacher <schumacher@kde.org> + Copyright (c) 2003 Waldo Bastian <bastian@kde.org> + Copyright (c) 2003 Zack Rusin <zack@kde.org> + Copyright (c) 2006 Michaël Larouche <michael.larouche@kdemail.net> + Copyright (c) 2008 Allen Winter <winter@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +// Compiling this file with this flag is just crazy +#undef QT_NO_CAST_FROM_ASCII + +#include <QtCore/QCoreApplication> +#include <QtCore/QFile> +#include <QtCore/QFileInfo> +#include <QtCore/QSettings> +#include <QtCore/QTextStream> +#include <QtXml/QDomAttr> +#include <QtCore/QRegExp> +#include <QtCore/QStringList> + +#include <ostream> +#include <iostream> +#include <stdlib.h> + +namespace +{ + QTextStream cout(stdout); + QTextStream cerr(stderr); +} + +static void parseArgs(const QStringList &args, QString &directory, QString &file1, QString &file2) +{ + int fileCount = 0; + directory = QChar::fromLatin1('.'); + + for (int i = 1; i < args.count(); ++i) { + if (args.at(i) == QLatin1String("-d") || args.at(i) == QLatin1String("--directory")) { + if (i + 1 > args.count()) { + cerr << args.at(i) << " needs an argument" << endl; + exit(1); + } + directory = args.at(++i); + } else if (args.at(i).startsWith(QLatin1String("-d"))) { + directory = args.at(i).mid(2); + } else if (args.at(i) == QLatin1String("--help") || args.at(i) == QLatin1String("-h")) { + cout << "Options:" << endl; + cout << " -L --license Display software license" << endl; + cout << " -d, --directory <dir> Directory to generate files in [.]" << endl; + cout << " -h, --help Display this help" << endl; + cout << endl; + cout << "Arguments:" << endl; + cout << " file.kcfg Input kcfg XML file" << endl; + cout << " file.kcfgc Code generation options file" << endl; + exit(0); + } else if (args.at(i) == QLatin1String("--license") || args.at(i) == QLatin1String("-L")) { + cout << "Copyright 2003 Cornelius Schumacher, Waldo Bastian, Zack Rusin," << endl; + cout << " Reinhold Kainhofer, Duncan Mac-Vicar P., Harald Fernengel" << endl; + cout << "This program comes with ABSOLUTELY NO WARRANTY." << endl; + cout << "You may redistribute copies of this program" << endl; + cout << "under the terms of the GNU Library Public License." << endl; + cout << "For more information about these matters, see the file named COPYING." << endl; + exit(0); + } else if (args.at(i).startsWith(QLatin1Char('-'))) { + cerr << "Unknown option: " << args.at(i) << endl; + exit(1); + } else if (fileCount == 0) { + file1 = args.at(i); + ++fileCount; + } else if (fileCount == 1) { + file2 = args.at(i); + ++fileCount; + } else { + cerr << "Too many arguments" << endl; + exit(1); + } + } + if (fileCount < 2) { + cerr << "Too few arguments" << endl; + exit(1); + } +} + +QStringList allNames; +QRegExp *validNameRegexp; +QString This; +QString Const; + +/** + Configuration Compiler Configuration +*/ +class CfgConfig +{ +public: + CfgConfig( const QString &codegenFilename ) + { + // Configure the compiler with some settings + QSettings codegenConfig(codegenFilename, QSettings::IniFormat); + + nameSpace = codegenConfig.value("NameSpace").toString(); + className = codegenConfig.value("ClassName").toString(); + if ( className.isEmpty() ) { + cerr << "Class name missing" << endl; + exit(1); + } + inherits = codegenConfig.value("Inherits").toString(); + if ( inherits.isEmpty() ) inherits = "KConfigSkeleton"; + visibility = codegenConfig.value("Visibility").toString(); + if ( !visibility.isEmpty() ) visibility += ' '; + forceStringFilename = codegenConfig.value("ForceStringFilename", false).toBool(); + singleton = codegenConfig.value("Singleton", false).toBool(); + staticAccessors = singleton; + customAddons = codegenConfig.value("CustomAdditions", false).toBool(); + memberVariables = codegenConfig.value("MemberVariables").toString(); + dpointer = (memberVariables == "dpointer"); + headerIncludes = codegenConfig.value("IncludeFiles", QStringList()).toStringList(); + sourceIncludes = codegenConfig.value("SourceIncludeFiles", QStringList()).toStringList(); + mutators = codegenConfig.value("Mutators", QStringList()).toStringList(); + allMutators = ((mutators.count() == 1) && (mutators.at(0).toLower() == "true")); + itemAccessors = codegenConfig.value("ItemAccessors", false).toBool(); + setUserTexts = codegenConfig.value("SetUserTexts", false).toBool(); + defaultGetters = codegenConfig.value("DefaultValueGetters", QStringList()).toStringList(); + allDefaultGetters = (defaultGetters.count() == 1) && (defaultGetters.at(0).toLower() == "true"); + globalEnums = codegenConfig.value("GlobalEnums", false).toBool(); + useEnumTypes = codegenConfig.value("UseEnumTypes", false).toBool(); + + const QString trString = codegenConfig.value("TranslationSystem").toString().toLower(); + if ( trString == "kde" ) { + translationSystem = KdeTranslation; + } else { + if ( !trString.isEmpty() && trString != "qt" ) { + cerr << "Unknown translation system, falling back to Qt tr()" << endl; + } + translationSystem = QtTranslation; + } + } + +public: + enum TranslationSystem { + QtTranslation, + KdeTranslation + }; + + // These are read from the .kcfgc configuration file + QString nameSpace; // The namespace for the class to be generated + QString className; // The class name to be generated + QString inherits; // The class the generated class inherits (if empty, from KConfigSkeleton) + QString visibility; + bool forceStringFilename; + bool singleton; // The class will be a singleton + bool staticAccessors; // provide or not static accessors + bool customAddons; + QString memberVariables; + QStringList headerIncludes; + QStringList sourceIncludes; + QStringList mutators; + QStringList defaultGetters; + bool allMutators; + bool setUserTexts; + bool allDefaultGetters; + bool dpointer; + bool globalEnums; + bool useEnumTypes; + bool itemAccessors; + TranslationSystem translationSystem; +}; + + +struct SignalArguments +{ + QString type; + QString variableName; +}; + +class Signal { +public: + QString name; + QString label; + QList<SignalArguments> arguments; +}; + + + + +class CfgEntry +{ + public: + struct Choice + { + QString name; + QString context; + QString label; + QString toolTip; + QString whatsThis; + }; + class Choices + { + public: + Choices() {} + Choices( const QList<Choice> &d, const QString &n, const QString &p ) + : prefix(p), choices(d), mName(n) + { + int i = n.indexOf(QLatin1String("::")); + if (i >= 0) + mExternalQual = n.left(i + 2); + } + QString prefix; + QList<Choice> choices; + const QString& name() const { return mName; } + const QString& externalQualifier() const { return mExternalQual; } + bool external() const { return !mExternalQual.isEmpty(); } + private: + QString mName; + QString mExternalQual; + }; + + CfgEntry( const QString &group, const QString &type, const QString &key, + const QString &name, const QString &labelContext, const QString &label, + const QString &toolTipContext, const QString &toolTip, const QString &whatsThisContext, const QString &whatsThis, const QString &code, + const QString &defaultValue, const Choices &choices, const QList<Signal> signalList, + bool hidden ) + : mGroup( group ), mType( type ), mKey( key ), mName( name ), + mLabelContext( labelContext ), mLabel( label ), mToolTipContext( toolTipContext ), mToolTip( toolTip ), + mWhatsThisContext( whatsThisContext ), mWhatsThis( whatsThis ), + mCode( code ), mDefaultValue( defaultValue ), mChoices( choices ), + mSignalList(signalList), mHidden( hidden ) + { + } + + void setGroup( const QString &group ) { mGroup = group; } + QString group() const { return mGroup; } + + void setType( const QString &type ) { mType = type; } + QString type() const { return mType; } + + void setKey( const QString &key ) { mKey = key; } + QString key() const { return mKey; } + + void setName( const QString &name ) { mName = name; } + QString name() const { return mName; } + + void setLabelContext( const QString &labelContext ) { mLabelContext = labelContext; } + QString labelContext() const { return mLabelContext; } + + void setLabel( const QString &label ) { mLabel = label; } + QString label() const { return mLabel; } + + void setToolTipContext( const QString &toolTipContext ) { mToolTipContext = toolTipContext; } + QString toolTipContext() const { return mToolTipContext; } + + void setToolTip( const QString &toolTip ) { mToolTip = toolTip; } + QString toolTip() const { return mToolTip; } + + void setWhatsThisContext( const QString &whatsThisContext ) { mWhatsThisContext = whatsThisContext; } + QString whatsThisContext() const { return mWhatsThisContext; } + + void setWhatsThis( const QString &whatsThis ) { mWhatsThis = whatsThis; } + QString whatsThis() const { return mWhatsThis; } + + void setDefaultValue( const QString &d ) { mDefaultValue = d; } + QString defaultValue() const { return mDefaultValue; } + + void setCode( const QString &d ) { mCode = d; } + QString code() const { return mCode; } + + void setMinValue( const QString &d ) { mMin = d; } + QString minValue() const { return mMin; } + + void setMaxValue( const QString &d ) { mMax = d; } + QString maxValue() const { return mMax; } + + void setParam( const QString &d ) { mParam = d; } + QString param() const { return mParam; } + + void setParamName( const QString &d ) { mParamName = d; } + QString paramName() const { return mParamName; } + + void setParamType( const QString &d ) { mParamType = d; } + QString paramType() const { return mParamType; } + + void setChoices( const QList<Choice> &d, const QString &n, const QString &p ) { mChoices = Choices( d, n, p ); } + Choices choices() const { return mChoices; } + + void setParamValues( const QStringList &d ) { mParamValues = d; } + QStringList paramValues() const { return mParamValues; } + + void setParamDefaultValues( const QStringList &d ) { mParamDefaultValues = d; } + QString paramDefaultValue(int i) const { return mParamDefaultValues[i]; } + + void setParamMax( int d ) { mParamMax = d; } + int paramMax() const { return mParamMax; } + + void setSignalList( const QList<Signal> &value ) { mSignalList = value; } + QList<Signal> signalList() const { return mSignalList; } + + bool hidden() const { return mHidden; } + + void dump() const + { + cerr << "<entry>" << endl; + cerr << " group: " << mGroup << endl; + cerr << " type: " << mType << endl; + cerr << " key: " << mKey << endl; + cerr << " name: " << mName << endl; + cerr << " label context: " << mLabelContext << endl; + cerr << " label: " << mLabel << endl; +// whatsthis + cerr << " code: " << mCode << endl; +// cerr << " values: " << mValues.join(":") << endl; + + if (!param().isEmpty()) + { + cerr << " param name: "<< mParamName << endl; + cerr << " param type: "<< mParamType << endl; + cerr << " paramvalues: " << mParamValues.join(QChar::fromLatin1(':')) << endl; + } + cerr << " default: " << mDefaultValue << endl; + cerr << " hidden: " << mHidden << endl; + cerr << " min: " << mMin << endl; + cerr << " max: " << mMax << endl; + cerr << "</entry>" << endl; + } + + private: + QString mGroup; + QString mType; + QString mKey; + QString mName; + QString mLabelContext; + QString mLabel; + QString mToolTipContext; + QString mToolTip; + QString mWhatsThisContext; + QString mWhatsThis; + QString mCode; + QString mDefaultValue; + QString mParam; + QString mParamName; + QString mParamType; + Choices mChoices; + QList<Signal> mSignalList; + QStringList mParamValues; + QStringList mParamDefaultValues; + int mParamMax; + bool mHidden; + QString mMin; + QString mMax; +}; + +class Param { +public: + QString name; + QString type; +}; + +// returns the name of an member variable +// use itemPath to know the full path +// like using d-> in case of dpointer +static QString varName(const QString &n, const CfgConfig &cfg) +{ + QString result; + if ( !cfg.dpointer ) { + result = QChar::fromLatin1('m') + n; + result[1] = result[1].toUpper(); + } + else { + result = n; + result[0] = result[0].toLower(); + } + return result; +} + +static QString varPath(const QString &n, const CfgConfig &cfg) +{ + QString result; + if ( cfg.dpointer ) { + result = "d->"+varName(n, cfg); + } + else { + result = varName(n, cfg); + } + return result; +} + +static QString enumName(const QString &n) +{ + QString result = QString::fromLatin1("Enum") + n; + result[4] = result[4].toUpper(); + return result; +} + +static QString enumName(const QString &n, const CfgEntry::Choices &c) +{ + QString result = c.name(); + if ( result.isEmpty() ) + { + result = QString::fromLatin1("Enum") + n; + result[4] = result[4].toUpper(); + } + return result; +} + +static QString enumType(const CfgEntry *e, bool globalEnums) +{ + QString result = e->choices().name(); + if ( result.isEmpty() ) + { + result = QString::fromLatin1("Enum") + e->name(); + if( !globalEnums ) + result += QString::fromLatin1("::type"); + result[4] = result[4].toUpper(); + } + return result; +} + +static QString enumTypeQualifier(const QString &n, const CfgEntry::Choices &c) +{ + QString result = c.name(); + if ( result.isEmpty() ) + { + result = QString::fromLatin1("Enum") + n + QString::fromLatin1("::"); + result[4] = result[4].toUpper(); + } + else if ( c.external() ) + result = c.externalQualifier(); + else + result.clear(); + return result; +} + +static QString setFunction(const QString &n, const QString &className = QString()) +{ + QString result = QString::fromLatin1("set") + n; + result[3] = result[3].toUpper(); + + if ( !className.isEmpty() ) + result = className + QString::fromLatin1("::") + result; + return result; +} + +static QString getDefaultFunction(const QString &n, const QString &className = QString()) +{ + QString result = QString::fromLatin1("default") + n + QString::fromLatin1("Value"); + result[7] = result[7].toUpper(); + + if ( !className.isEmpty() ) + result = className + QString::fromLatin1("::") + result; + return result; +} + +static QString getFunction(const QString &n, const QString &className = QString()) +{ + QString result = n; + result[0] = result[0].toLower(); + + if ( !className.isEmpty() ) + result = className + QString::fromLatin1("::") + result; + return result; +} + + +static void addQuotes( QString &s ) +{ + if ( !s.startsWith( QLatin1Char('"') ) ) + s.prepend( QLatin1Char('"') ); + if ( !s.endsWith( QLatin1Char('"') ) ) + s.append( QLatin1Char('"') ); +} + +static QString quoteString( const QString &s ) +{ + QString r = s; + r.replace( QLatin1Char('\\'), QLatin1String("\\\\") ); + r.replace( QLatin1Char('\"'), QLatin1String("\\\"") ); + r.remove( QLatin1Char('\r') ); + r.replace( QLatin1Char('\n'), QLatin1String("\\n\"\n\"") ); + return QLatin1Char('\"') + r + QLatin1Char('\"'); +} + +static QString literalString( const QString &s ) +{ + bool isAscii = true; + for(int i = s.length(); i--;) + if (s[i].unicode() > 127) isAscii = false; + + if (isAscii) + return QString::fromLatin1("QLatin1String( ") + quoteString(s) + QString::fromLatin1(" )"); + else + return QString::fromLatin1("QString::fromUtf8( ") + quoteString(s) + QString::fromLatin1(" )"); +} + +static QString dumpNode(const QDomNode &node) +{ + QString msg; + QTextStream s(&msg, QIODevice::WriteOnly ); + node.save(s, 0); + + msg = msg.simplified(); + if (msg.length() > 40) + return msg.left(37) + QString::fromLatin1("..."); + return msg; +} + +static QString filenameOnly(const QString& path) +{ + int i = path.lastIndexOf(QRegExp(QLatin1String("[/\\]"))); + if (i >= 0) + return path.mid(i+1); + return path; +} + +static QString signalEnumName(const QString &signalName) +{ + QString result; + result = QString::fromLatin1("signal") + signalName; + result[6] = result[6].toUpper(); + + return result; +} + +static void preProcessDefault( QString &defaultValue, const QString &name, + const QString &type, + const CfgEntry::Choices &choices, + QString &code, const CfgConfig &cfg ) +{ + if ( type == QLatin1String("String") && !defaultValue.isEmpty() ) { + defaultValue = literalString(defaultValue); + + } else if ( type == QLatin1String("Path") && !defaultValue.isEmpty() ) { + defaultValue = literalString( defaultValue ); + } else if ( type == QLatin1String("Url") && !defaultValue.isEmpty() ) { + // Use fromUserInput in order to support absolute paths and absolute urls, like KDE4's KUrl(QString) did. + defaultValue = QString::fromLatin1("QUrl::fromUserInput( ") + literalString(defaultValue) + QLatin1Char(')'); + } else if ( ( type == QLatin1String("UrlList") || type == QLatin1String("StringList") || type == QLatin1String("PathList")) && !defaultValue.isEmpty() ) { + QTextStream cpp( &code, QIODevice::WriteOnly | QIODevice::Append ); + if (!code.isEmpty()) + cpp << endl; + + if( type == "UrlList" ) { + cpp << " QList<QUrl> default" << name << ";" << endl; + } else { + cpp << " QStringList default" << name << ";" << endl; + } + const QStringList defaults = defaultValue.split(QLatin1Char(',')); + QStringList::ConstIterator it; + for( it = defaults.constBegin(); it != defaults.constEnd(); ++it ) { + cpp << " default" << name << ".append( "; + if( type == QLatin1String("UrlList") ) { + cpp << "QUrl::fromUserInput("; + } + cpp << "QString::fromUtf8( \"" << *it << "\" ) "; + if( type == QLatin1String("UrlList") ) { + cpp << ") "; + } + cpp << ");" << endl; + } + defaultValue = QString::fromLatin1("default") + name; + + } else if ( type == QLatin1String("Color") && !defaultValue.isEmpty() ) { + QRegExp colorRe(QLatin1String("\\d+,\\s*\\d+,\\s*\\d+(,\\s*\\d+)?")); + if (colorRe.exactMatch(defaultValue)) + { + defaultValue = QLatin1String("QColor( ") + defaultValue + QLatin1String(" )"); + } + else + { + defaultValue = QLatin1String("QColor( \"") + defaultValue + QLatin1String("\" )"); + } + + } else if ( type == QLatin1String("Enum") ) { + QList<CfgEntry::Choice>::ConstIterator it; + for( it = choices.choices.constBegin(); it != choices.choices.constEnd(); ++it ) { + if ( (*it).name == defaultValue ) { + if ( cfg.globalEnums && choices.name().isEmpty() ) + defaultValue.prepend( choices.prefix ); + else + defaultValue.prepend( enumTypeQualifier(name, choices) + choices.prefix ); + break; + } + } + + } else if ( type == QLatin1String("IntList") ) { + QTextStream cpp( &code, QIODevice::WriteOnly | QIODevice::Append ); + if (!code.isEmpty()) + cpp << endl; + + cpp << " QList<int> default" << name << ";" << endl; + if (!defaultValue.isEmpty()) + { + const QStringList defaults = defaultValue.split( QLatin1Char(',') ); + QStringList::ConstIterator it; + for( it = defaults.constBegin(); it != defaults.constEnd(); ++it ) { + cpp << " default" << name << ".append( " << *it << " );" + << endl; + } + } + defaultValue = QString::fromLatin1("default") + name; + } +} + + +CfgEntry *parseEntry( const QString &group, const QDomElement &element, const CfgConfig &cfg ) +{ + bool defaultCode = false; + QString type = element.attribute( "type" ); + QString name = element.attribute( "name" ); + QString key = element.attribute( "key" ); + QString hidden = element.attribute( "hidden" ); + QString labelContext; + QString label; + QString toolTipContext; + QString toolTip; + QString whatsThisContext; + QString whatsThis; + QString defaultValue; + QString code; + QString param; + QString paramName; + QString paramType; + CfgEntry::Choices choices; + QList<Signal> signalList; + QStringList paramValues; + QStringList paramDefaultValues; + QString minValue; + QString maxValue; + int paramMax = 0; + + for ( QDomElement e = element.firstChildElement(); !e.isNull(); e = e.nextSiblingElement() ) { + QString tag = e.tagName(); + if ( tag == "label" ) { + label = e.text(); + labelContext = e.attribute( "context" ); + } + else if ( tag == "tooltip" ) { + toolTip = e.text(); + toolTipContext = e.attribute( "context" ); + } + else if ( tag == "whatsthis" ) { + whatsThis = e.text(); + whatsThisContext = e.attribute( "context" ); + } + else if ( tag == "min" ) minValue = e.text(); + else if ( tag == "max" ) maxValue = e.text(); + else if ( tag == "code" ) code = e.text(); + else if ( tag == "parameter" ) + { + param = e.attribute( "name" ); + paramType = e.attribute( "type" ); + if ( param.isEmpty() ) { + cerr << "Parameter must have a name: " << dumpNode(e) << endl; + return 0; + } + if ( paramType.isEmpty() ) { + cerr << "Parameter must have a type: " << dumpNode(e) << endl; + return 0; + } + if ((paramType == "Int") || (paramType == "UInt")) + { + bool ok; + paramMax = e.attribute("max").toInt(&ok); + if (!ok) + { + cerr << "Integer parameter must have a maximum (e.g. max=\"0\"): " + << dumpNode(e) << endl; + return 0; + } + } + else if (paramType == "Enum") + { + for ( QDomElement e2 = e.firstChildElement(); !e2.isNull(); e2 = e2.nextSiblingElement() ) { + if (e2.tagName() == "values") + { + for ( QDomElement e3 = e2.firstChildElement(); !e3.isNull(); e3 = e3.nextSiblingElement() ) { + if (e3.tagName() == "value") + { + paramValues.append( e3.text() ); + } + } + break; + } + } + if (paramValues.isEmpty()) + { + cerr << "No values specified for parameter '" << param + << "'." << endl; + return 0; + } + paramMax = paramValues.count()-1; + } + else + { + cerr << "Parameter '" << param << "' has type " << paramType + << " but must be of type int, uint or Enum." << endl; + return 0; + } + } + else if ( tag == "default" ) + { + if (e.attribute("param").isEmpty()) + { + defaultValue = e.text(); + if (e.attribute( "code" ) == "true") + defaultCode = true; + } + } + else if ( tag == "choices" ) { + QString name = e.attribute( "name" ); + QString prefix = e.attribute( "prefix" ); + QList<CfgEntry::Choice> chlist; + for( QDomElement e2 = e.firstChildElement(); !e2.isNull(); e2 = e2.nextSiblingElement() ) { + if ( e2.tagName() == "choice" ) { + CfgEntry::Choice choice; + choice.name = e2.attribute( "name" ); + if ( choice.name.isEmpty() ) { + cerr << "Tag <choice> requires attribute 'name'." << endl; + } + for( QDomElement e3 = e2.firstChildElement(); !e3.isNull(); e3 = e3.nextSiblingElement() ) { + if ( e3.tagName() == "label" ) { + choice.label = e3.text(); + choice.context = e3.attribute( "context" ); + } + if ( e3.tagName() == "tooltip" ) { + choice.toolTip = e3.text(); + choice.context = e3.attribute( "context" ); + } + if ( e3.tagName() == "whatsthis" ) { + choice.whatsThis = e3.text(); + choice.context = e3.attribute( "context" ); + } + } + chlist.append( choice ); + } + } + choices = CfgEntry::Choices( chlist, name, prefix ); + } + else if ( tag == "emit" ) { + QDomNode signalNode; + Signal signal; + signal.name = e.attribute( "signal" ); + signalList.append( signal); + } + } + + + bool nameIsEmpty = name.isEmpty(); + if ( nameIsEmpty && key.isEmpty() ) { + cerr << "Entry must have a name or a key: " << dumpNode(element) << endl; + return 0; + } + + if ( key.isEmpty() ) { + key = name; + } + + if ( nameIsEmpty ) { + name = key; + name.remove( ' ' ); + } else if ( name.contains( ' ' ) ) { + cout<<"Entry '"<<name<<"' contains spaces! <name> elements can not contain spaces!"<<endl; + name.remove( ' ' ); + } + + if (name.contains("$(")) + { + if (param.isEmpty()) + { + cerr << "Name may not be parameterized: " << name << endl; + return 0; + } + } + else + { + if (!param.isEmpty()) + { + cerr << "Name must contain '$(" << param << ")': " << name << endl; + return 0; + } + } + + if ( label.isEmpty() ) { + label = key; + } + + if ( type.isEmpty() ) type = "String"; // XXX : implicit type might be bad + + if (!param.isEmpty()) + { + // Adjust name + paramName = name; + name.remove("$("+param+')'); + // Lookup defaults for indexed entries + for(int i = 0; i <= paramMax; i++) + { + paramDefaultValues.append(QString()); + } + + for ( QDomElement e = element.firstChildElement(); !e.isNull(); e = e.nextSiblingElement() ) { + QString tag = e.tagName(); + if ( tag == "default" ) + { + QString index = e.attribute("param"); + if (index.isEmpty()) + continue; + + bool ok; + int i = index.toInt(&ok); + if (!ok) + { + i = paramValues.indexOf(index); + if (i == -1) + { + cerr << "Index '" << index << "' for default value is unknown." << endl; + return 0; + } + } + + if ((i < 0) || (i > paramMax)) + { + cerr << "Index '" << i << "' for default value is out of range [0, "<< paramMax<<"]." << endl; + return 0; + } + + QString tmpDefaultValue = e.text(); + + if (e.attribute( "code" ) != "true") + preProcessDefault(tmpDefaultValue, name, type, choices, code, cfg); + + paramDefaultValues[i] = tmpDefaultValue; + } + } + } + + if (!validNameRegexp->exactMatch(name)) + { + if (nameIsEmpty) + cerr << "The key '" << key << "' can not be used as name for the entry because " + "it is not a valid name. You need to specify a valid name for this entry." << endl; + else + cerr << "The name '" << name << "' is not a valid name for an entry." << endl; + return 0; + } + + if (allNames.contains(name)) + { + if (nameIsEmpty) + cerr << "The key '" << key << "' can not be used as name for the entry because " + "it does not result in a unique name. You need to specify a unique name for this entry." << endl; + else + cerr << "The name '" << name << "' is not unique." << endl; + return 0; + } + allNames.append(name); + + if (!defaultCode) + { + preProcessDefault(defaultValue, name, type, choices, code, cfg); + } + + CfgEntry *result = new CfgEntry( group, type, key, name, labelContext, label, toolTipContext, toolTip, whatsThisContext, whatsThis, + code, defaultValue, choices, signalList, + hidden == "true" ); + if (!param.isEmpty()) + { + result->setParam(param); + result->setParamName(paramName); + result->setParamType(paramType); + result->setParamValues(paramValues); + result->setParamDefaultValues(paramDefaultValues); + result->setParamMax(paramMax); + } + result->setMinValue(minValue); + result->setMaxValue(maxValue); + + return result; +} + +static bool isUnsigned(const QString& type) +{ + if ( type == "UInt" ) return true; + if ( type == "ULongLong" ) return true; + return false; +} + +/** + Return parameter declaration for given type. +*/ +QString param( const QString &t ) +{ + const QString type = t.toLower(); + if ( type == "string" ) return "const QString &"; + else if ( type == "stringlist" ) return "const QStringList &"; + else if ( type == "font" ) return "const QFont &"; + else if ( type == "rect" ) return "const QRect &"; + else if ( type == "size" ) return "const QSize &"; + else if ( type == "color" ) return "const QColor &"; + else if ( type == "point" ) return "const QPoint &"; + else if ( type == "int" ) return "int"; + else if ( type == "uint" ) return "uint"; + else if ( type == "bool" ) return "bool"; + else if ( type == "double" ) return "double"; + else if ( type == "datetime" ) return "const QDateTime &"; + else if ( type == "longlong" ) return "qint64"; + else if ( type == "ulonglong" ) return "quint64"; + else if ( type == "intlist" ) return "const QList<int> &"; + else if ( type == "enum" ) return "int"; + else if ( type == "path" ) return "const QString &"; + else if ( type == "pathlist" ) return "const QStringList &"; + else if ( type == "password" ) return "const QString &"; + else if ( type == "url" ) return "const QUrl &"; + else if ( type == "urllist" ) return "const QList<QUrl> &"; + else { + cerr <<"kconfig_compiler does not support type \""<< type <<"\""<<endl; + return "QString"; //For now, but an assert would be better + } +} + +/** + Actual C++ storage type for given type. +*/ +QString cppType( const QString &t ) +{ + const QString type = t.toLower(); + if ( type == "string" ) return "QString"; + else if ( type == "stringlist" ) return "QStringList"; + else if ( type == "font" ) return "QFont"; + else if ( type == "rect" ) return "QRect"; + else if ( type == "size" ) return "QSize"; + else if ( type == "color" ) return "QColor"; + else if ( type == "point" ) return "QPoint"; + else if ( type == "int" ) return "int"; + else if ( type == "uint" ) return "uint"; + else if ( type == "bool" ) return "bool"; + else if ( type == "double" ) return "double"; + else if ( type == "datetime" ) return "QDateTime"; + else if ( type == "longlong" ) return "qint64"; + else if ( type == "ulonglong" ) return "quint64"; + else if ( type == "intlist" ) return "QList<int>"; + else if ( type == "enum" ) return "int"; + else if ( type == "path" ) return "QString"; + else if ( type == "pathlist" ) return "QStringList"; + else if ( type == "password" ) return "QString"; + else if ( type == "url" ) return "QUrl"; + else if ( type == "urllist" ) return "QList<QUrl>"; + else { + cerr<<"kconfig_compiler does not support type \""<< type <<"\""<<endl; + return "QString"; //For now, but an assert would be better + } +} + +QString defaultValue( const QString &t ) +{ + const QString type = t.toLower(); + if ( type == "string" ) return "\"\""; // Use empty string, not null string! + else if ( type == "stringlist" ) return "QStringList()"; + else if ( type == "font" ) return "QFont()"; + else if ( type == "rect" ) return "QRect()"; + else if ( type == "size" ) return "QSize()"; + else if ( type == "color" ) return "QColor(128, 128, 128)"; + else if ( type == "point" ) return "QPoint()"; + else if ( type == "int" ) return "0"; + else if ( type == "uint" ) return "0"; + else if ( type == "bool" ) return "false"; + else if ( type == "double" ) return "0.0"; + else if ( type == "datedime" ) return "QDateTime()"; + else if ( type == "longlong" ) return "0"; + else if ( type == "ulonglong" ) return "0"; + else if ( type == "intlist" ) return "QList<int>()"; + else if ( type == "enum" ) return "0"; + else if ( type == "path" ) return "\"\""; // Use empty string, not null string! + else if ( type == "pathlist" ) return "QStringList()"; + else if ( type == "password" ) return "\"\""; // Use empty string, not null string! + else if ( type == "url" ) return "QUrl()"; + else if ( type == "urllist" ) return "QList<QUrl>()"; + else { + cerr<<"Error, kconfig_compiler does not support the \""<< type <<"\" type!"<<endl; + return "QString"; //For now, but an assert would be better + } +} + +QString itemType( const QString &type ) +{ + QString t; + + t = type; + t.replace( 0, 1, t.left( 1 ).toUpper() ); + + return t; +} + +static QString itemDeclaration(const CfgEntry *e, const CfgConfig &cfg) +{ + if (cfg.itemAccessors) + return QString(); + + QString fCap = e->name(); + fCap[0] = fCap[0].toUpper(); + return " "+cfg.inherits+"::Item"+itemType( e->type() ) + + " *item" + fCap + + ( (!e->param().isEmpty())?(QString("[%1]").arg(e->paramMax()+1)) : QString()) + + ";\n"; +} + +// returns the name of an item variable +// use itemPath to know the full path +// like using d-> in case of dpointer +static QString itemVar(const CfgEntry *e, const CfgConfig &cfg) +{ + QString result; + if (cfg.itemAccessors) + { + if ( !cfg.dpointer ) + { + result = 'm' + e->name() + "Item"; + result[1] = result[1].toUpper(); + } + else + { + result = e->name() + "Item"; + result[0] = result[0].toLower(); + } + } + else + { + result = "item" + e->name(); + result[4] = result[4].toUpper(); + } + return result; +} + +static QString itemPath(const CfgEntry *e, const CfgConfig &cfg) +{ + QString result; + if ( cfg.dpointer ) { + result = "d->"+itemVar(e, cfg); + } + else { + result = itemVar(e, cfg); + } + return result; +} + +QString newItem( const QString &type, const QString &name, const QString &key, + const QString &defaultValue, const CfgConfig &cfg, const QString ¶m = QString()) +{ + QString t = "new "+cfg.inherits+"::Item" + itemType( type ) + + "( currentGroup(), " + key + ", " + varPath( name, cfg ) + param; + if ( type == "Enum" ) t += ", values" + name; + if ( !defaultValue.isEmpty() ) { + t += ", "; + if ( type == "String" ) t += defaultValue; + else t+= defaultValue; + } + t += " );"; + + return t; +} + +QString paramString(const QString &s, const CfgEntry *e, int i) +{ + QString result = s; + QString needle = "$("+e->param()+')'; + if (result.contains(needle)) + { + QString tmp; + if (e->paramType() == "Enum") + { + tmp = e->paramValues()[i]; + } + else + { + tmp = QString::number(i); + } + + result.replace(needle, tmp); + } + return result; +} + +QString paramString(const QString &group, const QList<Param> ¶meters) +{ + QString paramString = group; + QString arguments; + int i = 1; + for (QList<Param>::ConstIterator it = parameters.constBegin(); + it != parameters.constEnd(); ++it) + { + if (paramString.contains("$("+(*it).name+')')) + { + QString tmp; + tmp.sprintf("%%%d", i++); + paramString.replace("$("+(*it).name+')', tmp); + arguments += ".arg( mParam"+(*it).name+" )"; + } + } + if (arguments.isEmpty()) + return "QLatin1String( \""+group+"\" )"; + + return "QString( QLatin1String( \""+paramString+"\" ) )"+arguments; +} + +QString translatedString(const CfgConfig &cfg, const QString &string, const QString &context = QString(), const QString ¶m = QString(), const QString ¶mValue = QString()) +{ + QString result; + + switch (cfg.translationSystem) { + case CfgConfig::QtTranslation: + if (!context.isEmpty()) { + result+= "/*: " + context + " */ QCoreApplication::translate(\""; + } else { + result+= "QCoreApplication::translate(\""; + } + result+= cfg.className + "\", "; + break; + + case CfgConfig::KdeTranslation: + if (!context.isEmpty()) { + result+= "i18nc(" + quoteString(context) + ", "; + } else { + result+= "i18n("; + } + break; + } + + if (!param.isEmpty()) { + QString resolvedString = string; + resolvedString.replace("$("+param+')', paramValue); + result+= quoteString(resolvedString); + } else { + result+= quoteString(string); + } + + result+= ')'; + + return result; +} + +/* int i is the value of the parameter */ +QString userTextsFunctions( CfgEntry *e, const CfgConfig &cfg, QString itemVarStr=QString(), QString i=QString() ) +{ + QString txt; + if (itemVarStr.isNull()) itemVarStr=itemPath(e, cfg); + if ( !e->label().isEmpty() ) { + txt += " " + itemVarStr + "->setLabel( "; + txt += translatedString(cfg, e->label(), e->labelContext(), e->param(), i); + txt += " );\n"; + } + if ( !e->toolTip().isEmpty() ) { + txt += " " + itemVarStr + "->setToolTip( "; + txt += translatedString(cfg, e->toolTip(), e->toolTipContext(), e->param(), i); + txt += " );\n"; + } + if ( !e->whatsThis().isEmpty() ) { + txt += " " + itemVarStr + "->setWhatsThis( "; + txt += translatedString(cfg, e->whatsThis(), e->whatsThisContext(), e->param(), i); + txt += " );\n"; + } + return txt; +} + +// returns the member accesor implementation +// which should go in the h file if inline +// or the cpp file if not inline +QString memberAccessorBody( CfgEntry *e, bool globalEnums, const CfgConfig &cfg ) +{ + QString result; + QTextStream out(&result, QIODevice::WriteOnly); + QString n = e->name(); + QString t = e->type(); + bool useEnumType = cfg.useEnumTypes && t == "Enum"; + + out << "return "; + if (useEnumType) + out << "static_cast<" << enumType(e, globalEnums) << ">("; + out << This << varPath(n, cfg); + if (!e->param().isEmpty()) + out << "[i]"; + if (useEnumType) + out << ")"; + out << ";" << endl; + + return result; +} + +// returns the member mutator implementation +// which should go in the h file if inline +// or the cpp file if not inline +QString memberMutatorBody( CfgEntry *e, const CfgConfig &cfg ) +{ + QString result; + QTextStream out(&result, QIODevice::WriteOnly); + QString n = e->name(); + QString t = e->type(); + + if (!e->minValue().isEmpty()) + { + if (e->minValue() != "0" || !isUnsigned(t)) { // skip writing "if uint<0" (#187579) + out << "if (v < " << e->minValue() << ")" << endl; + out << "{" << endl; + out << " qDebug() << \"" << setFunction(n); + out << ": value \" << v << \" is less than the minimum value of "; + out << e->minValue()<< "\";" << endl; + out << " v = " << e->minValue() << ";" << endl; + out << "}" << endl; + } + } + + if (!e->maxValue().isEmpty()) + { + out << endl << "if (v > " << e->maxValue() << ")" << endl; + out << "{" << endl; + out << " qDebug() << \"" << setFunction(n); + out << ": value \" << v << \" is greater than the maximum value of "; + out << e->maxValue()<< "\";" << endl; + out << " v = " << e->maxValue() << ";" << endl; + out << "}" << endl << endl; + } + + out << "if (!" << This << "isImmutable( QString::fromLatin1( \""; + if (!e->param().isEmpty()) + { + out << e->paramName().replace("$("+e->param()+")", "%1") << "\" ).arg( "; + if ( e->paramType() == "Enum" ) { + out << "QLatin1String( "; + + if (cfg.globalEnums) + out << enumName(e->param()) << "ToString[i]"; + else + out << enumName(e->param()) << "::enumToString[i]"; + + out << " )"; + } + else + { + out << "i"; + } + out << " )"; + } + else + { + out << n << "\" )"; + } + out << " ))" << (!e->signalList().empty() ? " {" : "") << endl; + out << " " << This << varPath(n, cfg); + if (!e->param().isEmpty()) + out << "[i]"; + out << " = v;" << endl; + + if ( !e->signalList().empty() ) { + Q_FOREACH(const Signal &signal, e->signalList()) { + out << " " << This << varPath("settingsChanged", cfg) << " |= " << signalEnumName(signal.name) << ";" << endl; + } + out << "}" << endl; + } + + return result; +} + +// returns the member get default implementation +// which should go in the h file if inline +// or the cpp file if not inline +QString memberGetDefaultBody( CfgEntry *e ) +{ + QString result = e->code(); + QTextStream out(&result, QIODevice::WriteOnly); + out << endl; + + if (!e->param().isEmpty()) { + out << " switch (i) {" << endl; + for (int i = 0; i <= e->paramMax(); ++i) { + if (!e->paramDefaultValue(i).isEmpty()) { + out << " case " << i << ": return " << e->paramDefaultValue(i) << ';' << endl; + } + } + out << " default:" << endl; + out << " return " << e->defaultValue().replace("$("+e->param()+')', "i") << ';' << endl; + out << " }" << endl; + } else { + out << " return " << e->defaultValue() << ';'; + } + + return result; +} + +// returns the item accesor implementation +// which should go in the h file if inline +// or the cpp file if not inline +QString itemAccessorBody( CfgEntry *e, const CfgConfig &cfg ) +{ + QString result; + QTextStream out(&result, QIODevice::WriteOnly); + + out << "return " << itemPath(e, cfg); + if (!e->param().isEmpty()) out << "[i]"; + out << ";" << endl; + + return result; +} + +//indents text adding X spaces per line +QString indent(QString text, int spaces) +{ + QString result; + QTextStream out(&result, QIODevice::WriteOnly); + QTextStream in(&text, QIODevice::ReadOnly); + QString currLine; + while ( !in.atEnd() ) + { + currLine = in.readLine(); + if (!currLine.isEmpty()) + for (int i=0; i < spaces; i++) + out << " "; + out << currLine << endl; + } + return result; +} + +// adds as many 'namespace foo {' lines to p_out as +// there are namespaces in p_ns +void beginNamespaces(const QString &p_ns, QTextStream &p_out) +{ + if ( !p_ns.isEmpty() ) { + const QStringList nameSpaces = p_ns.split( "::" ); + foreach (const QString &ns, nameSpaces ) + p_out << "namespace " << ns << " {" << endl; + p_out << endl; + } +} + +// adds as many '}' lines to p_out as +// there are namespaces in p_ns +void endNamespaces(const QString &p_ns, QTextStream &p_out) +{ + if ( !p_ns.isEmpty() ) { + const int namespaceCount = p_ns.count( "::" ) + 1; + for ( int i = 0; i < namespaceCount; ++i ) + p_out << "}" << endl; + p_out << endl; + } +} + + +int main( int argc, char **argv ) +{ + QCoreApplication app(argc, argv); + + validNameRegexp = new QRegExp("[a-zA-Z_][a-zA-Z0-9_]*"); + + QString directoryName, inputFilename, codegenFilename; + parseArgs(app.arguments(), directoryName, inputFilename, codegenFilename); + + QString baseDir = directoryName; +#ifdef Q_OS_WIN + if (!baseDir.endsWith('/') && !baseDir.endsWith('\\')) +#else + if (!baseDir.endsWith('/')) +#endif + baseDir.append("/"); + + if (!codegenFilename.endsWith(QLatin1String(".kcfgc"))) + { + cerr << "Codegen options file must have extension .kcfgc" << endl; + return 1; + } + QString baseName = QFileInfo(codegenFilename).fileName(); + baseName = baseName.left(baseName.length() - 6); + + CfgConfig cfg = CfgConfig( codegenFilename ); + + QFile input( inputFilename ); + + QDomDocument doc; + QString errorMsg; + int errorRow; + int errorCol; + if ( !doc.setContent( &input, &errorMsg, &errorRow, &errorCol ) ) { + cerr << "Unable to load document." << endl; + cerr << "Parse error in " << inputFilename << ", line " << errorRow << ", col " << errorCol << ": " << errorMsg << endl; + return 1; + } + + QDomElement cfgElement = doc.documentElement(); + + if ( cfgElement.isNull() ) { + cerr << "No document in kcfg file" << endl; + return 1; + } + + QString cfgFileName; + bool cfgFileNameArg = false; + QList<Param> parameters; + QList<Signal> signalList; + QStringList includes; + bool hasSignals = false; + + QList<CfgEntry*> entries; + + for ( QDomElement e = cfgElement.firstChildElement(); !e.isNull(); e = e.nextSiblingElement() ) { + QString tag = e.tagName(); + + if ( tag == "include" ) { + QString includeFile = e.text(); + if (!includeFile.isEmpty()) + includes.append(includeFile); + + } else if ( tag == "kcfgfile" ) { + cfgFileName = e.attribute( "name" ); + cfgFileNameArg = e.attribute( "arg" ).toLower() == "true"; + for( QDomElement e2 = e.firstChildElement(); !e2.isNull(); e2 = e2.nextSiblingElement() ) { + if ( e2.tagName() == "parameter" ) { + Param p; + p.name = e2.attribute( "name" ); + p.type = e2.attribute( "type" ); + if (p.type.isEmpty()) + p.type = "String"; + parameters.append( p ); + } + } + + } else if ( tag == "group" ) { + QString group = e.attribute( "name" ); + if ( group.isEmpty() ) { + cerr << "Group without name" << endl; + return 1; + } + for( QDomElement e2 = e.firstChildElement(); !e2.isNull(); e2 = e2.nextSiblingElement() ) { + if ( e2.tagName() != "entry" ) continue; + CfgEntry *entry = parseEntry( group, e2, cfg ); + if ( entry ) entries.append( entry ); + else { + cerr << "Can not parse entry." << endl; + return 1; + } + } + } + else if ( tag == "signal" ) { + QString signalName = e.attribute( "name" ); + if ( signalName.isEmpty() ) { + cerr << "Signal without name." << endl; + return 1; + } + Signal theSignal; + theSignal.name = signalName; + + for( QDomElement e2 = e.firstChildElement(); !e2.isNull(); e2 = e2.nextSiblingElement() ) { + if ( e2.tagName() == "argument") { + SignalArguments argument; + argument.type = e2.attribute("type"); + if ( argument.type.isEmpty() ) { + cerr << "Signal argument without type." << endl; + return 1; + } + argument.variableName = e2.text(); + theSignal.arguments.append(argument); + } + else if( e2.tagName() == "label") { + theSignal.label = e2.text(); + } + } + signalList.append(theSignal); + } + } + + if ( cfg.className.isEmpty() ) { + cerr << "Class name missing" << endl; + return 1; + } + + if ( cfg.singleton && !parameters.isEmpty() ) { + cerr << "Singleton class can not have parameters" << endl; + return 1; + } + + if ( !cfgFileName.isEmpty() && cfgFileNameArg) + { + cerr << "Having both a fixed filename and a filename as argument is not possible." << endl; + return 1; + } + + if ( entries.isEmpty() ) { + cerr << "No entries." << endl; + } + +#if 0 + CfgEntry *cfg; + for( cfg = entries.first(); cfg; cfg = entries.next() ) { + cfg->dump(); + } +#endif + + hasSignals = !signalList.empty(); + QString headerFileName = baseName + ".h"; + QString implementationFileName = baseName + ".cpp"; + QString mocFileName = baseName + ".moc"; + QString cppPreamble; // code to be inserted at the beginnin of the cpp file, e.g. initialization of static values + + QFile header( baseDir + headerFileName ); + if ( !header.open( QIODevice::WriteOnly ) ) { + cerr << "Can not open '" << baseDir << headerFileName << "for writing." << endl; + return 1; + } + + QTextStream h( &header ); + + h << "// This file is generated by kconfig_compiler from " << QFileInfo(inputFilename).fileName() << "." << endl; + h << "// All changes you do to this file will be lost." << endl; + + h << "#ifndef " << ( !cfg.nameSpace.isEmpty() ? QString (QString(cfg.nameSpace).replace( "::", "_" ).toUpper() + '_') : "" ) + << cfg.className.toUpper() << "_H" << endl; + h << "#define " << ( !cfg.nameSpace.isEmpty() ? QString (QString(cfg.nameSpace).replace( "::", "_" ).toUpper() + '_') : "" ) + << cfg.className.toUpper() << "_H" << endl << endl; + + // Includes + QStringList::ConstIterator it; + for( it = cfg.headerIncludes.constBegin(); it != cfg.headerIncludes.constEnd(); ++it ) { + if ( (*it).startsWith('"') ) + h << "#include " << *it << endl; + else + h << "#include <" << *it << ">" << endl; + } + + if ( cfg.headerIncludes.count() > 0 ) h << endl; + + if ( !cfg.singleton && parameters.isEmpty() ) + h << "#include <qglobal.h>" << endl; + + if ( cfg.inherits=="KCoreConfigSkeleton" ) { + h << "#include <kcoreconfigskeleton.h>" << endl; + } else { + h << "#include <kconfigskeleton.h>" << endl; + } + + h << "#include <QCoreApplication>" << endl; + h << "#include <QDebug>" << endl << endl; + + // Includes + for( it = includes.constBegin(); it != includes.constEnd(); ++it ) { + if ( (*it).startsWith('"') ) + h << "#include " << *it << endl; + else + h << "#include <" << *it << ">" << endl; + } + + beginNamespaces(cfg.nameSpace, h); + + // Private class declaration + if ( cfg.dpointer ) + h << "class " << cfg.className << "Private;" << endl << endl; + + // Class declaration header + h << "class " << cfg.visibility << cfg.className << " : public " << cfg.inherits << endl; + + h << "{" << endl; + // Add Q_OBJECT macro if the config need signals. + if( hasSignals ) + h << " Q_OBJECT" << endl; + h << " public:" << endl; + + // enums + QList<CfgEntry*>::ConstIterator itEntry; + for( itEntry = entries.constBegin(); itEntry != entries.constEnd(); ++itEntry ) { + const CfgEntry::Choices &choices = (*itEntry)->choices(); + const QList<CfgEntry::Choice> chlist = choices.choices; + if ( !chlist.isEmpty() ) { + QStringList values; + QList<CfgEntry::Choice>::ConstIterator itChoice; + for( itChoice = chlist.constBegin(); itChoice != chlist.constEnd(); ++itChoice ) { + values.append( choices.prefix + (*itChoice).name ); + } + if ( choices.name().isEmpty() ) { + if ( cfg.globalEnums ) { + h << " enum " << enumName( (*itEntry)->name(), (*itEntry)->choices() ) << " { " << values.join( ", " ) << " };" << endl; + } else { + // Create an automatically named enum + h << " class " << enumName( (*itEntry)->name(), (*itEntry)->choices() ) << endl; + h << " {" << endl; + h << " public:" << endl; + h << " enum type { " << values.join( ", " ) << ", COUNT };" << endl; + h << " };" << endl; + } + } else if ( !choices.external() ) { + // Create a named enum + h << " enum " << enumName( (*itEntry)->name(), (*itEntry)->choices() ) << " { " << values.join( ", " ) << " };" << endl; + } + } + const QStringList values = (*itEntry)->paramValues(); + if ( !values.isEmpty() ) { + if ( cfg.globalEnums ) { + // ### FIXME!! + // make the following string table an index-based string search! + // ### + h << " enum " << enumName( (*itEntry)->param() ) << " { " << values.join( ", " ) << " };" << endl; + h << " static const char* const " << enumName( (*itEntry)->param() ) << "ToString[];" << endl; + cppPreamble += "const char* const " + cfg.className + "::" + enumName( (*itEntry)->param() ) + + "ToString[] = { \"" + values.join( "\", \"" ) + "\" };\n"; + } else { + h << " class " << enumName( (*itEntry)->param() ) << endl; + h << " {" << endl; + h << " public:" << endl; + h << " enum type { " << values.join( ", " ) << ", COUNT };" << endl; + h << " static const char* const enumToString[];" << endl; + h << " };" << endl; + cppPreamble += "const char* const " + cfg.className + "::" + enumName( (*itEntry)->param() ) + + "::enumToString[] = { \"" + values.join( "\", \"" ) + "\" };\n"; + } + } + } + if ( hasSignals ) { + h << "\n enum {" << endl; + unsigned val = 1; + QList<Signal>::ConstIterator it, itEnd = signalList.constEnd(); + for ( it = signalList.constBegin(); it != itEnd; val <<= 1) { + if ( !val ) { + cerr << "Too many signals to create unique bit masks" << endl; + exit(1); + } + Signal signal = *it; + h << " " << signalEnumName(signal.name) << " = 0x" << hex << val; + if ( ++it != itEnd ) + h << ","; + h << endl; + } + h << " };" << dec << endl; + } + h << endl; + // Constructor or singleton accessor + if ( !cfg.singleton ) { + h << " " << cfg.className << "("; + if (cfgFileNameArg) + { + if(cfg.forceStringFilename) + h << " const QString &cfgfilename" + << (parameters.isEmpty() ? " = QString()" : ", "); + else + h << " KSharedConfig::Ptr config" + << (parameters.isEmpty() ? " = KSharedConfig::openConfig()" : ", "); + } + for (QList<Param>::ConstIterator it = parameters.constBegin(); + it != parameters.constEnd(); ++it) + { + if (it != parameters.constBegin()) + h << ","; + h << " " << param((*it).type) << " " << (*it).name; + } + h << " );" << endl; + } else { + h << " static " << cfg.className << " *self();" << endl; + if (cfgFileNameArg) + { + h << " static void instance(const QString& cfgfilename);" << endl; + } + } + + // Destructor + h << " ~" << cfg.className << "();" << endl << endl; + + // global variables + if (cfg.staticAccessors) + This = "self()->"; + else + Const = " const"; + + for( itEntry = entries.constBegin(); itEntry != entries.constEnd(); ++itEntry ) { + QString n = (*itEntry)->name(); + QString t = (*itEntry)->type(); + + // Manipulator + if (cfg.allMutators || cfg.mutators.contains(n)) + { + h << " /**" << endl; + h << " Set " << (*itEntry)->label() << endl; + h << " */" << endl; + if (cfg.staticAccessors) + h << " static" << endl; + h << " void " << setFunction(n) << "( "; + if (!(*itEntry)->param().isEmpty()) + h << cppType((*itEntry)->paramType()) << " i, "; + if (cfg.useEnumTypes && t == "Enum") + h << enumType(*itEntry, cfg.globalEnums); + else + h << param( t ); + h << " v )"; + // function body inline only if not using dpointer + // for BC mode + if ( !cfg.dpointer ) + { + h << endl << " {" << endl; + h << indent(memberMutatorBody(*itEntry, cfg), 6 ); + h << " }" << endl; + } + else + { + h << ";" << endl; + } + } + h << endl; + // Accessor + h << " /**" << endl; + h << " Get " << (*itEntry)->label() << endl; + h << " */" << endl; + if (cfg.staticAccessors) + h << " static" << endl; + h << " "; + if (cfg.useEnumTypes && t == "Enum") + h << enumType(*itEntry, cfg.globalEnums); + else + h << cppType(t); + h << " " << getFunction(n) << "("; + if (!(*itEntry)->param().isEmpty()) + h << " " << cppType((*itEntry)->paramType()) <<" i "; + h << ")" << Const; + // function body inline only if not using dpointer + // for BC mode + if ( !cfg.dpointer ) + { + h << endl << " {" << endl; + h << indent(memberAccessorBody(*itEntry, cfg.globalEnums, cfg), 6 ); + h << " }" << endl; + } + else + { + h << ";" << endl; + } + + // Default value Accessor + if ((cfg.allDefaultGetters || cfg.defaultGetters.contains(n)) && !(*itEntry)->defaultValue().isEmpty()) { + h << endl; + h << " /**" << endl; + h << " Get " << (*itEntry)->label() << " default value" << endl; + h << " */" << endl; + if (cfg.staticAccessors) + h << " static" << endl; + h << " "; + if (cfg.useEnumTypes && t == "Enum") + h << enumType(*itEntry, cfg.globalEnums); + else + h << cppType(t); + h << " " << getDefaultFunction(n) << "("; + if ( !(*itEntry)->param().isEmpty() ) + h << " " << cppType( (*itEntry)->paramType() ) <<" i "; + h << ")" << Const << endl; + h << " {" << endl; + h << " return "; + if (cfg.useEnumTypes && t == "Enum") + h << "static_cast<" << enumType(*itEntry, cfg.globalEnums) << ">("; + h << getDefaultFunction(n) << "_helper("; + if ( !(*itEntry)->param().isEmpty() ) + h << " i "; + h << ")"; + if (cfg.useEnumTypes && t == "Enum") + h << ")"; + h << ";" << endl; + h << " }" << endl; + } + + // Item accessor + if ( cfg.itemAccessors ) { + h << endl; + h << " /**" << endl; + h << " Get Item object corresponding to " << n << "()" + << endl; + h << " */" << endl; + h << " Item" << itemType( (*itEntry)->type() ) << " *" + << getFunction( n ) << "Item("; + if (!(*itEntry)->param().isEmpty()) { + h << " " << cppType((*itEntry)->paramType()) << " i "; + } + h << ")"; + if ( !cfg.dpointer ) + { + h << endl << " {" << endl; + h << indent( itemAccessorBody((*itEntry), cfg), 6); + h << " }" << endl; + } + else + { + h << ";" << endl; + } + } + + h << endl; + } + + + // Signal definition. + if( hasSignals ) { + h << endl; + h << " Q_SIGNALS:"; + Q_FOREACH(const Signal &signal, signalList) { + h << endl; + if ( !signal.label.isEmpty() ) { + h << " /**" << endl; + h << " " << signal.label << endl; + h << " */" << endl; + } + h << " void " << signal.name << "("; + QList<SignalArguments>::ConstIterator it, itEnd = signal.arguments.constEnd(); + for ( it = signal.arguments.constBegin(); it != itEnd; ) { + SignalArguments argument = *it; + QString type = param(argument.type); + if ( cfg.useEnumTypes && argument.type == "Enum" ) { + for ( int i = 0, end = entries.count(); i < end; ++i ) { + if ( entries[i]->name() == argument.variableName ) { + type = enumType(entries[i], cfg.globalEnums); + break; + } + } + } + h << type << " " << argument.variableName; + if ( ++it != itEnd ) { + h << ", "; + } + } + h << ");" << endl; + } + h << endl; + } + + h << " protected:" << endl; + + // Private constructor for singleton + if ( cfg.singleton ) { + h << " " << cfg.className << "("; + if ( cfgFileNameArg ) + h << "const QString& arg"; + h << ");" << endl; + h << " friend class " << cfg.className << "Helper;" << endl << endl; + } + + if ( hasSignals ) { + h << " virtual bool usrWriteConfig();" << endl; + } + + // Member variables + if ( !cfg.memberVariables.isEmpty() && cfg.memberVariables != "private" && cfg.memberVariables != "dpointer") { + h << " " << cfg.memberVariables << ":" << endl; + } + + // Class Parameters + for (QList<Param>::ConstIterator it = parameters.constBegin(); + it != parameters.constEnd(); ++it) + { + h << " " << cppType((*it).type) << " mParam" << (*it).name << ";" << endl; + } + + if ( cfg.memberVariables != "dpointer" ) + { + QString group; + for( itEntry = entries.constBegin(); itEntry != entries.constEnd(); ++itEntry ) { + if ( (*itEntry)->group() != group ) { + group = (*itEntry)->group(); + h << endl; + h << " // " << group << endl; + } + h << " " << cppType( (*itEntry)->type() ) << " " << varName( (*itEntry)->name(), cfg ); + if ( !(*itEntry)->param().isEmpty() ) + { + h << QString("[%1]").arg( (*itEntry)->paramMax()+1 ); + } + h << ";" << endl; + + if ( cfg.allDefaultGetters || cfg.defaultGetters.contains((*itEntry)->name()) ) + { + h << " "; + if (cfg.staticAccessors) + h << "static "; + h << cppType((*itEntry)->type()) << " " << getDefaultFunction((*itEntry)->name()) << "_helper("; + if ( !(*itEntry)->param().isEmpty() ) + h << " " << cppType( (*itEntry)->paramType() ) <<" i "; + h << ")" << Const << ";" << endl; + } + } + + h << endl << " private:" << endl; + if ( cfg.itemAccessors ) { + for( itEntry = entries.constBegin(); itEntry != entries.constEnd(); ++itEntry ) { + h << " Item" << itemType( (*itEntry)->type() ) << " *" << itemVar( *itEntry, cfg ); + if ( !(*itEntry)->param().isEmpty() ) h << QString("[%1]").arg( (*itEntry)->paramMax()+1 ); + h << ";" << endl; + } + } + if ( hasSignals ) + h << " uint " << varName("settingsChanged", cfg) << ";" << endl; + + } + else + { + // use a private class for both member variables and items + h << " private:" << endl; + for( itEntry = entries.constBegin(); itEntry != entries.constEnd(); ++itEntry ) { + if ( cfg.allDefaultGetters || cfg.defaultGetters.contains((*itEntry)->name()) ) { + h << " "; + if (cfg.staticAccessors) + h << "static "; + h << cppType((*itEntry)->type()) << " " << getDefaultFunction((*itEntry)->name()) << "_helper("; + if ( !(*itEntry)->param().isEmpty() ) + h << " " << cppType( (*itEntry)->paramType() ) <<" i "; + h << ")" << Const << ";" << endl; + } + } + h << " " + cfg.className + "Private *d;" << endl; + } + + if (cfg.customAddons) + { + h << " // Include custom additions" << endl; + h << " #include \"" << filenameOnly(baseName) << "_addons.h\"" <<endl; + } + + h << "};" << endl << endl; + + endNamespaces(cfg.nameSpace, h); + + h << "#endif" << endl << endl; + + + header.close(); + + QFile implementation( baseDir + implementationFileName ); + if ( !implementation.open( QIODevice::WriteOnly ) ) { + cerr << "Can not open '" << implementationFileName << "for writing." + << endl; + return 1; + } + + QTextStream cpp( &implementation ); + + + cpp << "// This file is generated by kconfig_compiler from " << QFileInfo(inputFilename).fileName() << "." << endl; + cpp << "// All changes you do to this file will be lost." << endl << endl; + + cpp << "#include \"" << headerFileName << "\"" << endl << endl; + + for( it = cfg.sourceIncludes.constBegin(); it != cfg.sourceIncludes.constEnd(); ++it ) { + if ( (*it).startsWith('"') ) + cpp << "#include " << *it << endl; + else + cpp << "#include <" << *it << ">" << endl; + } + + if ( cfg.sourceIncludes.count() > 0 ) cpp << endl; + + if ( cfg.setUserTexts && cfg.translationSystem==CfgConfig::KdeTranslation) + cpp << "#include <klocalizedstring.h>" << endl << endl; + + // Header required by singleton implementation + if ( cfg.singleton ) + cpp << "#include <qglobal.h>" << endl << "#include <QtCore/QFile>" << endl << endl; + if ( cfg.singleton && cfgFileNameArg ) + cpp << "#include <QDebug>" << endl << endl; + + if ( !cfg.nameSpace.isEmpty() ) + cpp << "using namespace " << cfg.nameSpace << ";" << endl << endl; + + QString group; + + // private class implementation + if ( cfg.dpointer ) + { + beginNamespaces(cfg.nameSpace, cpp); + cpp << "class " << cfg.className << "Private" << endl; + cpp << "{" << endl; + cpp << " public:" << endl; + for( itEntry = entries.constBegin(); itEntry != entries.constEnd(); ++itEntry ) { + if ( (*itEntry)->group() != group ) { + group = (*itEntry)->group(); + cpp << endl; + cpp << " // " << group << endl; + } + cpp << " " << cppType( (*itEntry)->type() ) << " " << varName( (*itEntry)->name(), cfg ); + if ( !(*itEntry)->param().isEmpty() ) + { + cpp << QString("[%1]").arg( (*itEntry)->paramMax()+1 ); + } + cpp << ";" << endl; + } + cpp << endl << " // items" << endl; + for( itEntry = entries.constBegin(); itEntry != entries.constEnd(); ++itEntry ) { + cpp << " "+cfg.inherits+"::Item" << itemType( (*itEntry)->type() ) << " *" << itemVar( *itEntry, cfg ); + if ( !(*itEntry)->param().isEmpty() ) cpp << QString("[%1]").arg( (*itEntry)->paramMax()+1 ); + cpp << ";" << endl; + } + if ( hasSignals ) { + cpp << " uint " << varName("settingsChanged", cfg) << ";" << endl; + } + + cpp << "};" << endl << endl; + endNamespaces(cfg.nameSpace, cpp); + } + + // Singleton implementation + if ( cfg.singleton ) { + beginNamespaces(cfg.nameSpace, cpp); + cpp << "class " << cfg.className << "Helper" << endl; + cpp << '{' << endl; + cpp << " public:" << endl; + cpp << " " << cfg.className << "Helper() : q(0) {}" << endl; + cpp << " ~" << cfg.className << "Helper() { delete q; }" << endl; + cpp << " " << cfg.className << " *q;" << endl; + cpp << "};" << endl; + endNamespaces(cfg.nameSpace, cpp); + cpp << "Q_GLOBAL_STATIC(" << cfg.className << "Helper, s_global" << cfg.className << ")" << endl; + + cpp << cfg.className << " *" << cfg.className << "::self()" << endl; + cpp << "{" << endl; + if ( cfgFileNameArg ) { + cpp << " if (!s_global" << cfg.className << "()->q)" << endl; + cpp << " qFatal(\"you need to call " << cfg.className << "::instance before using\");" << endl; + } else { + cpp << " if (!s_global" << cfg.className << "()->q) {" << endl; + cpp << " new " << cfg.className << ';' << endl; + cpp << " s_global" << cfg.className << "()->q->readConfig();" << endl; + cpp << " }" << endl << endl; + } + cpp << " return s_global" << cfg.className << "()->q;" << endl; + cpp << "}" << endl << endl; + + if ( cfgFileNameArg ) { + cpp << "void " << cfg.className << "::instance(const QString& cfgfilename)" << endl; + cpp << "{" << endl; + cpp << " if (s_global" << cfg.className << "()->q) {" << endl; + cpp << " qDebug() << \"" << cfg.className << "::instance called after the first use - ignoring\";" << endl; + cpp << " return;" << endl; + cpp << " }" << endl; + cpp << " new " << cfg.className << "(cfgfilename);" << endl; + cpp << " s_global" << cfg.className << "()->q->readConfig();" << endl; + cpp << "}" << endl << endl; + } + } + + if ( !cppPreamble.isEmpty() ) + cpp << cppPreamble << endl; + + // Constructor + cpp << cfg.className << "::" << cfg.className << "( "; + if ( cfgFileNameArg ) { + if ( !cfg.singleton && ! cfg.forceStringFilename) + cpp << " KSharedConfig::Ptr config"; + else + cpp << " const QString& config"; + cpp << (parameters.isEmpty() ? " " : ", "); + } + + for (QList<Param>::ConstIterator it = parameters.constBegin(); + it != parameters.constEnd(); ++it) + { + if (it != parameters.constBegin()) + cpp << ","; + cpp << " " << param((*it).type) << " " << (*it).name; + } + cpp << " )" << endl; + + cpp << " : " << cfg.inherits << "("; + if ( !cfgFileName.isEmpty() ) cpp << " QLatin1String( \"" << cfgFileName << "\" "; + if ( cfgFileNameArg ) cpp << " config "; + if ( !cfgFileName.isEmpty() ) cpp << ") "; + cpp << ")" << endl; + + // Store parameters + for (QList<Param>::ConstIterator it = parameters.constBegin(); + it != parameters.constEnd(); ++it) + { + cpp << " , mParam" << (*it).name << "(" << (*it).name << ")" << endl; + } + + if ( hasSignals && !cfg.dpointer ) + cpp << " , " << varName("settingsChanged", cfg) << "(0)" << endl; + + cpp << "{" << endl; + + if (cfg.dpointer) + { + cpp << " d = new " + cfg.className + "Private;" << endl; + if (hasSignals) + cpp << " " << varPath("settingsChanged", cfg) << " = 0;" << endl; + } + // Needed in case the singleton class is used as baseclass for + // another singleton. + if (cfg.singleton) { + cpp << " Q_ASSERT(!s_global" << cfg.className << "()->q);" << endl; + cpp << " s_global" << cfg.className << "()->q = this;" << endl; + } + + group.clear(); + + for( itEntry = entries.constBegin(); itEntry != entries.constEnd(); ++itEntry ) { + if ( (*itEntry)->group() != group ) { + if ( !group.isEmpty() ) cpp << endl; + group = (*itEntry)->group(); + cpp << " setCurrentGroup( " << paramString(group, parameters) << " );" << endl << endl; + } + + QString key = paramString( (*itEntry)->key(), parameters ); + if ( !(*itEntry)->code().isEmpty() ) { + cpp << (*itEntry)->code() << endl; + } + if ( (*itEntry)->type() == "Enum" ) { + cpp << " QList<"+cfg.inherits+"::ItemEnum::Choice> values" + << (*itEntry)->name() << ";" << endl; + const QList<CfgEntry::Choice> choices = (*itEntry)->choices().choices; + QList<CfgEntry::Choice>::ConstIterator it; + for( it = choices.constBegin(); it != choices.constEnd(); ++it ) { + cpp << " {" << endl; + cpp << " "+cfg.inherits+"::ItemEnum::Choice choice;" << endl; + cpp << " choice.name = QLatin1String(\"" << (*it).name << "\");" << endl; + if ( cfg.setUserTexts ) { + if ( !(*it).label.isEmpty() ) { + cpp << " choice.label = " + << translatedString(cfg, (*it).label, (*it).context) + << ";" << endl; + } + if ( !(*it).toolTip.isEmpty() ) { + cpp << " choice.toolTip = " + << translatedString(cfg, (*it).toolTip, (*it).context) + << ";" << endl; + } + if ( !(*it).whatsThis.isEmpty() ) { + cpp << " choice.whatsThis = " + << translatedString(cfg, (*it).whatsThis, (*it).context) + << ";" << endl; + } + } + cpp << " values" << (*itEntry)->name() << ".append( choice );" << endl; + cpp << " }" << endl; + } + } + + if (!cfg.dpointer) + cpp << itemDeclaration( *itEntry, cfg ); + + if ( (*itEntry)->param().isEmpty() ) + { + // Normal case + cpp << " " << itemPath( *itEntry, cfg ) << " = " + << newItem( (*itEntry)->type(), (*itEntry)->name(), key, (*itEntry)->defaultValue(), cfg ) << endl; + + if ( !(*itEntry)->minValue().isEmpty() ) + cpp << " " << itemPath( *itEntry, cfg ) << "->setMinValue(" << (*itEntry)->minValue() << ");" << endl; + if ( !(*itEntry)->maxValue().isEmpty() ) + cpp << " " << itemPath( *itEntry, cfg ) << "->setMaxValue(" << (*itEntry)->maxValue() << ");" << endl; + + if ( cfg.setUserTexts ) + cpp << userTextsFunctions( (*itEntry), cfg ); + + cpp << " addItem( " << itemPath( *itEntry, cfg ); + QString quotedName = (*itEntry)->name(); + addQuotes( quotedName ); + if ( quotedName != key ) cpp << ", QLatin1String( \"" << (*itEntry)->name() << "\" )"; + cpp << " );" << endl; + } + else + { + // Indexed + for(int i = 0; i <= (*itEntry)->paramMax(); i++) + { + QString defaultStr; + QString itemVarStr(itemPath( *itEntry, cfg )+QString("[%1]").arg(i)); + + if ( !(*itEntry)->paramDefaultValue(i).isEmpty() ) + defaultStr = (*itEntry)->paramDefaultValue(i); + else if ( !(*itEntry)->defaultValue().isEmpty() ) + defaultStr = paramString( (*itEntry)->defaultValue(), (*itEntry), i ); + else + defaultStr = defaultValue( (*itEntry)->type() ); + + cpp << " " << itemVarStr << " = " + << newItem( (*itEntry)->type(), (*itEntry)->name(), paramString(key, *itEntry, i), defaultStr,cfg, QString("[%1]").arg(i) ) + << endl; + + if ( cfg.setUserTexts ) + cpp << userTextsFunctions( *itEntry, cfg, itemVarStr, (*itEntry)->paramName() ); + + // Make mutators for enum parameters work by adding them with $(..) replaced by the + // param name. The check for isImmutable in the set* functions doesn't have the param + // name available, just the corresponding enum value (int), so we need to store the + // param names in a separate static list!. + cpp << " addItem( " << itemVarStr << ", QLatin1String( \""; + if ( (*itEntry)->paramType()=="Enum" ) + cpp << (*itEntry)->paramName().replace( "$("+(*itEntry)->param()+')', "%1").arg((*itEntry)->paramValues()[i] ); + else + cpp << (*itEntry)->paramName().replace( "$("+(*itEntry)->param()+')', "%1").arg(i); + cpp << "\" ) );" << endl; + } + } + } + + cpp << "}" << endl << endl; + + if (cfg.dpointer) + { + // setters and getters go in Cpp if in dpointer mode + for( itEntry = entries.constBegin(); itEntry != entries.constEnd(); ++itEntry ) { + QString n = (*itEntry)->name(); + QString t = (*itEntry)->type(); + + // Manipulator + if (cfg.allMutators || cfg.mutators.contains(n)) + { + cpp << "void " << setFunction(n, cfg.className) << "( "; + if ( !(*itEntry)->param().isEmpty() ) + cpp << cppType( (*itEntry)->paramType() ) << " i, "; + if (cfg.useEnumTypes && t == "Enum") + cpp << enumType(*itEntry, cfg.globalEnums); + else + cpp << param( t ); + cpp << " v )" << endl; + // function body inline only if not using dpointer + // for BC mode + cpp << "{" << endl; + cpp << indent(memberMutatorBody( *itEntry, cfg ), 6); + cpp << "}" << endl << endl; + } + + // Accessor + if (cfg.useEnumTypes && t == "Enum") + cpp << enumType(*itEntry, cfg.globalEnums); + else + cpp << cppType(t); + cpp << " " << getFunction(n, cfg.className) << "("; + if ( !(*itEntry)->param().isEmpty() ) + cpp << " " << cppType( (*itEntry)->paramType() ) <<" i "; + cpp << ")" << Const << endl; + // function body inline only if not using dpointer + // for BC mode + cpp << "{" << endl; + cpp << indent(memberAccessorBody( *itEntry, cfg.globalEnums, cfg ), 2); + cpp << "}" << endl << endl; + + // Default value Accessor -- written by the loop below + + // Item accessor + if ( cfg.itemAccessors ) + { + cpp << endl; + cpp << cfg.inherits+"::Item" << itemType( (*itEntry)->type() ) << " *" + << getFunction( n, cfg.className ) << "Item("; + if ( !(*itEntry)->param().isEmpty() ) { + cpp << " " << cppType( (*itEntry)->paramType() ) << " i "; + } + cpp << ")" << endl; + cpp << "{" << endl; + cpp << indent(itemAccessorBody( *itEntry, cfg ), 2); + cpp << "}" << endl; + } + + cpp << endl; + } + } + + // default value getters always go in Cpp + for( itEntry = entries.constBegin(); itEntry != entries.constEnd(); ++itEntry ) { + QString n = (*itEntry)->name(); + QString t = (*itEntry)->type(); + + // Default value Accessor, as "helper" function + if (( cfg.allDefaultGetters || cfg.defaultGetters.contains(n) ) && !(*itEntry)->defaultValue().isEmpty() ) { + cpp << cppType(t) << " " << getDefaultFunction(n, cfg.className) << "_helper("; + if ( !(*itEntry)->param().isEmpty() ) + cpp << " " << cppType( (*itEntry)->paramType() ) <<" i "; + cpp << ")" << Const << endl; + cpp << "{" << endl; + cpp << memberGetDefaultBody(*itEntry) << endl; + cpp << "}" << endl << endl; + } + } + + // Destructor + cpp << cfg.className << "::~" << cfg.className << "()" << endl; + cpp << "{" << endl; + if ( cfg.singleton ) { + if ( cfg.dpointer ) + cpp << " delete d;" << endl; + cpp << " s_global" << cfg.className << "()->q = 0;" << endl; + } + cpp << "}" << endl << endl; + + if ( hasSignals ) { + cpp << "bool " << cfg.className << "::" << "usrWriteConfig()" << endl; + cpp << "{" << endl; + cpp << " const bool res = " << cfg.inherits << "::usrWriteConfig();" << endl; + cpp << " if (!res) return false;" << endl << endl; + Q_FOREACH(const Signal &signal, signalList) { + cpp << " if ( " << varPath("settingsChanged", cfg) << " & " << signalEnumName(signal.name) << " ) " << endl; + cpp << " emit " << signal.name << "("; + QList<SignalArguments>::ConstIterator it, itEnd = signal.arguments.constEnd(); + for ( it = signal.arguments.constBegin(); it != itEnd; ) { + SignalArguments argument = *it; + bool cast = false; + if ( cfg.useEnumTypes && argument.type == "Enum" ) { + for ( int i = 0, end = entries.count(); i < end; ++i ) { + if ( entries[i]->name() == argument.variableName ) { + cpp << "static_cast<" << enumType(entries[i], cfg.globalEnums) << ">("; + cast = true; + break; + } + } + } + cpp << varPath(argument.variableName, cfg); + if ( cast ) + cpp << ")"; + if ( ++it != itEnd ) + cpp << ", "; + } + cpp << ");" << endl << endl; + } + cpp << " " << varPath("settingsChanged", cfg) << " = 0;" << endl; + cpp << " return true;" << endl; + cpp << "}" << endl; + } + + // Add includemoc if they are signals defined. + if( hasSignals ) { + cpp << endl; + cpp << "#include \"" << mocFileName << "\"" << endl; + cpp << endl; + } + + // clear entries list + qDeleteAll( entries ); + + implementation.close(); +} |