commit cd4f0df87cd373f0fe8418787bb8b1e293383670 Author: Andrew Lee (李健秋) Date: Wed Aug 12 03:15:13 2015 +0800 Adding upstream version 0.9.0. Signed-off-by: Andrew Lee (李健秋) diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..378eac2 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +build diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..56b845a --- /dev/null +++ b/AUTHORS @@ -0,0 +1,13 @@ +Upstream Authors: + LXQt team: http://lxqt.org + Razor team: http://razor-qt.org + +Copyright: + Copyright (c) 2010-2012 Razor team + Copyright (c) 2012-2014 LXQt team + +License: GPL-2 and LGPL-2.1+ +The full text of the licenses can be found in the 'COPYING' file. + +The lxqt-config-cursor component is based on the "qt-xcurtheme" project +and is licensed under GPL 2. diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..41ac0cb --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,44 @@ +cmake_minimum_required(VERSION 2.8.11) + +project(lxqt-config) + +option(UPDATE_TRANSLATIONS "Update source translation translations/*.ts files" OFF) + +# Set default installation paths +set(LIB_INSTALL_DIR "lib${LIB_SUFFIX}" CACHE PATH "Installation path for libraries") + +set(CMAKE_INCLUDE_CURRENT_DIR ON) +set(CMAKE_POSITION_INDEPENDENT_CODE ON) +set(CMAKE_AUTOMOC ON) + +find_package(Qt5Widgets REQUIRED QUIET) +find_package(Qt5DBus REQUIRED QUIET) +find_package(Qt5Xml REQUIRED QUIET) +find_package(Qt5Concurrent REQUIRED QUIET) +find_package(Qt5X11Extras REQUIRED QUIET) +find_package(Qt5LinguistTools REQUIRED QUIET) +find_package(lxqt REQUIRED QUIET) +find_package(qt5xdg REQUIRED) +find_package(KF5WindowSystem REQUIRED QUIET) + +include(${LXQT_USE_FILE}) +include(${QTXDG_USE_FILE}) + +include(LXQtTranslate) + +add_subdirectory(src) +add_subdirectory(liblxqt-config-cursor) +add_subdirectory(lxqt-config-input) +add_subdirectory(lxqt-config-file-associations) +add_subdirectory(lxqt-config-appearance) +add_subdirectory(lxqt-config-monitor) + +# building tarball with CPack ------------------------------------------------- +include(InstallRequiredSystemLibraries) +set(CPACK_PACKAGE_VERSION_MAJOR ${LXQT_MAJOR_VERSION}) +set(CPACK_PACKAGE_VERSION_MINOR ${LXQT_MINOR_VERSION}) +set(CPACK_PACKAGE_VERSION_PATCH ${LXQT_PATCH_VERSION}) +set(CPACK_GENERATOR TBZ2) +set(CPACK_SOURCE_GENERATOR TBZ2) +set(CPACK_SOURCE_IGNORE_FILES /build/;.gitignore;.*~;.git;.kdev4;temp) +include(CPack) diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..a8dd823 --- /dev/null +++ b/COPYING @@ -0,0 +1,461 @@ + + 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 diff --git a/liblxqt-config-cursor/CMakeLists.txt b/liblxqt-config-cursor/CMakeLists.txt new file mode 100644 index 0000000..1e6012e --- /dev/null +++ b/liblxqt-config-cursor/CMakeLists.txt @@ -0,0 +1,89 @@ +project(lxqt-config-cursor) +find_package(X11 REQUIRED) + +find_package(PkgConfig REQUIRED) + +pkg_check_modules(XCB REQUIRED xcb) +include_directories(${XCB_INCLUDE_DIRS}) +link_libraries(${XCB_LIBRARIES}) + +include_directories ( + "${CMAKE_CURRENT_BINARY_DIR}" + ${X11_INCLUDE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/xcr +) + +set(lxqt-config-cursor_HDRS + thememodel.h + previewwidget.h + itemdelegate.h + selectwnd.h + warninglabel.h +) + +set(lxqt-config-cursor_SRCS + crtheme.cpp + selectwnd.cpp + xcr/xcrimg.cpp + xcr/xcrxcur.cpp + xcr/xcrthemefx.cpp + xcr/xcrtheme.cpp + xcr/xcrthemexp.cpp + cfgfile.cpp + previewwidget.cpp + itemdelegate.cpp + thememodel.cpp + warninglabel.cpp +) + +set(lxqt-config-cursor_UIS + ui/selectwnd.ui + ui/warninglabel.ui +) + +find_package(ZLIB REQUIRED) + +qt5_wrap_ui(lxqt-config-cursor_CXX ${lxqt-config-cursor_UIS}) + +# Translations ********************************** +lxqt_translate_ts(QM_FILES + UPDATE_TRANSLATIONS + ${UPDATE_TRANSLATIONS} + SOURCES + ${lxqt-config-cursor_HDRS} + ${lxqt-config-cursor_SRCS} + ${lxqt-config-cursor_UIS} + INSTALL_DIR + "${LXQT_TRANSLATIONS_DIR}/${PROJECT_NAME}" +) + +lxqt_app_translation_loader(lxqt-config-cursor_QM_LOADER ${PROJECT_NAME}) + +#************************************************ + +add_library(lxqt-config-cursor + SHARED + ${lxqt-config-cursor_SRCS} + ${lxqt-config-cursor_CXX} + ${lxqt-config-cursor_MOCS} + ${DESKTOP_FILES} + ${QM_FILES} + ${lxqt-config-cursor_QM_LOADER} +) + +target_link_libraries(lxqt-config-cursor + Qt5::X11Extras + Qt5::DBus + Qt5::Xml + ${X11_X11_LIB} + ${X11_Xcursor_LIB} + ${LXQT_LIBRARIES} + ${QTXDG_LIBRARIES} + ${ZLIB_LIBRARY} + ${X11_Xfixes_LIB} +) +# not needed probably ${X11_Xfixes_LIB}) + +install(TARGETS lxqt-config-cursor DESTINATION ${LIB_INSTALL_DIR}) +install(FILES ${DESKTOP_FILES} DESTINATION "${CMAKE_INSTALL_PREFIX}/share/applications") diff --git a/liblxqt-config-cursor/cfgfile.cpp b/liblxqt-config-cursor/cfgfile.cpp new file mode 100644 index 0000000..6d790a1 --- /dev/null +++ b/liblxqt-config-cursor/cfgfile.cpp @@ -0,0 +1,122 @@ +/* coded by Ketmar // Vampire Avalon (psyc://ketmar.no-ip.org/~Ketmar) + * (c)DWTFYW + * + * This program is free software. It comes without any warranty, to + * the extent permitted by applicable law. You can redistribute it + * and/or modify it under the terms of the Do What The Fuck You Want + * To Public License, Version 2, as published by Sam Hocevar. See + * http://sam.zoy.org/wtfpl/COPYING for more details. + */ +#include "cfgfile.h" + +#include +#include +#include +#include + +QMultiMap loadCfgFile(const QString &fname, bool forceLoCase) +{ + QMultiMap res; + QFile fl(fname); + if (fl.open(QIODevice::ReadOnly)) + { + QTextStream stream; + stream.setDevice(&fl); + stream.setCodec("UTF-8"); + QString curPath = "/"; + while (1) + { + QString s = stream.readLine(); + if (s.isNull()) break; + s = s.trimmed(); + if (s.isEmpty() || s[0] == '#' || s[0] == ';') continue; + if (s[0] == '[') + { + // new path + int len = s.length()-1; + if (s[len] == ']') len--; + s = s.mid(1, len).simplified(); + s += '/'; + curPath = s; + continue; + } + int eqp = s.indexOf('='); + if (eqp < 0) continue; // invalid entry + QString name = s.left(eqp).simplified(); + QString value = s.mid(eqp+1).simplified(); + if (name.isEmpty()) continue; // invalid entry + name.prepend(curPath); + if (forceLoCase) name = name.toLower(); + res.insert(name, value); + } + fl.close(); + } + return res; +} + +void fixXDefaults(const QString &themeName) +{ + QStringList lst; + { + QFile fl(QDir::home().path()+"/.Xdefaults"); + if (fl.open(QIODevice::ReadOnly)) + { + QTextStream stream; + stream.setDevice(&fl); + while (1) + { + QString s = stream.readLine(); + if (s.isNull()) + break; + // if the line does not contain Xcursor?theme, save it to a list + if (!(s.startsWith(QLatin1String("Xcursor")) && s.midRef(8).startsWith(QLatin1String("theme")))) + lst << s; + } + fl.close(); + } + } + while (lst.size() > 0) + { + QString s(lst[lst.size()-1]); + if (!s.trimmed().isEmpty()) break; + lst.removeAt(lst.size()-1); + } + { + //QByteArray ba(themeName.toUtf8()); + QFile fl(QDir::home().path()+"/.Xdefaults"); + if (fl.open(QIODevice::WriteOnly)) + { + QTextStream stream; + stream.setDevice(&fl); + foreach (const QString &s, lst) + { + stream << s << "\n"; + } + stream << "\nXcursor.theme: " << themeName << "\n"; + fl.close(); + } + } +} + +const QString findDefaultTheme() +{ + QString res = "default"; + QFile fl(QDir::home().path()+"/.Xdefaults"); + if (fl.open(QIODevice::ReadOnly)) + { + QTextStream stream; + stream.setDevice(&fl); + while (1) + { + QString s = stream.readLine(); + if (s.isNull()) break; + if (!s.startsWith("Xcursor.theme:")) continue; + s.remove(0, 14); + s = s.trimmed(); + if (s.isEmpty()) s = "default"; + res = s; + } + fl.close(); + } + return res; +} diff --git a/liblxqt-config-cursor/cfgfile.h b/liblxqt-config-cursor/cfgfile.h new file mode 100644 index 0000000..a6d7528 --- /dev/null +++ b/liblxqt-config-cursor/cfgfile.h @@ -0,0 +1,20 @@ +/* coded by Ketmar // Vampire Avalon (psyc://ketmar.no-ip.org/~Ketmar) + * (c)DWTFYW + * + * This program is free software. It comes without any warranty, to + * the extent permitted by applicable law. You can redistribute it + * and/or modify it under the terms of the Do What The Fuck You Want + * To Public License, Version 2, as published by Sam Hocevar. See + * http://sam.zoy.org/wtfpl/COPYING for more details. + */ +#ifndef CFGFILE_H +#define CFGFILE_H + +#include +#include + +QMultiMap loadCfgFile(const QString &fname, bool forceLoCase=false); +void fixXDefaults(const QString &themeName); +const QString findDefaultTheme(); + +#endif diff --git a/liblxqt-config-cursor/crtheme.cpp b/liblxqt-config-cursor/crtheme.cpp new file mode 100644 index 0000000..1b6d565 --- /dev/null +++ b/liblxqt-config-cursor/crtheme.cpp @@ -0,0 +1,276 @@ +/* Copyright © 2006-2007 Fredrik Höglund + * (c)GPL2 (c)GPL3 + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License version 2 or at your option version 3 as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +/* + * additional code: Ketmar // Vampire Avalon (psyc://ketmar.no-ip.org/~Ketmar) + */ +#include + +#include "crtheme.h" + +#include +#include + +#include "cfgfile.h" + +#include +#include +#include + +// Static variable holding alternative names for some cursors +static QHash alternatives; + +/////////////////////////////////////////////////////////////////////////////// +XCursorThemeData::XCursorThemeData(const QDir &aDir) +{ + mHidden = false; + // parse configs, etc + mPath = aDir.path(); + setName(aDir.dirName()); + if (aDir.exists("index.theme")) parseIndexFile(); + if (mDescription.isEmpty()) mDescription = "no description"; + if (mTitle.isEmpty()) mTitle = mName; +} + +void XCursorThemeData::parseIndexFile() +{ + QMultiMap cfg = loadCfgFile(mPath+"/index.theme", true); + if (cfg.contains("icon theme/name")) mTitle = cfg.values("icon theme/name").at(0).trimmed(); + if (cfg.contains("icon theme/comment")) mDescription = cfg.values("icon theme/comment").at(0).trimmed(); + if (cfg.contains("icon theme/example")) mSample = cfg.values("icon theme/example").at(0).trimmed(); + if (cfg.contains("icon theme/hidden")) + { + QString hiddenValue = cfg.values("icon theme/hidden").at(0).toLower(); + mHidden = hiddenValue=="false" ? false : true; + } + if (cfg.contains("icon theme/inherits")) + { + QStringList i = cfg.values("icon theme/inherits"), res; + for (int f = i.size()-1; f >= 0; f--) res << i.at(f).trimmed(); + } + if (mDescription.startsWith("- Converted by")) mDescription.remove(0, 2); +} + +QString XCursorThemeData::findAlternative(const QString &name) const +{ + if (alternatives.isEmpty()) + { + alternatives.reserve(18); + + // Qt uses non-standard names for some core cursors. + // If Xcursor fails to load the cursor, Qt creates it with the correct name using the + // core protcol instead (which in turn calls Xcursor). We emulate that process here. + // Note that there's a core cursor called cross, but it's not the one Qt expects. + alternatives.insert("cross", "crosshair"); + alternatives.insert("up_arrow", "center_ptr"); + alternatives.insert("wait", "watch"); + alternatives.insert("ibeam", "xterm"); + alternatives.insert("size_all", "fleur"); + alternatives.insert("pointing_hand", "hand2"); + + // Precomputed MD5 hashes for the hardcoded bitmap cursors in Qt and KDE. + // Note that the MD5 hash for left_ptr_watch is for the KDE version of that cursor. + alternatives.insert("size_ver", "00008160000006810000408080010102"); + alternatives.insert("size_hor", "028006030e0e7ebffc7f7070c0600140"); + alternatives.insert("size_bdiag", "c7088f0f3e6c8088236ef8e1e3e70000"); + alternatives.insert("size_fdiag", "fcf1c3c7cd4491d801f1e1c78f100000"); + alternatives.insert("whats_this", "d9ce0ab605698f320427677b458ad60b"); + alternatives.insert("split_h", "14fef782d02440884392942c11205230"); + alternatives.insert("split_v", "2870a09082c103050810ffdffffe0204"); + alternatives.insert("forbidden", "03b6e0fcb3499374a867c041f52298f0"); + alternatives.insert("left_ptr_watch", "3ecb610c1bf2410f44200f48c40d3599"); + alternatives.insert("hand2", "e29285e634086352946a0e7090d73106"); + alternatives.insert("openhand", "9141b49c8149039304290b508d208c40"); + alternatives.insert("closedhand", "05e88622050804100c20044008402080"); + } + + return alternatives.value(name, QString()); +} + +QPixmap XCursorThemeData::icon() const +{ + if (mIcon.isNull()) mIcon = createIcon(); + return mIcon; +} + +QImage XCursorThemeData::autoCropImage(const QImage &image) const +{ + // Compute an autocrop rectangle for the image + QRect r(image.rect().bottomRight(), image.rect().topLeft()); + const quint32 *pixels = reinterpret_cast(image.bits()); + for (int y = 0; y < image.height(); ++y) + { + for (int x = 0; x < image.width(); ++x) + { + if (*(pixels++)) + { + if (x < r.left()) r.setLeft(x); + if (x > r.right()) r.setRight(x); + if (y < r.top()) r.setTop(y); + if (y > r.bottom()) r.setBottom(y); + } + } + } + // Normalize the rectangle + return image.copy(r.normalized()); +} + +static int nominalCursorSize(int iconSize) +{ + for (int i = 512; i > 8; i /= 2) + { + if (i < iconSize) return i; + if ((i*0.75) < iconSize) return int(i*0.75); + } + return 8; +} + +QPixmap XCursorThemeData::createIcon() const +{ + int iconSize = QApplication::style()->pixelMetric(QStyle::PM_LargeIconSize); + int cursorSize = nominalCursorSize(iconSize); + QSize size = QSize(iconSize, iconSize); + + QPixmap pixmap; + QImage image = loadImage(sample(), cursorSize); + if (image.isNull() && sample() != "left_ptr") image = loadImage("left_ptr", cursorSize); + if (!image.isNull()) + { + // Scale the image if it's larger than the preferred icon size + if (image.width() > size.width() || image.height() > size.height()) + { + image = image.scaled(size, Qt::KeepAspectRatio, Qt::SmoothTransformation); + pixmap = QPixmap::fromImage(image); + } + } + return pixmap; +} + +XcursorImage *XCursorThemeData::xcLoadImage(const QString &image, int size) const +{ + QByteArray cursorName = QFile::encodeName(image); + QByteArray themeName = QFile::encodeName(name()); + return XcursorLibraryLoadImage(cursorName, themeName, size); +} + +XcursorImages *XCursorThemeData::xcLoadImages(const QString &image, int size) const +{ + QByteArray cursorName = QFile::encodeName(image); + QByteArray themeName = QFile::encodeName(name()); + return XcursorLibraryLoadImages(cursorName, themeName, size); +} + +unsigned long XCursorThemeData::loadCursorHandle(const QString &name, int size) const +{ + if (size == -1) size = XcursorGetDefaultSize(QX11Info::display()); + // Load the cursor images + XcursorImages *images = xcLoadImages(name, size); + if (!images) images = xcLoadImages(findAlternative(name), size); + // Fall back to a legacy cursor + //if (!images) return LegacyTheme::loadCursor(name); + if (!images) return 0; + // Create the cursor + unsigned long handle = (unsigned long)XcursorImagesLoadCursor(QX11Info::display(), images); + XcursorImagesDestroy(images); + //setCursorName(cursor, name); + return handle; +} + +QImage XCursorThemeData::loadImage(const QString &name, int size) const +{ + if (size == -1) size = XcursorGetDefaultSize(QX11Info::display()); + // Load the image + XcursorImage *xcimage = xcLoadImage(name, size); + if (!xcimage) xcimage = xcLoadImage(findAlternative(name), size); + // Fall back to a legacy cursor + //if (!xcimage) return LegacyTheme::loadImage(name); + if (!xcimage) return QImage(); + // Convert the XcursorImage to a QImage, and auto-crop it + QImage image((uchar *)xcimage->pixels, xcimage->width, xcimage->height, QImage::Format_ARGB32_Premultiplied); + image = autoCropImage(image); + XcursorImageDestroy(xcimage); + return image; +} + +bool XCursorThemeData::isWritable() const +{ + QFileInfo fi(path()); + return fi.isWritable(); +} + +/////////////////////////////////////////////////////////////////////////////// +bool haveXfixes() +{ + bool result = false; + int event_base, error_base; + if (XFixesQueryExtension(QX11Info::display(), &event_base, &error_base)) + { + int major, minor; + XFixesQueryVersion(QX11Info::display(), &major, &minor); + result = (major >= 2); + } + return result; +} + +bool applyTheme(const XCursorThemeData &theme) +{ + // Require the Xcursor version that shipped with X11R6.9 or greater, since + // in previous versions the Xfixes code wasn't enabled due to a bug in the + // build system (freedesktop bug #975). + if (!haveXfixes()) return false; + + QByteArray themeName = QFile::encodeName(theme.name()); + + // Set up the proper launch environment for newly started apps + //k8:!!!:KToolInvocation::klauncher()->setLaunchEnv("XCURSOR_THEME", themeName); + + // Update the Xcursor X resources + //k8:!!!:runRdb(0); + + // Reload the standard cursors + QStringList names; + // Qt cursors + names << "left_ptr" << "up_arrow" << "cross" << "wait" + << "left_ptr_watch" << "ibeam" << "size_ver" << "size_hor" + << "size_bdiag" << "size_fdiag" << "size_all" << "split_v" + << "split_h" << "pointing_hand" << "openhand" + << "closedhand" << "forbidden" << "whats_this"; + // X core cursors + names << "X_cursor" << "right_ptr" << "hand1" + << "hand2" << "watch" << "xterm" + << "crosshair" << "left_ptr_watch" << "center_ptr" + << "sb_h_double_arrow" << "sb_v_double_arrow" << "fleur" + << "top_left_corner" << "top_side" << "top_right_corner" + << "right_side" << "bottom_right_corner" << "bottom_side" + << "bottom_left_corner" << "left_side" << "question_arrow" + << "pirate"; + + //QX11Info x11Info; + foreach (const QString &name, names) + { + Cursor cursor = (Cursor)theme.loadCursorHandle(name); + XFixesChangeCursorByName(QX11Info::display(), cursor, QFile::encodeName(name)); + // FIXME: do we need to free the cursor? + } + return true; +} + +QString getCurrentTheme() +{ + return XcursorGetTheme(QX11Info::display()); +} diff --git a/liblxqt-config-cursor/crtheme.h b/liblxqt-config-cursor/crtheme.h new file mode 100644 index 0000000..83cd541 --- /dev/null +++ b/liblxqt-config-cursor/crtheme.h @@ -0,0 +1,119 @@ +/* Copyright © 2006-2007 Fredrik Höglund + * (c)GPL2 (c)GPL3 + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License version 2 or at your option version 3 as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +/* + * additional code: Ketmar // Vampire Avalon (psyc://ketmar.no-ip.org/~Ketmar) + */ +#ifndef CRTHEME_H +#define CRTHEME_H + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/////////////////////////////////////////////////////////////////////////////// +// X11 is SHIT! +struct _XcursorImage; +struct _XcursorImages; + +typedef _XcursorImage XcursorImage; +typedef _XcursorImages XcursorImages; + + +/////////////////////////////////////////////////////////////////////////////// +class XCursorThemeData +{ +public: + enum ItemDataRole { + // Note: use printf "0x%08X\n" $(($RANDOM*$RANDOM)) + // to define additional roles. + DisplayDetailRole = 0x24A3DAF8 + }; + + XCursorThemeData(const QDir &aDir); + + const QString &name() const { return mName; } + const QString &title() const { return mTitle; } + const QString &description() const { return mDescription; } + const QString &sample() const { return mSample; } + const QString &path() const { return mPath; } + bool isHidden() const { return mHidden; } + QPixmap icon() const; + const QStringList &inherits() const { return mInherits; } + + inline void setName(const QString &name) + { + mName = name; + mHash = qHash(name); + } + + bool isWritable() const; + + /// Hash value for the internal name + uint hash() const { return mHash; } + + /// Loads the cursor @p name, with the nominal size @p size. + /// If the theme doesn't have the cursor @p name, it should return + /// the default cursor from the active theme instead. + unsigned long loadCursorHandle(const QString &name, int size=-1) const; + + /// Loads the cursor image @p name, with the nominal size @p size. + /// The image should be autocropped to the smallest possible size. + /// If the theme doesn't have the cursor @p name, it should return a null image. + QImage loadImage(const QString &name, int size=-1) const; + + XcursorImage *xcLoadImage(const QString &image, int size=-1) const; + XcursorImages *xcLoadImages(const QString &image, int size=-1) const; + + QString findAlternative(const QString &name) const; + +protected: + void parseIndexFile(); + + /// Creates the icon returned by @ref icon(). + QPixmap createIcon() const; + + /// Convenience function for cropping an image. + QImage autoCropImage(const QImage &image) const; + +protected: + QString mName; + QString mTitle; + QString mDescription; + QString mPath; + QString mSample; + mutable QPixmap mIcon; + bool mHidden; + uint mHash; + QStringList mInherits; +}; + +bool haveXfixes(); +bool applyTheme(const XCursorThemeData &theme); + +QString getCurrentTheme(); + +#endif diff --git a/liblxqt-config-cursor/itemdelegate.cpp b/liblxqt-config-cursor/itemdelegate.cpp new file mode 100644 index 0000000..0a4e674 --- /dev/null +++ b/liblxqt-config-cursor/itemdelegate.cpp @@ -0,0 +1,141 @@ +/* Copyright © 2006-2007 Fredrik Höglund + * (c)GPL2 (c)GPL3 + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License version 2 or at your option version 3 as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +/* + * additional code: Ketmar // Vampire Avalon (psyc://ketmar.no-ip.org/~Ketmar) + */ +#include "itemdelegate.h" +#include "crtheme.h" + +#include +#include +#include + + +namespace { + const int decorationMargin = 8; +} + + +/////////////////////////////////////////////////////////////////////////////// +ItemDelegate::ItemDelegate(QObject *parent) : QAbstractItemDelegate(parent) +{ +} + + +ItemDelegate::~ItemDelegate() +{ +} + +QString ItemDelegate::firstLine(const QModelIndex &index) const +{ + if (index.isValid()) return index.model()->data(index, Qt::DisplayRole).toString(); + return QString(); +} + +QString ItemDelegate::secondLine(const QModelIndex &index) const +{ + if (index.isValid()) return index.model()->data(index, XCursorThemeData::DisplayDetailRole).toString(); + return QString(); +} + +QPixmap ItemDelegate::decoration(const QModelIndex &index) const +{ + if (index.isValid()) return qvariant_cast(index.model()->data(index, Qt::DecorationRole)); + return QPixmap(); +} + +QSize ItemDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const +{ + if (!index.isValid()) return QSize(); + + QFont normalfont = option.font; + QFont boldfont = normalfont; + boldfont.setBold(true); + // Extract the items we want to measure + QString firstRow = firstLine(index); + QString secondRow = secondLine(index); + // Compute the height + QFontMetrics fm1(boldfont); + QFontMetrics fm2(normalfont); + int height = fm1.lineSpacing() + fm2.lineSpacing(); + height = qMax(height, option.decorationSize.height()); + // Compute the text width + int width = fm1.width(firstRow); + width = qMax(width, fm2.width(secondRow)); + // Add decoration width + margin + width += option.decorationSize.width()+decorationMargin; + return QSize(width, height+16); +} + +QPalette::ColorRole ItemDelegate::foregroundRole(const QStyleOptionViewItem &option, const QModelIndex &index) const +{ + Q_UNUSED(index) + if (option.state & QStyle::State_Selected) return QPalette::HighlightedText; + return QPalette::Text; +} + +void ItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const +{ + if (!index.isValid()) return; + painter->save(); + + QFont normalfont = option.font; + QFont boldfont = normalfont; + boldfont.setBold(true); + + QString firstRow = firstLine(index); + QString secondRow = secondLine(index); + QPixmap pixmap = decoration(index); + + QColor textcol = option.palette.color(foregroundRole(option, index)); + + // Draw the background + QStyleOptionViewItemV4 opt = option; + QStyle *style = opt.widget ? opt.widget->style() : QApplication::style(); + style->drawPrimitive(QStyle::PE_PanelItemViewItem, &opt, painter, opt.widget); + + // Draw the icon + int x = option.rect.left()+(option.decorationSize.width()-pixmap.width()+decorationMargin)/2; + int y = option.rect.top()+(option.rect.height()-pixmap.height())/2; + QRect pixmapRect = QStyle::visualRect(option.direction, option.rect, QRect(x, y, pixmap.width(), pixmap.height())); + painter->drawPixmap(pixmapRect.x(), pixmapRect.y(), pixmap); + + // Draw the text + QFontMetrics fm1(boldfont); + QFontMetrics fm2(normalfont); + + int textAreaHeight = fm1.lineSpacing()+fm2.lineSpacing(); + + x = option.rect.left()+option.decorationSize.width()+decorationMargin; + int y1 = option.rect.top()+(option.rect.height()-textAreaHeight)/2; + int y2 = y1+fm1.lineSpacing(); + QRect firstRowRect = QStyle::visualRect(option.direction, option.rect, QRect(x, y1, fm1.width(firstRow), fm1.lineSpacing())); + QRect secondRowRect = QStyle::visualRect(option.direction, option.rect, QRect(x, y2, fm2.width(secondRow), fm2.lineSpacing())); + painter->setPen(textcol); + + // First line + painter->setFont(boldfont); + painter->drawText(firstRowRect, Qt::AlignCenter, firstRow); + + // Second line + painter->setFont(normalfont); + painter->drawText(secondRowRect, Qt::AlignCenter, secondRow); + + painter->restore(); +} diff --git a/liblxqt-config-cursor/itemdelegate.h b/liblxqt-config-cursor/itemdelegate.h new file mode 100644 index 0000000..81f0f9e --- /dev/null +++ b/liblxqt-config-cursor/itemdelegate.h @@ -0,0 +1,48 @@ +/* Copyright © 2006-2007 Fredrik Höglund + * (c)GPL2 (c)GPL3 + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License version 2 or at your option version 3 as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +/* + * additional code: Ketmar // Vampire Avalon (psyc://ketmar.no-ip.org/~Ketmar) + */ +#ifndef ITEMDELEGATE_H +#define ITEMDELEGATE_H + +#include + +class QPainter; + + +class ItemDelegate : public QAbstractItemDelegate +{ + Q_OBJECT + +public: + ItemDelegate(QObject *parent = 0); + ~ItemDelegate(); + + QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const; + void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const; + +private: + QString firstLine(const QModelIndex &index) const; + QString secondLine(const QModelIndex &index) const; + QPixmap decoration(const QModelIndex &index) const; + QPalette::ColorRole foregroundRole(const QStyleOptionViewItem &option, const QModelIndex &index) const; +}; + +#endif diff --git a/liblxqt-config-cursor/main.cpp b/liblxqt-config-cursor/main.cpp new file mode 100644 index 0000000..186aaf0 --- /dev/null +++ b/liblxqt-config-cursor/main.cpp @@ -0,0 +1,42 @@ +/* coded by Ketmar // Vampire Avalon (psyc://ketmar.no-ip.org/~Ketmar) + * (c)DWTFYW + * + * This program is free software. It comes without any warranty, to + * the extent permitted by applicable law. You can redistribute it + * and/or modify it under the terms of the Do What The Fuck You Want + * To Public License, Version 2, as published by Sam Hocevar. See + * http://sam.zoy.org/wtfpl/COPYING for more details. + */ +//#include +#include + +#include +#include +#include "main.h" +#include "lxqttranslate.h" + +#include +#include +#include +#include +#include +#include +#include + + +/////////////////////////////////////////////////////////////////////////////// +int main (int argc, char *argv[]) +{ + //QTextCodec::setCodecForCStrings(QTextCodec::codecForName("koi8-r")); + //QTextCodec::setCodecForLocale(QTextCodec::codecForName("koi8-r")); + + LxQt::Application app(argc, argv); + TRANSLATE_APP; + + //qDebug() << findDefaultTheme() << getCurrentTheme(); + + SelectWnd *sw = new SelectWnd; + sw->show(); + sw->setCurrent(); + return app.exec(); +} diff --git a/liblxqt-config-cursor/main.h b/liblxqt-config-cursor/main.h new file mode 100644 index 0000000..09b9673 --- /dev/null +++ b/liblxqt-config-cursor/main.h @@ -0,0 +1,19 @@ +/* coded by Ketmar // Vampire Avalon (psyc://ketmar.no-ip.org/~Ketmar) + * (c)DWTFYW + * + * This program is free software. It comes without any warranty, to + * the extent permitted by applicable law. You can redistribute it + * and/or modify it under the terms of the Do What The Fuck You Want + * To Public License, Version 2, as published by Sam Hocevar. See + * http://sam.zoy.org/wtfpl/COPYING for more details. + */ +#ifndef MAIN_H +#define MAIN_H + + +#include "cfgfile.h" +#include "crtheme.h" +#include "selectwnd.h" + + +#endif diff --git a/liblxqt-config-cursor/man/lxqt-config-mouse.1 b/liblxqt-config-cursor/man/lxqt-config-mouse.1 new file mode 100644 index 0000000..a01082b --- /dev/null +++ b/liblxqt-config-cursor/man/lxqt-config-mouse.1 @@ -0,0 +1,39 @@ +.TH lxqt-config-cursor "1" "September 2012" "LXQt\-qt\ 0.7.0" "LXQt\ Cursor settings" +.SH NAME +lxqt-config-cursor \- Application of \fBLXQt\fR: the faster and lighter QT Desktop Environment +.SH SYNOPSIS +.B lxqt-config-cursor +.br +.SH DESCRIPTION +This its a simple GUI cursor theme configuraton (by the moment) for the LXQt desktop environment. +Also can manage theme installation for it (localy for/per user only). +.P +\fBLXQt\fR is an advanced, easy-to-use, and fast desktop environment based on Qt +technologies, ships several core desktop components, all of which are optional: +.P + * Panel + * Desktop + * Application launcher + * Settings center \fI(related to this)\fR + * Session handler + * Polkit handler + * SSH password access + * Display manager handler +.P +These components perform similar actions to those available in other desktop +environments, and their name is self-descriptive. They are usually not launched +by hand but automatically, when choosing a \fBLXQt\-qt\fR session in the Display +Manager. +.P +.SH "REPORTING BUGS" +Report bugs to https://github.com/lxde/lxde-qt/issues +.SH "SEE ALSO" +\fBLXQt\fR it has been tailored for users who value simplicity, speed, and +an intuitive interface, also intended for less powerful machines. See also: +.\" any module must refers to session app, for more info on start it +.P +\fBlxqt-config.1\fR LXQt application for performing settings on many applications +.P +.SH AUTHOR +This manual page was created by \fBPICCORO Lenz McKAY\fR \fI\fR +for \fBLXQt\fR project and VENENUX GNU/Linux but can be used by others. diff --git a/liblxqt-config-cursor/previewwidget.cpp b/liblxqt-config-cursor/previewwidget.cpp new file mode 100644 index 0000000..7fe319e --- /dev/null +++ b/liblxqt-config-cursor/previewwidget.cpp @@ -0,0 +1,221 @@ +/* Copyright © 2003-2007 Fredrik Höglund + * (c)GPL2 (c)GPL3 + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +/* + * additional code: Ketmar // Vampire Avalon (psyc://ketmar.no-ip.org/~Ketmar) + */ +#include + +#include +#include + +#include "previewwidget.h" + +#include "crtheme.h" + +#include +#include + +#include +#include + +namespace { + // Preview cursors + const char *const cursorNames[] = { + "left_ptr", + "left_ptr_watch", + "wait", + "pointing_hand", + "whats_this", + "ibeam", + "size_all", + "size_fdiag", + "cross", + "split_h", + "size_ver", + "size_hor", + "size_bdiag", + "split_v", + }; + + const int numCursors = 9; // The number of cursors from the above list to be previewed + const int previewSize = 24; // The nominal cursor size to be used in the preview widget + const int cursorSpacing = 20; // Spacing between preview cursors + const int widgetMinWidth = 10; // The minimum width of the preview widget + const int widgetMinHeight = 48; // The minimum height of the preview widget +} + + +/////////////////////////////////////////////////////////////////////////////// +class PreviewCursor +{ + public: + PreviewCursor (const XCursorThemeData &theme, const QString &name); + ~PreviewCursor () {} + + const QPixmap &pixmap () const { return mPixmap; } + int width () const { return mPixmap.width(); } + int height () const { return mPixmap.height(); } + inline QRect rect () const; + void setPosition (const QPoint &p) { mPos = p; } + void setPosition (int x, int y) { mPos = QPoint(x, y); } + QPoint position () const { return mPos; } + operator const xcb_cursor_t& () const { return mCursorHandle; } + operator const QPixmap& () const { return pixmap(); } + + private: + QPixmap mPixmap; + xcb_cursor_t mCursorHandle; + QPoint mPos; +}; + + +/////////////////////////////////////////////////////////////////////////////// +PreviewCursor::PreviewCursor(const XCursorThemeData &theme, const QString &name) +{ + // Create the preview pixmap + QImage image = theme.loadImage(name, previewSize); + if (image.isNull()) return; + int maxSize = previewSize*2; + if (image.height() > maxSize || image.width() > maxSize) + image = image.scaled(maxSize, maxSize, Qt::KeepAspectRatio, Qt::SmoothTransformation); + mPixmap = QPixmap::fromImage(image); + // load the cursor + mCursorHandle = theme.loadCursorHandle(name, previewSize); +} + +QRect PreviewCursor::rect() const +{ + return QRect(mPos, mPixmap.size()).adjusted(-(cursorSpacing/2), -(cursorSpacing/2), cursorSpacing/2, cursorSpacing/2); +} + + +/////////////////////////////////////////////////////////////////////////////// +PreviewWidget::PreviewWidget(QWidget *parent) : QWidget(parent) +{ + setMouseTracking(true); + mCurrent = NULL; +} + +PreviewWidget::~PreviewWidget() +{ + qDeleteAll(mList); + mList.clear(); +} + + +// Since Qt5, wrapping a Cursor handle with QCursor is no longer supported. +// So we have to do it ourselves. I really hate Qt 5! +void PreviewWidget::setCursorHandle(xcb_cursor_t cursorHandle) +{ + WId wid = nativeParentWidget()->windowHandle()->winId(); + xcb_change_window_attributes(QX11Info::connection(), wid, XCB_CW_CURSOR, &cursorHandle); + xcb_flush(QX11Info::connection()); +} + + +QSize PreviewWidget::sizeHint() const +{ + int totalWidth = 0, maxHeight = 0; + foreach (const PreviewCursor *c, mList) + { + totalWidth += c->width(); + maxHeight = qMax(c->height(), maxHeight); + } + totalWidth += (mList.count()-1)*cursorSpacing; + maxHeight = qMax(maxHeight, widgetMinHeight); + return QSize(qMax(totalWidth, widgetMinWidth), qMax(height(), maxHeight)); +} + +void PreviewWidget::layoutItems() +{ + if (!mList.isEmpty()) + { + QSize size = sizeHint(); + int cursorWidth = size.width()/mList.count(); + int nextX = (width()-size.width())/2; + foreach (PreviewCursor *c, mList) + { + c->setPosition(nextX+(cursorWidth-c->width())/2, (height()-c->height())/2); + nextX += cursorWidth; + } + } + mNeedLayout = false; +} + +void PreviewWidget::setTheme(const XCursorThemeData &theme) +{ + qDeleteAll(mList); + mList.clear(); + for (int i = 0; i < numCursors; ++i) mList << new PreviewCursor(theme, cursorNames[i]); + mNeedLayout = true; + updateGeometry(); + mCurrent = NULL; + update(); +} + + +void PreviewWidget::clearTheme() +{ + qDeleteAll(mList); + mList.clear(); + mCurrent = NULL; + update(); +} + +void PreviewWidget::paintEvent(QPaintEvent *) +{ + QPainter p(this); + if (mNeedLayout) layoutItems(); + foreach (const PreviewCursor *c, mList) + { + if (c->pixmap().isNull()) continue; + p.drawPixmap(c->position(), *c); + } +} + +void PreviewWidget::mouseMoveEvent(QMouseEvent *e) +{ + if (mNeedLayout) layoutItems(); + foreach (const PreviewCursor *c, mList) + { + if (c->rect().contains(e->pos())) + { + if (c != mCurrent) + { + // NOTE: we have to set the Qt cursor value to something other than Qt::ArrowCursor + // Otherwise, though we set the xcursor handle to the underlying window, Qt still + // thinks that the current cursor is Qt::ArrowCursor and will not restore the cursor + // later when we call setCursor(Qt::ArrowCursor). So, we set it to BlankCursor to + // cheat Qt so it knows that the current cursor is not Qt::ArrowCursor. + // This is a dirty hack, but without this, Qt cannot restore Qt::ArrowCursor later. + setCursor(Qt::BlankCursor); + setCursorHandle(*c); + mCurrent = c; + } + return; + } + } + setCursor(Qt::ArrowCursor); + mCurrent = NULL; +} + + +void PreviewWidget::resizeEvent(QResizeEvent *) +{ + if (!mList.isEmpty()) mNeedLayout = true; +} diff --git a/liblxqt-config-cursor/previewwidget.h b/liblxqt-config-cursor/previewwidget.h new file mode 100644 index 0000000..3d035ea --- /dev/null +++ b/liblxqt-config-cursor/previewwidget.h @@ -0,0 +1,60 @@ +/* Copyright © 2003-2007 Fredrik Höglund + * (c)GPL2 + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +/* + * additional code: Ketmar // Vampire Avalon (psyc://ketmar.no-ip.org/~Ketmar) + */ +#ifndef PREVIEWWIDGET_H +#define PREVIEWWIDGET_H + +#include + +#include +#include + +class XCursorThemeData; +class PreviewCursor; + +class PreviewWidget : public QWidget +{ + Q_OBJECT + +public: + PreviewWidget (QWidget *parent=0); + ~PreviewWidget (); + + void setTheme (const XCursorThemeData &theme); + void clearTheme (); + + QSize sizeHint () const; + + void setCursorHandle(xcb_cursor_t cursorHandle); + +protected: + void paintEvent (QPaintEvent *e); + void mouseMoveEvent(QMouseEvent *e); + void resizeEvent (QResizeEvent *e); + +private: + void layoutItems (); + + QList mList; + const PreviewCursor *mCurrent; + bool mNeedLayout; +}; + +#endif diff --git a/liblxqt-config-cursor/selectwnd.cpp b/liblxqt-config-cursor/selectwnd.cpp new file mode 100644 index 0000000..5f48f7f --- /dev/null +++ b/liblxqt-config-cursor/selectwnd.cpp @@ -0,0 +1,229 @@ +/* coded by Ketmar // Vampire Avalon (psyc://ketmar.no-ip.org/~Ketmar) + * (c)DWTFYW + * + * This program is free software. It comes without any warranty, to + * the extent permitted by applicable law. You can redistribute it + * and/or modify it under the terms of the Do What The Fuck You Want + * To Public License, Version 2, as published by Sam Hocevar. See + * http://sam.zoy.org/wtfpl/COPYING for more details. + */ + +// 2014-04-10 modified by Hong Jen Yee (PCMan) for integration with lxqt-config-input + +#include + +#include "selectwnd.h" + +#include +#include +#include +#include +#include +#include + +#include "cfgfile.h" +#include "crtheme.h" +#include "thememodel.h" +#include "itemdelegate.h" + +#include "xcrimg.h" +#include "xcrxcur.h" +#include "xcrtheme.h" + +#include +#include +#include +#include + +#define HOME_ICON_DIR QDir::homePath() + "/.icons" + +SelectWnd::SelectWnd(LxQt::Settings* settings, QWidget *parent) : QWidget(parent), mSettings(settings) +{ + setupUi(this); + + warningLabel->hide(); + + mModel = new XCursorThemeModel(this); + + int size = style()->pixelMetric(QStyle::PM_LargeIconSize); + lbThemes->setModel(mModel); + lbThemes->setItemDelegate(new ItemDelegate(this)); + lbThemes->setIconSize(QSize(size, size)); + lbThemes->setSelectionMode(QAbstractItemView::SingleSelection); + + // Make sure we find out about selection changes + connect(lbThemes->selectionModel(), SIGNAL(currentChanged(const QModelIndex &, const QModelIndex &)), + SLOT(currentChanged(const QModelIndex &, const QModelIndex &))); + // display/hide warning label + connect(mModel, SIGNAL(modelReset()), + this, SLOT(handleWarning())); + connect(mModel, SIGNAL(rowsInserted(const QModelIndex&, int, int)), + this, SLOT(handleWarning())); + connect(mModel, SIGNAL(rowsRemoved(const QModelIndex&, int, int)), + this, SLOT(handleWarning())); + + connect(warningLabel, SIGNAL(showDirInfo()), + this, SLOT(showDirInfo())); + + // Disable the install button if we can't install new themes to ~/.icons, + // or Xcursor isn't set up to look for cursor themes there + btInstall->setEnabled(mModel->searchPaths().contains(HOME_ICON_DIR) && iconsIsWritable()); + // TODO/FIXME: btInstall functionality + btInstall->hide(); + btRemove->hide(); + + //QTimer::singleShot(0, this, SLOT(setCurrent())); + + handleWarning(); +} + + +SelectWnd::~SelectWnd() +{ +} + +void SelectWnd::setCurrent() +{ + lbThemes->selectionModel()->clear(); + + QString ct = getCurrentTheme(); + mAppliedIndex = mModel->defaultIndex(); + + if (!ct.isEmpty()) mAppliedIndex = mModel->findIndex(ct); + else mAppliedIndex = mModel->defaultIndex(); + + if (mAppliedIndex.isValid()) + { + const XCursorThemeData *theme = mModel->theme(mAppliedIndex); + // Select the current theme + selectRow(mAppliedIndex); + lbThemes->scrollTo(mAppliedIndex, QListView::PositionAtCenter); + // Update the preview widget as well + if (theme) preview->setTheme(*theme);// else preview->clearTheme(); + } +} + +bool SelectWnd::iconsIsWritable() const +{ + const QFileInfo icons = QFileInfo(HOME_ICON_DIR); + const QFileInfo home = QFileInfo(QDir::homePath()); + return ((icons.exists() && icons.isDir() && icons.isWritable()) || (!icons.exists() && home.isWritable())); +} + +/* +void SelectWnd::keyPressEvent(QKeyEvent *e) +{ + if (e->key() == Qt::Key_Escape) close(); +} +*/ + +void SelectWnd::selectRow(int row) const +{ + // Create a selection that stretches across all columns + QModelIndex from = mModel->index(row, 0); + QModelIndex to = mModel->index(row, mModel->columnCount()-1); + QItemSelection selection(from, to); + lbThemes->selectionModel()->select(selection, QItemSelectionModel::Select); + lbThemes->selectionModel()->setCurrentIndex(mAppliedIndex, QItemSelectionModel::NoUpdate); +} + +void SelectWnd::currentChanged(const QModelIndex ¤t, const QModelIndex &previous) +{ + Q_UNUSED(previous) + if (current.isValid()) { + const XCursorThemeData *theme = mModel->theme(current); + if (theme) { + preview->setTheme(*theme); + btRemove->setEnabled(theme->isWritable()); + } else { + preview->clearTheme(); + } + + // directly apply the current settings + applyCurrent(); + } else { + preview->clearTheme(); + } + //emit changed(mAppliedIndex != current); +} + +void SelectWnd::on_btInstall_clicked() +{ + qDebug() << "'install' clicked"; +} + +void SelectWnd::applyCurrent() +{ + //qDebug() << "'set' clicked"; + const XCursorThemeData *theme = mModel->theme(lbThemes->currentIndex()); + if (!theme) return; + applyTheme(*theme); + fixXDefaults(theme->name()); + + // call xrdb to merge the new settings in ~/.Xdefaults + // FIXME: need to check if we're running in X? + QProcess xrdb; + xrdb.start("xrdb -merge " + QDir::home().path() + "/.Xdefaults"); + xrdb.waitForFinished(); + + // old razor-qt and lxqt versions use $XCURSOR_THEME environment variable + // for this, but it's less flexible and more problematic. Let's deprecate its use. + mSettings->beginGroup("Environment"); + mSettings->remove("XCURSOR_THEME"); // ensure that we're not using XCURSOR_THEME + mSettings->endGroup(); + // save to Mouse/cursor_theme instead + mSettings->beginGroup("Mouse"); + mSettings->setValue("cursor_theme", theme->name()); + mSettings->endGroup(); + + // The XCURSOR_THEME environment varialbe does not work sometimes. + // Besides, XDefaults values are not used by Qt. + // So, let's write the new theme name to ~/.icons/default/index.theme. + // This is the most reliable way. + // QSettings will encode the group name "Icon Theme" to "Icon%20Theme" and there is no way to turn it off. + // So let's not use it here. :-( + QString dirPath = HOME_ICON_DIR + "/default"; + QDir().mkpath(dirPath); // ensure the existence of the ~/.icons/default dir + QFile indexTheme(dirPath + "/index.theme"); + if(indexTheme.open(QIODevice::WriteOnly|QIODevice::Truncate)) + { + QTextStream(&indexTheme) << + "# Written by lxqt-config-appearance\n" << + "[Icon Theme]\n" << + "Name=Default\n" << + "Comment=Default cursor theme\n" << + "Inherits=" << theme->name() << "\n"; + indexTheme.close(); + } +} + +void SelectWnd::on_btRemove_clicked() +{ + qDebug() << "'remove' clicked"; + const XCursorThemeData *theme = mModel->theme(lbThemes->currentIndex()); + if (!theme) return; + QString ct = getCurrentTheme(); + if (ct == theme->name()) + { + QMessageBox::warning(this, tr("XCurTheme error"), + tr("You can't remove active theme!"), QMessageBox::Ok, QMessageBox::Ok); + return; + } + QDir d(theme->path()); + preview->clearTheme(); + mModel->removeTheme(lbThemes->currentIndex()); + removeXCursorTheme(d); +} + +void SelectWnd::handleWarning() +{ + bool empty = mModel->rowCount(); + warningLabel->setVisible(!empty); + preview->setVisible(empty); + infoLabel->setVisible(empty); +} + +void SelectWnd::showDirInfo() +{ + QToolTip::showText(mapToGlobal(warningLabel->buttonPos()), mModel->searchPaths().join("\n")); +} diff --git a/liblxqt-config-cursor/selectwnd.h b/liblxqt-config-cursor/selectwnd.h new file mode 100644 index 0000000..38ff2ff --- /dev/null +++ b/liblxqt-config-cursor/selectwnd.h @@ -0,0 +1,59 @@ +/* coded by Ketmar // Vampire Avalon (psyc://ketmar.no-ip.org/~Ketmar) + * (c)DWTFYW + * + * This program is free software. It comes without any warranty, to + * the extent permitted by applicable law. You can redistribute it + * and/or modify it under the terms of the Do What The Fuck You Want + * To Public License, Version 2, as published by Sam Hocevar. See + * http://sam.zoy.org/wtfpl/COPYING for more details. + */ + +// 2014-04-10 modified by Hong Jen Yee (PCMan) for integration with lxqt-config-input + +#ifndef SELECTWND_H +#define SELECTWND_H + +#include +#include + +namespace LxQt { + class Settings; +} + +class XCursorThemeModel; + +#include "ui_selectwnd.h" +class SelectWnd : public QWidget, private Ui_SelectWnd +{ + Q_OBJECT + +public: + SelectWnd (LxQt::Settings* settings, QWidget *parent=0); + ~SelectWnd (); + +public slots: + void setCurrent (); + +protected: + // void keyPressEvent (QKeyEvent *e); + +private: + bool iconsIsWritable () const; + void selectRow (int) const; + void selectRow (const QModelIndex &index) const { selectRow(index.row()); } + void applyCurrent (); + +private slots: + void currentChanged (const QModelIndex ¤t, const QModelIndex &previous); + void on_btInstall_clicked (); + void on_btRemove_clicked (); + void handleWarning(); + void showDirInfo(); + +private: + XCursorThemeModel *mModel; + QPersistentModelIndex mAppliedIndex; + LxQt::Settings* mSettings; +}; + +#endif diff --git a/liblxqt-config-cursor/thememodel.cpp b/liblxqt-config-cursor/thememodel.cpp new file mode 100644 index 0000000..66d87ba --- /dev/null +++ b/liblxqt-config-cursor/thememodel.cpp @@ -0,0 +1,328 @@ +/* Copyright © 2005-2007 Fredrik Höglund + * (c)GPL2 (c)GPL3 + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License version 2 or at your option version 3 as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +/* + * additional code: Ketmar // Vampire Avalon (psyc://ketmar.no-ip.org/~Ketmar) + */ +#include + +#include "thememodel.h" + +#include + +#include "crtheme.h" +#include "cfgfile.h" + +#include +#include + + +//#define DUMP_FOUND_THEMES + + +/////////////////////////////////////////////////////////////////////////////// +XCursorThemeModel::XCursorThemeModel (QObject *parent) : QAbstractTableModel(parent) +{ + insertThemes(); +} + + +XCursorThemeModel::~XCursorThemeModel() +{ + qDeleteAll(mList); + mList.clear(); +} + + +QVariant XCursorThemeModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + // Only provide text for the headers + if (role != Qt::DisplayRole) return QVariant(); + // Horizontal header labels + if (orientation == Qt::Horizontal) + { + switch (section) + { + case NameColumn: return tr("Name"); + case DescColumn: return tr("Description"); + default: return QVariant(); + } + } + // Numbered vertical header lables + return QString(section); +} + +QVariant XCursorThemeModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid() || index.row() < 0 || index.row() >= mList.count()) return QVariant(); + const XCursorThemeData *theme = mList.at(index.row()); + // Text label + if (role == Qt::DisplayRole) + { + switch (index.column()) + { + case NameColumn: return theme->title(); + case DescColumn: return theme->description(); + default: return QVariant(); + } + } + // Description for the first name column + if (role == XCursorThemeData::DisplayDetailRole && index.column() == NameColumn) return theme->description(); + // Icon for the name column + if (role == Qt::DecorationRole && index.column() == NameColumn) return theme->icon(); + // + return QVariant(); +} + +void XCursorThemeModel::sort(int column, Qt::SortOrder order) +{ + Q_UNUSED(column); + Q_UNUSED(order); + // Sorting of the model isn't implemented, as the KCM currently uses + // a sorting proxy model. +} + +const XCursorThemeData *XCursorThemeModel::theme(const QModelIndex &index) +{ + if (!index.isValid()) return NULL; + if (index.row() < 0 || index.row() >= mList.count()) return NULL; + return mList.at(index.row()); +} + +QModelIndex XCursorThemeModel::findIndex(const QString &name) +{ + uint hash = qHash(name); + for (int i = 0; i < mList.count(); ++i) + { + const XCursorThemeData *theme = mList.at(i); + if (theme->hash() == hash) return index(i, 0); + } + return QModelIndex(); +} + +QModelIndex XCursorThemeModel::defaultIndex() +{ + return findIndex(mDefaultName); +} + +const QStringList XCursorThemeModel::searchPaths() +{ + if (!mBaseDirs.isEmpty()) return mBaseDirs; + // Get the search path from Xcursor + QString path = XcursorLibraryPath(); + // Separate the paths + mBaseDirs = path.split(':', QString::SkipEmptyParts); + // Remove duplicates + QMutableStringListIterator i(mBaseDirs); + while (i.hasNext()) + { + const QString path = i.next(); + QMutableStringListIterator j(i); + while (j.hasNext()) if (j.next() == path) j.remove(); + } + // Expand all occurrences of ~/ to the home dir + mBaseDirs.replaceInStrings(QRegExp("^~\\/"), QDir::home().path() + '/'); + return mBaseDirs; +} + +bool XCursorThemeModel::hasTheme(const QString &name) const +{ + const uint hash = qHash(name); + foreach (const XCursorThemeData *theme, mList) if (theme->hash() == hash) return true; + return false; +} + +bool XCursorThemeModel::isCursorTheme(const QString &theme, const int depth) +{ + // Prevent infinite recursion + if (depth > 10) return false; + // Search each icon theme directory for 'theme' + foreach (const QString &baseDir, searchPaths()) + { + QDir dir(baseDir); + if (!dir.exists() || !dir.cd(theme)) continue; + // If there's a cursors subdir, we'll assume this is a cursor theme + if (dir.exists("cursors")) return true; + // If the theme doesn't have an index.theme file, it can't inherit any themes + if (!dir.exists("index.theme")) continue; + // Open the index.theme file, so we can get the list of inherited themes + QMultiMap cfg = loadCfgFile(dir.path()+"/index.theme", true); + QStringList inherits = cfg.values("icon theme/inherits"); + // Recurse through the list of inherited themes, to check if one of them is a cursor theme + // note that items are reversed + for (int f = inherits.size()-1; f >= 0; --f) + { + QString inh = inherits.at(f); + // Avoid possible DoS + if (inh == theme) continue; + if (isCursorTheme(inh, depth+1)) return true; + } + } + return false; +} + +bool XCursorThemeModel::handleDefault(const QDir &themeDir) +{ + QFileInfo info(themeDir.path()); + // If "default" is a symlink + if (info.isSymLink()) + { + QFileInfo target(info.symLinkTarget()); + if (target.exists() && (target.isDir() || target.isSymLink())) mDefaultName = target.fileName(); + return true; + } + // If there's no cursors subdir, or if it's empty + if (!themeDir.exists("cursors") || + QDir(themeDir.path() + "/cursors").entryList(QDir::Files | + QDir::NoDotAndDotDot).isEmpty()) + { + if (themeDir.exists("index.theme")) + { + XCursorThemeData theme(themeDir); + if (!theme.inherits().isEmpty()) mDefaultName = theme.inherits().at(0); + } + return true; + } + mDefaultName = QLatin1String("default"); + return false; +} + +//#define DUMP_FOUND_THEMES +void XCursorThemeModel::processThemeDir(const QDir &themeDir) +{ +#ifdef DUMP_FOUND_THEMES + qDebug() << "looking at:" << themeDir.path(); +#endif + bool haveCursors = themeDir.exists("cursors"); + // Special case handling of "default", since it's usually either a + // symlink to another theme, or an empty theme that inherits another theme + if (mDefaultName.isNull() && themeDir.dirName() == "default") + { + if (handleDefault(themeDir)) return; + } + // If the directory doesn't have a cursors subdir and lacks an + // index.theme file it can't be a cursor theme. + if (!themeDir.exists("index.theme") && !haveCursors) + { + //qDebug() << "IS NOT THEME" << themeDir; + return; + } + // Create a cursor theme object for the theme dir + XCursorThemeData *theme = new XCursorThemeData(themeDir); + // Skip this theme if it's hidden +#ifdef DUMP_FOUND_THEMES + qDebug() << + " theme name:" << theme->name() << + "\n theme title:" << theme->title() << + "\n theme desc:" << theme->description() << + "\n theme sample:" << theme->sample() << + "\n theme inherits:" << theme->inherits(); +#endif + if (theme->isHidden()) + { + //qDebug() << "HIDDEN THEME" << theme->name() << themeDir; + delete theme; + return; + } + // If there's no cursors subdirectory we'll do a recursive scan + // to check if the theme inherits a theme with one + if (!haveCursors) + { + bool foundCursorTheme = false; + foreach (const QString &name, theme->inherits()) + { + if ((foundCursorTheme = isCursorTheme(name))) break; + } + if (!foundCursorTheme) + { + delete theme; + return; + } + } + // Append the theme to the list + mList.append(theme); +} + +void XCursorThemeModel::insertThemes() +{ + // Scan each base dir for Xcursor themes and add them to the list + foreach (const QString &baseDir, searchPaths()) + { + QDir dir(baseDir); + //qDebug() << "TOPLEVEL" << baseDir; + if (!dir.exists()) continue; + //qDebug() << " continue passed"; + // Process each subdir in the directory + foreach (const QString &name, dir.entryList(QDir::AllDirs | + QDir::NoDotAndDotDot | QDir::Readable | QDir::Executable)) + { + //qDebug() << " SUBDIR" << name; + // Don't process the theme if a theme with the same name already exists + // in the list. Xcursor will pick the first one it finds in that case, + // and since we use the same search order, the one Xcursor picks should + // be the one already in the list + if (hasTheme(name)) + { + qDebug() << "duplicate theme:" << dir.path()+name; + } + if (!dir.cd(name)) + { + qDebug() << "can't cd:" << dir.path()+name; + continue; + } + processThemeDir(dir); + dir.cdUp(); // Return to the base dir + } + } + // The theme Xcursor will end up using if no theme is configured + //if (mDefaultName.isNull() || !hasTheme(mDefaultName)) mDefaultName = legacy->name(); +} + +bool XCursorThemeModel::addTheme(const QDir &dir) +{ + XCursorThemeData *theme = new XCursorThemeData(dir); + // Don't add the theme to the list if it's hidden + if (theme->isHidden()) + { + delete theme; + return false; + } + // If an item with the same name already exists in the list, + // we'll remove it before inserting the new one. + for (int i = 0; i < mList.count(); ++i) + { + if (mList.at(i)->hash() == theme->hash()) + { + removeTheme(index(i, 0)); + break; + } + } + // Append the theme to the list + beginInsertRows(QModelIndex(), rowCount(), rowCount()); + mList.append(theme); + endInsertRows(); + return true; +} + +void XCursorThemeModel::removeTheme(const QModelIndex &index) +{ + if (!index.isValid()) return; + beginRemoveRows(QModelIndex(), index.row(), index.row()); + delete mList.takeAt(index.row()); + endRemoveRows(); +} diff --git a/liblxqt-config-cursor/thememodel.h b/liblxqt-config-cursor/thememodel.h new file mode 100644 index 0000000..771c5a2 --- /dev/null +++ b/liblxqt-config-cursor/thememodel.h @@ -0,0 +1,116 @@ +/* Copyright © 2005-2007 Fredrik Höglund + * (c)GPL2 (c)GPL3 + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License version 2 or at your option version 3 as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +/* + * additional code: Ketmar // Vampire Avalon (psyc://ketmar.no-ip.org/~Ketmar) + */ +#ifndef THEMEMODEL_H +#define THEMEMODEL_H + +#include +#include + +class QDir; +class XCursorThemeData; + + +// The two TableView/TreeView columns provided by the model +enum Columns { NameColumn = 0, DescColumn }; + + +/** + * The XCursorThemeModel class provides a model for all locally installed + * Xcursor themes, and the KDE/Qt legacy bitmap theme. + * + * This class automatically scans the locations in the file system from + * which Xcursor loads cursors, and creates an internal list of all + * available cursor themes. + * + * The model provides this theme list to item views in the form of a list + * of rows with two columns; the first column has the theme's descriptive + * name and its sample cursor as its icon, and the second column contains + * the theme's description. + * + * Additional Xcursor themes can be added to a model after it's been + * created, by calling addTheme(), which takes QDir as a parameter, + * with the themes location. The intention is for this function to be + * called when a new Xcursor theme has been installed, after the model + * was instantiated. + * + * The KDE legacy theme is a read-only entry, with the descriptive name + * "KDE Classic", and the internal name "#kde_legacy#". + * + * Calling defaultIndex() will return the index of the theme Xcursor + * will use if the user hasn't explicitly configured a cursor theme. + */ +class XCursorThemeModel : public QAbstractTableModel +{ + Q_OBJECT + +public: + XCursorThemeModel (QObject *parent = 0); + ~XCursorThemeModel (); + + inline int columnCount (const QModelIndex &parent = QModelIndex()) const; + inline int rowCount (const QModelIndex &parent = QModelIndex()) const; + QVariant headerData (int section, Qt::Orientation orientation, int role) const; + QVariant data (const QModelIndex &index, int role) const; + void sort (int column, Qt::SortOrder order = Qt::AscendingOrder); + + /// Returns the CursorTheme at @p index. + const XCursorThemeData *theme (const QModelIndex &index); + + /// Returns the index for the CursorTheme with the internal name @p name, + /// or an invalid index if no matching theme can be found. + QModelIndex findIndex (const QString &name); + + /// Returns the index for the default theme. + QModelIndex defaultIndex (); + + /// Adds the theme in @p dir, and returns @a true if successful or @a false otherwise. + bool addTheme (const QDir &dir); + void removeTheme (const QModelIndex &index); + + /// Returns the list of base dirs Xcursor looks for themes in. + const QStringList searchPaths (); + +private: + bool handleDefault (const QDir &dir); + void processThemeDir (const QDir &dir); + void insertThemes (); + bool hasTheme (const QString &theme) const; + bool isCursorTheme (const QString &theme, const int depth = 0); + +private: + QListmList; + QStringList mBaseDirs; + QString mDefaultName; +}; + +int XCursorThemeModel::rowCount (const QModelIndex &) const +{ + return mList.count(); +} + + +int XCursorThemeModel::columnCount (const QModelIndex &) const +{ + return 2; +} + +#endif diff --git a/liblxqt-config-cursor/translations/lxqt-config-cursor.ts b/liblxqt-config-cursor/translations/lxqt-config-cursor.ts new file mode 100644 index 0000000..77b9f7e --- /dev/null +++ b/liblxqt-config-cursor/translations/lxqt-config-cursor.ts @@ -0,0 +1,68 @@ + + + + + SelectWnd + + + LXQt Mouse Theme Configuration + + + + + Select the cursor theme you want to use (hover preview to test cursor). <b>LXQt session needs restart after this change</b>: + + + + + &Install New Theme... + + + + + &Remove Theme + + + + + XCurTheme error + + + + + You can't remove active theme! + + + + + WarningLabel + + + Form + + + + + LXQt could not find any cursor theme. The default X11 cursor theme will be used instead. LXQt looked in the following directories: + + + + + Show... + + + + + XCursorThemeModel + + + Name + + + + + Description + + + + diff --git a/liblxqt-config-cursor/translations/lxqt-config-cursor_ar.ts b/liblxqt-config-cursor/translations/lxqt-config-cursor_ar.ts new file mode 100644 index 0000000..770f650 --- /dev/null +++ b/liblxqt-config-cursor/translations/lxqt-config-cursor_ar.ts @@ -0,0 +1,77 @@ + + + + + SelectWnd + + + LXQt Mouse Theme Configuration + اعداد شكل فأرة سطح ريزر + + + + Select the cursor theme you want to use (hover preview to test cursor). <b>LXQt session needs restart after this change</b>: + اختر سكل المؤشِّر الذي تريد استخدامه (مرر المؤشِّر متخطيَّاً لمعاينته). +<b>يجب إعادة تشغيل جلسة سطح ريزر بعد هذا التَّغيير</b> + + + + &Install New Theme... + تث&بيت واجهةٍ شكليَّةٍ جديدةٍ... + + + &Set Theme + ت^عيين الواجهة الشَّكليَّة + + + + &Remove Theme + إ&زالة الواجهة الشَّكليَّة + + + &Close + إ&غلاق + + + + XCurTheme error + خطأٌ في الواجهة الشَّكليَّة للمؤشر الرسوميّ + + + + You can't remove active theme! + ﻻ يمكنك إزالة واجهةٍ مفعَّلةٍ + + + + WarningLabel + + + Form + + + + + LXQt could not find any cursor theme. The default X11 cursor theme will be used instead. LXQt looked in the following directories: + + + + + Show... + + + + + XCursorThemeModel + + + Name + الاسم + + + + Description + الوصف + + + diff --git a/liblxqt-config-cursor/translations/lxqt-config-cursor_cs.ts b/liblxqt-config-cursor/translations/lxqt-config-cursor_cs.ts new file mode 100644 index 0000000..8e53646 --- /dev/null +++ b/liblxqt-config-cursor/translations/lxqt-config-cursor_cs.ts @@ -0,0 +1,76 @@ + + + + + SelectWnd + + + LXQt Mouse Theme Configuration + Nastavení motivu myši + + + + Select the cursor theme you want to use (hover preview to test cursor). <b>LXQt session needs restart after this change</b>: + Vyberte motiv ukazovátka, jejž chcete používat (přejeďte myší nad náhledem kvůli vyzkoušení ukazovátka). <b>Sezení LXQt je potřeba po této změně spustit znovu</b>: + + + + &Install New Theme... + Na&instalovat nový motiv... + + + &Set Theme + &Nastavit motiv + + + + &Remove Theme + &Odstranit motiv + + + &Close + &Zavřít + + + + XCurTheme error + Chyba XCurTheme + + + + You can't remove active theme! + Nemůžete odstranit právě nastavený motiv + + + + WarningLabel + + + Form + + + + + LXQt could not find any cursor theme. The default X11 cursor theme will be used instead. LXQt looked in the following directories: + + + + + Show... + + + + + XCursorThemeModel + + + Name + Název + + + + Description + Popis + + + diff --git a/liblxqt-config-cursor/translations/lxqt-config-cursor_cs_CZ.ts b/liblxqt-config-cursor/translations/lxqt-config-cursor_cs_CZ.ts new file mode 100644 index 0000000..b22bd2d --- /dev/null +++ b/liblxqt-config-cursor/translations/lxqt-config-cursor_cs_CZ.ts @@ -0,0 +1,76 @@ + + + + + SelectWnd + + + LXQt Mouse Theme Configuration + Nastavení motivu myši + + + + Select the cursor theme you want to use (hover preview to test cursor). <b>LXQt session needs restart after this change</b>: + Vyberte motiv ukazovátka, jejž chcete používat (přejeďte myší nad náhledem kvůli vyzkoušení ukazovátka). <b>Sezení LXQt je potřeba po této změně spustit znovu</b>: + + + + &Install New Theme... + Na&instalovat nový motiv... + + + &Set Theme + &Nastavit motiv + + + + &Remove Theme + &Odstranit motiv + + + &Close + &Zavřít + + + + XCurTheme error + Chyba XCurTheme + + + + You can't remove active theme! + Nemůžete odstranit právě nastavený motiv + + + + WarningLabel + + + Form + + + + + LXQt could not find any cursor theme. The default X11 cursor theme will be used instead. LXQt looked in the following directories: + + + + + Show... + + + + + XCursorThemeModel + + + Name + Název + + + + Description + Popis + + + diff --git a/liblxqt-config-cursor/translations/lxqt-config-cursor_da_DK.ts b/liblxqt-config-cursor/translations/lxqt-config-cursor_da_DK.ts new file mode 100644 index 0000000..a7f8650 --- /dev/null +++ b/liblxqt-config-cursor/translations/lxqt-config-cursor_da_DK.ts @@ -0,0 +1,77 @@ + + + + + SelectWnd + + + LXQt Mouse Theme Configuration + LXQt Musemarkør Tema Indstillinger + + + + Select the cursor theme you want to use (hover preview to test cursor). <b>LXQt session needs restart after this change</b>: + Vælg det markør tema, du vil bruge (forhåndsvisning for at teste markør). +<b> LXQt session skal genstartes efter denne ændring </ b>: + + + + &Install New Theme... + &Installer Nyt Tema... + + + &Set Theme + &Sæt Tema + + + + &Remove Theme + &Fjern Tema + + + &Close + &Afslut + + + + XCurTheme error + XCurTheme fejl + + + + You can't remove active theme! + Det aktive tema kan ikke fjernes! + + + + WarningLabel + + + Form + + + + + LXQt could not find any cursor theme. The default X11 cursor theme will be used instead. LXQt looked in the following directories: + + + + + Show... + + + + + XCursorThemeModel + + + Name + Navn + + + + Description + Beskrivelse + + + diff --git a/liblxqt-config-cursor/translations/lxqt-config-cursor_de.ts b/liblxqt-config-cursor/translations/lxqt-config-cursor_de.ts new file mode 100644 index 0000000..96fd7a8 --- /dev/null +++ b/liblxqt-config-cursor/translations/lxqt-config-cursor_de.ts @@ -0,0 +1,77 @@ + + + + + SelectWnd + + + LXQt Mouse Theme Configuration + LXQt Mauszeigerdesign Konfiguration + + + + Select the cursor theme you want to use (hover preview to test cursor). <b>LXQt session needs restart after this change</b>: + Wähle das gewünschte Mauszeigerdesign aus (zum Test Maus über Vorschau bewegen) +<b>Die LXQt-Sitzung muss nach dieser Veränderung neu gestartet werden</b>: + + + + &Install New Theme... + &Neues Design installieren... + + + &Set Theme + &Design festlegen + + + + &Remove Theme + D&esign entfernen + + + &Close + &Schließen + + + + XCurTheme error + XcurTheme Fehler + + + + You can't remove active theme! + Das aktive Design kann nicht entfernt werden! + + + + WarningLabel + + + Form + Dialogfenster + + + + LXQt could not find any cursor theme. The default X11 cursor theme will be used instead. LXQt looked in the following directories: + LXQt konnte kein Mauszeigerdesign finden. Stattdessen wird das Default-Mauszeigerdesign von X11 verwendet. LXQt suchte in folgenden Verzeichnissen: + + + + Show... + Anzeigen... + + + + XCursorThemeModel + + + Name + Name + + + + Description + Beschreibung + + + diff --git a/liblxqt-config-cursor/translations/lxqt-config-cursor_el_GR.ts b/liblxqt-config-cursor/translations/lxqt-config-cursor_el_GR.ts new file mode 100644 index 0000000..43aeed7 --- /dev/null +++ b/liblxqt-config-cursor/translations/lxqt-config-cursor_el_GR.ts @@ -0,0 +1,76 @@ + + + + + SelectWnd + + + LXQt Mouse Theme Configuration + Διαμόρφωση θέματος ποντικιού LXQt + + + + Select the cursor theme you want to use (hover preview to test cursor). <b>LXQt session needs restart after this change</b>: + Επιλέξτε το θέμα δείκτη που θέλετε να χρησιμοποιήσετε (κινηθείτε επάνω για προεπισκόπηση). <b>Χρειάζεται επανεκκίνηση της συνεδρίας LXQt μετά την αλλαγή</b>: + + + + &Install New Theme... + &Εγκατάσταση νέου θέματος... + + + &Set Theme + Ε&πιλογή θέματος + + + + &Remove Theme + &Αφαίρεση θέματος + + + &Close + Κλεί&σιμο + + + + XCurTheme error + Σφάλμα του θέματος δείκτη X + + + + You can't remove active theme! + Δεν μπορείτε να αφαιρέσετε το ενεργό θέμα! + + + + WarningLabel + + + Form + + + + + LXQt could not find any cursor theme. The default X11 cursor theme will be used instead. LXQt looked in the following directories: + + + + + Show... + + + + + XCursorThemeModel + + + Name + Όνομα + + + + Description + Περιγραφή + + + diff --git a/liblxqt-config-cursor/translations/lxqt-config-cursor_eo.ts b/liblxqt-config-cursor/translations/lxqt-config-cursor_eo.ts new file mode 100644 index 0000000..2393129 --- /dev/null +++ b/liblxqt-config-cursor/translations/lxqt-config-cursor_eo.ts @@ -0,0 +1,76 @@ + + + + + SelectWnd + + + LXQt Mouse Theme Configuration + Agordoj de etosoj de muso de LXQt + + + + Select the cursor theme you want to use (hover preview to test cursor). <b>LXQt session needs restart after this change</b>: + Elektu la etoson de kursoro, kiun vi volas uzi (ŝveba antaŭrigardo por testi kursoron). <b>Seanco de LXQt postulas restartigon post ol ĉi tiu ŝanĝo</b>: + + + + &Install New Theme... + &Instali novan etoson... + + + &Set Theme + Agordi eto&son + + + + &Remove Theme + Fo&rigi etoson + + + &Close + &Fermi + + + + XCurTheme error + Eraro de XCurTheme + + + + You can't remove active theme! + Vi ne povas forigi aktivan etoson! + + + + WarningLabel + + + Form + + + + + LXQt could not find any cursor theme. The default X11 cursor theme will be used instead. LXQt looked in the following directories: + + + + + Show... + + + + + XCursorThemeModel + + + Name + Nomo + + + + Description + Priskribo + + + diff --git a/liblxqt-config-cursor/translations/lxqt-config-cursor_es.ts b/liblxqt-config-cursor/translations/lxqt-config-cursor_es.ts new file mode 100644 index 0000000..8f49b08 --- /dev/null +++ b/liblxqt-config-cursor/translations/lxqt-config-cursor_es.ts @@ -0,0 +1,76 @@ + + + + + SelectWnd + + + LXQt Mouse Theme Configuration + Configuración de LXQt para el Tema del Ratón + + + + Select the cursor theme you want to use (hover preview to test cursor). <b>LXQt session needs restart after this change</b>: + Seleccione el tema del cursor que desea utilizar (pase el cursor para una vista previa). <b>LXQt necesita reiniciar la sesión después de este cambio </ b>: + + + + &Install New Theme... + &Instalar Nuevo Tema... + + + &Set Theme + &Establecer Tema + + + + &Remove Theme + &Quitar Tema + + + &Close + &Cerrar + + + + XCurTheme error + Error en XCurTheme + + + + You can't remove active theme! + ¡No puedes quitar el tema activo! + + + + WarningLabel + + + Form + + + + + LXQt could not find any cursor theme. The default X11 cursor theme will be used instead. LXQt looked in the following directories: + + + + + Show... + + + + + XCursorThemeModel + + + Name + Nombre + + + + Description + Descripción + + + diff --git a/liblxqt-config-cursor/translations/lxqt-config-cursor_es_VE.ts b/liblxqt-config-cursor/translations/lxqt-config-cursor_es_VE.ts new file mode 100644 index 0000000..5a4feca --- /dev/null +++ b/liblxqt-config-cursor/translations/lxqt-config-cursor_es_VE.ts @@ -0,0 +1,76 @@ + + + + + SelectWnd + + + LXQt Mouse Theme Configuration + Configuracion de tema de raton de LXQt + + + + Select the cursor theme you want to use (hover preview to test cursor). <b>LXQt session needs restart after this change</b>: + Selecciona el cursor del raton que tu desees usar (colocalo encima para ver una previsualizacion) <b>La sesion de LXQt necesita reinicializarse despues de un cambio</b> + + + + &Install New Theme... + &Instalar nuevo tema + + + &Set Theme + A&Signar el tema + + + + &Remove Theme + &Remover el tema + + + &Close + &Cerrar + + + + XCurTheme error + XCurTheme error + + + + You can't remove active theme! + No puedes remover el tema activo! + + + + WarningLabel + + + Form + + + + + LXQt could not find any cursor theme. The default X11 cursor theme will be used instead. LXQt looked in the following directories: + + + + + Show... + + + + + XCursorThemeModel + + + Name + Nombre + + + + Description + Descripcion + + + diff --git a/liblxqt-config-cursor/translations/lxqt-config-cursor_eu.ts b/liblxqt-config-cursor/translations/lxqt-config-cursor_eu.ts new file mode 100644 index 0000000..78c9599 --- /dev/null +++ b/liblxqt-config-cursor/translations/lxqt-config-cursor_eu.ts @@ -0,0 +1,76 @@ + + + + + SelectWnd + + + LXQt Mouse Theme Configuration + LXQt saguaren gaiaren konfigurazioa + + + + Select the cursor theme you want to use (hover preview to test cursor). <b>LXQt session needs restart after this change</b>: + Hautatu erabili nahi duzun kurtsore-gaia (nabarmendu aurrebista kurtsorea probatzeko). <b>LXQt saioa berrabiarazi behar da aldaketa honen ondoren</b>: + + + + &Install New Theme... + &Instalatu gai berria... + + + &Set Theme + &Ezarri gaia + + + + &Remove Theme + &Kendu gaia + + + &Close + &Itxi + + + + XCurTheme error + XCurTheme errorea + + + + You can't remove active theme! + Ezin duzu gai aktiboa kendu! + + + + WarningLabel + + + Form + + + + + LXQt could not find any cursor theme. The default X11 cursor theme will be used instead. LXQt looked in the following directories: + + + + + Show... + + + + + XCursorThemeModel + + + Name + Izena + + + + Description + Deskribapena + + + diff --git a/liblxqt-config-cursor/translations/lxqt-config-cursor_fi.ts b/liblxqt-config-cursor/translations/lxqt-config-cursor_fi.ts new file mode 100644 index 0000000..704e1df --- /dev/null +++ b/liblxqt-config-cursor/translations/lxqt-config-cursor_fi.ts @@ -0,0 +1,76 @@ + + + + + SelectWnd + + + LXQt Mouse Theme Configuration + LXQtin hiiriteeman asetukset + + + + Select the cursor theme you want to use (hover preview to test cursor). <b>LXQt session needs restart after this change</b>: + Valitse haluamasi osoitinteema (käytä esikatselua testataksesi osoitinteemaa). <b>LXQt-istunto tulee käynnistää uudelleen tämän muutoksen jälkeen</b>: + + + + &Install New Theme... + &Asenna uusi teema... + + + &Set Theme + Aseta &teema + + + + &Remove Theme + &Poista teema + + + &Close + &Sulje + + + + XCurTheme error + XCurTheme-virhe + + + + You can't remove active theme! + Käytössä olevaa teemaa ei voi poistaa! + + + + WarningLabel + + + Form + + + + + LXQt could not find any cursor theme. The default X11 cursor theme will be used instead. LXQt looked in the following directories: + + + + + Show... + + + + + XCursorThemeModel + + + Name + Nimi + + + + Description + Kuvaus + + + diff --git a/liblxqt-config-cursor/translations/lxqt-config-cursor_fr_FR.ts b/liblxqt-config-cursor/translations/lxqt-config-cursor_fr_FR.ts new file mode 100644 index 0000000..0152194 --- /dev/null +++ b/liblxqt-config-cursor/translations/lxqt-config-cursor_fr_FR.ts @@ -0,0 +1,72 @@ + + + + + SelectWnd + + + LXQt Mouse Theme Configuration + + + + + Select the cursor theme you want to use (hover preview to test cursor). <b>LXQt session needs restart after this change</b>: + + + + + &Install New Theme... + + + + + &Remove Theme + + + + &Close + &Fermer + + + + XCurTheme error + + + + + You can't remove active theme! + + + + + WarningLabel + + + Form + + + + + LXQt could not find any cursor theme. The default X11 cursor theme will be used instead. LXQt looked in the following directories: + + + + + Show... + + + + + XCursorThemeModel + + + Name + + + + + Description + + + + diff --git a/liblxqt-config-cursor/translations/lxqt-config-cursor_hu_HU.ts b/liblxqt-config-cursor/translations/lxqt-config-cursor_hu_HU.ts new file mode 100644 index 0000000..3797b0c --- /dev/null +++ b/liblxqt-config-cursor/translations/lxqt-config-cursor_hu_HU.ts @@ -0,0 +1,72 @@ + + + + + SelectWnd + + + LXQt Mouse Theme Configuration + + + + + Select the cursor theme you want to use (hover preview to test cursor). <b>LXQt session needs restart after this change</b>: + + + + + &Install New Theme... + + + + + &Remove Theme + + + + &Close + &Bezárás + + + + XCurTheme error + + + + + You can't remove active theme! + + + + + WarningLabel + + + Form + + + + + LXQt could not find any cursor theme. The default X11 cursor theme will be used instead. LXQt looked in the following directories: + + + + + Show... + + + + + XCursorThemeModel + + + Name + + + + + Description + + + + diff --git a/liblxqt-config-cursor/translations/lxqt-config-cursor_it_IT.ts b/liblxqt-config-cursor/translations/lxqt-config-cursor_it_IT.ts new file mode 100644 index 0000000..e9d095c --- /dev/null +++ b/liblxqt-config-cursor/translations/lxqt-config-cursor_it_IT.ts @@ -0,0 +1,77 @@ + + + + + SelectWnd + + + LXQt Mouse Theme Configuration + Configurazione del tema del mouse di LXQt + + + + Select the cursor theme you want to use (hover preview to test cursor). <b>LXQt session needs restart after this change</b>: + Seleziona il tema del cursore che vuoi utilizzare (passa sull'anteprima per provare il cursore). +<b>La sessione di LXQt deve essere riavviata dopo questa modifica</b>: + + + + &Install New Theme... + &Installa un nuovo tema... + + + &Set Theme + &Imposta il tema + + + + &Remove Theme + &Rimuovi il tema + + + &Close + &Chiudi + + + + XCurTheme error + Errore XCurTheme + + + + You can't remove active theme! + Non puoi rimuovere il tema attivo! + + + + WarningLabel + + + Form + + + + + LXQt could not find any cursor theme. The default X11 cursor theme will be used instead. LXQt looked in the following directories: + + + + + Show... + + + + + XCursorThemeModel + + + Name + Nome + + + + Description + Descrizione + + + diff --git a/liblxqt-config-cursor/translations/lxqt-config-cursor_ja.ts b/liblxqt-config-cursor/translations/lxqt-config-cursor_ja.ts new file mode 100644 index 0000000..278331c --- /dev/null +++ b/liblxqt-config-cursor/translations/lxqt-config-cursor_ja.ts @@ -0,0 +1,68 @@ + + + + + SelectWnd + + + LXQt Mouse Theme Configuration + LXQtマウステーマの設定 + + + + Select the cursor theme you want to use (hover preview to test cursor). <b>LXQt session needs restart after this change</b>: + 使いたいカーソルテーマを選択 (プレビューをテストカーソルに合わせます). <b>LXQtセッションはこの変更後に再起動が必要です</b>: + + + + &Install New Theme... + 新しいテーマのインストール...(&I) + + + + &Remove Theme + テーマの削除(&R) + + + + XCurTheme error + XCurTheme エラー + + + + You can't remove active theme! + アクティブなテーマは削除できません! + + + + WarningLabel + + + Form + フォーム + + + + LXQt could not find any cursor theme. The default X11 cursor theme will be used instead. LXQt looked in the following directories: + カーソルテーマを見つけられませんでした。代わりに、デフォルトのX11カーソルテーマが使われます。LXQtは以下のディレクトリーを検索しました: + + + + Show... + 表示 + + + + XCursorThemeModel + + + Name + 名称 + + + + Description + 説明 + + + diff --git a/liblxqt-config-cursor/translations/lxqt-config-cursor_lt.ts b/liblxqt-config-cursor/translations/lxqt-config-cursor_lt.ts new file mode 100644 index 0000000..fc5ebc8 --- /dev/null +++ b/liblxqt-config-cursor/translations/lxqt-config-cursor_lt.ts @@ -0,0 +1,72 @@ + + + + + SelectWnd + + + LXQt Mouse Theme Configuration + + + + + Select the cursor theme you want to use (hover preview to test cursor). <b>LXQt session needs restart after this change</b>: + + + + + &Install New Theme... + + + + + &Remove Theme + + + + &Close + &Užverti + + + + XCurTheme error + + + + + You can't remove active theme! + + + + + WarningLabel + + + Form + + + + + LXQt could not find any cursor theme. The default X11 cursor theme will be used instead. LXQt looked in the following directories: + + + + + Show... + + + + + XCursorThemeModel + + + Name + + + + + Description + + + + diff --git a/liblxqt-config-cursor/translations/lxqt-config-cursor_nl.ts b/liblxqt-config-cursor/translations/lxqt-config-cursor_nl.ts new file mode 100644 index 0000000..16d97a1 --- /dev/null +++ b/liblxqt-config-cursor/translations/lxqt-config-cursor_nl.ts @@ -0,0 +1,72 @@ + + + + + SelectWnd + + + LXQt Mouse Theme Configuration + + + + + Select the cursor theme you want to use (hover preview to test cursor). <b>LXQt session needs restart after this change</b>: + + + + + &Install New Theme... + + + + + &Remove Theme + + + + &Close + &Sluiten + + + + XCurTheme error + + + + + You can't remove active theme! + + + + + WarningLabel + + + Form + + + + + LXQt could not find any cursor theme. The default X11 cursor theme will be used instead. LXQt looked in the following directories: + + + + + Show... + + + + + XCursorThemeModel + + + Name + + + + + Description + + + + diff --git a/liblxqt-config-cursor/translations/lxqt-config-cursor_pl_PL.ts b/liblxqt-config-cursor/translations/lxqt-config-cursor_pl_PL.ts new file mode 100644 index 0000000..754530d --- /dev/null +++ b/liblxqt-config-cursor/translations/lxqt-config-cursor_pl_PL.ts @@ -0,0 +1,77 @@ + + + + + SelectWnd + + + LXQt Mouse Theme Configuration + Wygląd kursora + + + + Select the cursor theme you want to use (hover preview to test cursor). <b>LXQt session needs restart after this change</b>: + Wybierz motyw kursora ( najedz kursorem na podgląd by przetestować): <b> +Wymagane jest ponowne uruchomienie sesji </b>: + + + + &Install New Theme... + &Zainstaluj Nowe Motywy + + + &Set Theme + &Wybierz Motyw + + + + &Remove Theme + &Usuń Motyw + + + &Close + &Zamknij + + + + XCurTheme error + Błąd XCurTheme + + + + You can't remove active theme! + Nie możesz usunąć aktywnego motywu + + + + WarningLabel + + + Form + + + + + LXQt could not find any cursor theme. The default X11 cursor theme will be used instead. LXQt looked in the following directories: + + + + + Show... + + + + + XCursorThemeModel + + + Name + Nazwa + + + + Description + Opis + + + diff --git a/liblxqt-config-cursor/translations/lxqt-config-cursor_pt.ts b/liblxqt-config-cursor/translations/lxqt-config-cursor_pt.ts new file mode 100644 index 0000000..a042217 --- /dev/null +++ b/liblxqt-config-cursor/translations/lxqt-config-cursor_pt.ts @@ -0,0 +1,76 @@ + + + + + SelectWnd + + + LXQt Mouse Theme Configuration + Definições do tema de cursor do LXQt + + + + Select the cursor theme you want to use (hover preview to test cursor). <b>LXQt session needs restart after this change</b>: + Escolha o tema de cursor a utilizar (passe com o rato para testar). <b>Tem que reiniciar o LXQt a sessão após a alteração</b>: + + + + &Install New Theme... + &Instalar novo tema... + + + &Set Theme + &Definir tema + + + + &Remove Theme + &Remover tema + + + &Close + Fe&char + + + + XCurTheme error + Erro XCurTheme + + + + You can't remove active theme! + Não pode remover o tema ativo! + + + + WarningLabel + + + Form + Formulário + + + + LXQt could not find any cursor theme. The default X11 cursor theme will be used instead. LXQt looked in the following directories: + O LxQt não encontrou quaisquer temas de cursor. Será utilizado o tema de cursor X11. O LxQt procurou nestes diretórios: + + + + Show... + Mostrar... + + + + XCursorThemeModel + + + Name + Nome + + + + Description + Descrição + + + diff --git a/liblxqt-config-cursor/translations/lxqt-config-cursor_pt_BR.ts b/liblxqt-config-cursor/translations/lxqt-config-cursor_pt_BR.ts new file mode 100644 index 0000000..6e2214a --- /dev/null +++ b/liblxqt-config-cursor/translations/lxqt-config-cursor_pt_BR.ts @@ -0,0 +1,76 @@ + + + + + SelectWnd + + + LXQt Mouse Theme Configuration + Configuração Do Tema Do Mouse + + + + Select the cursor theme you want to use (hover preview to test cursor). <b>LXQt session needs restart after this change</b>: + Selecione o tema do cursor que você deseja usar (pairar visualização para testar o cursor). <b>A sessão LXQt precisa reiniciar após esta mudança</b>: + + + + &Install New Theme... + &Instalar Novo Tema... + + + &Set Theme + &Definir Tema + + + + &Remove Theme + &Remover Tema + + + &Close + &Fechar + + + + XCurTheme error + Erro XCurTheme + + + + You can't remove active theme! + Você não pode remover o tema ativo! + + + + WarningLabel + + + Form + + + + + LXQt could not find any cursor theme. The default X11 cursor theme will be used instead. LXQt looked in the following directories: + + + + + Show... + + + + + XCursorThemeModel + + + Name + Nome + + + + Description + Descrição + + + diff --git a/liblxqt-config-cursor/translations/lxqt-config-cursor_ro_RO.ts b/liblxqt-config-cursor/translations/lxqt-config-cursor_ro_RO.ts new file mode 100644 index 0000000..9e3fb26 --- /dev/null +++ b/liblxqt-config-cursor/translations/lxqt-config-cursor_ro_RO.ts @@ -0,0 +1,76 @@ + + + + + SelectWnd + + + LXQt Mouse Theme Configuration + Configurare temă maus LXQt + + + + Select the cursor theme you want to use (hover preview to test cursor). <b>LXQt session needs restart after this change</b>: + Selectați tema de cursor pe care doriți să o utilizați (treceți peste cu mausul pentru a testa cursorul)</b>Sesiunea LXQt necesită o repornire după această modificare</b>: + + + + &Install New Theme... + &Instalează temă nouă... + + + &Set Theme + &Setează tema + + + + &Remove Theme + Elimină tema + + + &Close + În&chide + + + + XCurTheme error + Eroare XCurTheme + + + + You can't remove active theme! + Nu se poate elimina tema activă! + + + + WarningLabel + + + Form + + + + + LXQt could not find any cursor theme. The default X11 cursor theme will be used instead. LXQt looked in the following directories: + + + + + Show... + + + + + XCursorThemeModel + + + Name + Nume + + + + Description + Descriere + + + diff --git a/liblxqt-config-cursor/translations/lxqt-config-cursor_ru.ts b/liblxqt-config-cursor/translations/lxqt-config-cursor_ru.ts new file mode 100644 index 0000000..8ee0ad0 --- /dev/null +++ b/liblxqt-config-cursor/translations/lxqt-config-cursor_ru.ts @@ -0,0 +1,68 @@ + + + + + SelectWnd + + + LXQt Mouse Theme Configuration + Настройка темы курсора LXQt + + + + Select the cursor theme you want to use (hover preview to test cursor). <b>LXQt session needs restart after this change</b>: + Выберите тему курсора, которую вы хотите использовать (наведите курсор на область предварительного просмотра для проверки). <b>Сессию LXQt нужно перезапустить после изменений</b>: + + + + &Install New Theme... + &Установить новую тему… + + + + &Remove Theme + &Удалить тему + + + + XCurTheme error + Ошибка XCurTheme + + + + You can't remove active theme! + Невозможно удалить активную тему! + + + + WarningLabel + + + Form + + + + + LXQt could not find any cursor theme. The default X11 cursor theme will be used instead. LXQt looked in the following directories: + LXQt не смог найти какую-нибудь тему курсора. Будет использована тема X11 по-умолчанию. LXQt искал в следующих папках: + + + + Show... + Показать… + + + + XCursorThemeModel + + + Name + Имя + + + + Description + Описание + + + diff --git a/liblxqt-config-cursor/translations/lxqt-config-cursor_ru_RU.ts b/liblxqt-config-cursor/translations/lxqt-config-cursor_ru_RU.ts new file mode 100644 index 0000000..8616c2a --- /dev/null +++ b/liblxqt-config-cursor/translations/lxqt-config-cursor_ru_RU.ts @@ -0,0 +1,68 @@ + + + + + SelectWnd + + + LXQt Mouse Theme Configuration + Настройка темы курсора LXQt + + + + Select the cursor theme you want to use (hover preview to test cursor). <b>LXQt session needs restart after this change</b>: + Выберите тему курсора, которую вы хотите использовать (наведите курсор на область предварительного просмотра для проверки). <b>Сессию LXQt нужно перезапустить после изменений</b>: + + + + &Install New Theme... + &Установить новую тему… + + + + &Remove Theme + &Удалить тему + + + + XCurTheme error + Ошибка XCurTheme + + + + You can't remove active theme! + Невозможно удалить активную тему! + + + + WarningLabel + + + Form + + + + + LXQt could not find any cursor theme. The default X11 cursor theme will be used instead. LXQt looked in the following directories: + LXQt не смог найти какую-нибудь тему курсора. Будет использована тема X11 по-умолчанию. LXQt искал в следующих папках: + + + + Show... + Показать… + + + + XCursorThemeModel + + + Name + Имя + + + + Description + Описание + + + diff --git a/liblxqt-config-cursor/translations/lxqt-config-cursor_sl.ts b/liblxqt-config-cursor/translations/lxqt-config-cursor_sl.ts new file mode 100644 index 0000000..7779b50 --- /dev/null +++ b/liblxqt-config-cursor/translations/lxqt-config-cursor_sl.ts @@ -0,0 +1,72 @@ + + + + + SelectWnd + + + LXQt Mouse Theme Configuration + + + + + Select the cursor theme you want to use (hover preview to test cursor). <b>LXQt session needs restart after this change</b>: + + + + + &Install New Theme... + + + + + &Remove Theme + + + + &Close + &Zapri + + + + XCurTheme error + + + + + You can't remove active theme! + + + + + WarningLabel + + + Form + + + + + LXQt could not find any cursor theme. The default X11 cursor theme will be used instead. LXQt looked in the following directories: + + + + + Show... + + + + + XCursorThemeModel + + + Name + + + + + Description + + + + diff --git a/liblxqt-config-cursor/translations/lxqt-config-cursor_th_TH.ts b/liblxqt-config-cursor/translations/lxqt-config-cursor_th_TH.ts new file mode 100644 index 0000000..63df882 --- /dev/null +++ b/liblxqt-config-cursor/translations/lxqt-config-cursor_th_TH.ts @@ -0,0 +1,76 @@ + + + + + SelectWnd + + + LXQt Mouse Theme Configuration + การตั้งค่าชุดตกแต่งเมาส์ LXQt + + + + Select the cursor theme you want to use (hover preview to test cursor). <b>LXQt session needs restart after this change</b>: + เลือกชุดตกแต่งเคอร์เซอร์ที่คุณต้องการจะใช้ (วางเคอร์เซอร์ไว้บนตัวอย่างเพื่อทดสอบมัน). <b>วาระงาน LXQt จำเป็นต้องเริ่มใหม่หลังการเปลี่ยนแปลงนี้</b>: + + + + &Install New Theme... + ติดตั้งชุด&ตกแต่ง... + + + &Set Theme + &ใช้เป็นชุดตกแต่ง + + + + &Remove Theme + &ลบชุดตกแต่ง + + + &Close + ปิ&ด + + + + XCurTheme error + XCurTheme ขัดข้อง + + + + You can't remove active theme! + คุณไม่สามารถลบชุดตกแต่งที่กำลังใช้งานอยู่ได้ + + + + WarningLabel + + + Form + + + + + LXQt could not find any cursor theme. The default X11 cursor theme will be used instead. LXQt looked in the following directories: + + + + + Show... + + + + + XCursorThemeModel + + + Name + ชื่อ + + + + Description + รายละเอียด + + + diff --git a/liblxqt-config-cursor/translations/lxqt-config-cursor_tr.ts b/liblxqt-config-cursor/translations/lxqt-config-cursor_tr.ts new file mode 100644 index 0000000..d2368d5 --- /dev/null +++ b/liblxqt-config-cursor/translations/lxqt-config-cursor_tr.ts @@ -0,0 +1,72 @@ + + + + + SelectWnd + + + LXQt Mouse Theme Configuration + + + + + Select the cursor theme you want to use (hover preview to test cursor). <b>LXQt session needs restart after this change</b>: + + + + + &Install New Theme... + + + + + &Remove Theme + + + + &Close + &Kapat + + + + XCurTheme error + + + + + You can't remove active theme! + + + + + WarningLabel + + + Form + + + + + LXQt could not find any cursor theme. The default X11 cursor theme will be used instead. LXQt looked in the following directories: + + + + + Show... + + + + + XCursorThemeModel + + + Name + + + + + Description + + + + diff --git a/liblxqt-config-cursor/translations/lxqt-config-cursor_uk.ts b/liblxqt-config-cursor/translations/lxqt-config-cursor_uk.ts new file mode 100644 index 0000000..6df2660 --- /dev/null +++ b/liblxqt-config-cursor/translations/lxqt-config-cursor_uk.ts @@ -0,0 +1,76 @@ + + + + + SelectWnd + + + LXQt Mouse Theme Configuration + Налаштування тем миші LXQt + + + + Select the cursor theme you want to use (hover preview to test cursor). <b>LXQt session needs restart after this change</b>: + Оберіть тему курсорів, яку Ви бажаєте використовувати (наведіть на попереднй перегляд для перевірки курсору). <b>Сеанс LXQt потребує перезапуску щоб ці зміни подіяли</b>: + + + + &Install New Theme... + &Встановити нову тему... + + + &Set Theme + &Призначити тему + + + + &Remove Theme + Вилу&чити тему + + + &Close + &Закрити + + + + XCurTheme error + Збій XCurTheme + + + + You can't remove active theme! + Неможливо вилучити активну тему! + + + + WarningLabel + + + Form + + + + + LXQt could not find any cursor theme. The default X11 cursor theme will be used instead. LXQt looked in the following directories: + + + + + Show... + + + + + XCursorThemeModel + + + Name + Ім'я + + + + Description + Опис + + + diff --git a/liblxqt-config-cursor/translations/lxqt-config-cursor_zh_CN.ts b/liblxqt-config-cursor/translations/lxqt-config-cursor_zh_CN.ts new file mode 100644 index 0000000..cc24ebd --- /dev/null +++ b/liblxqt-config-cursor/translations/lxqt-config-cursor_zh_CN.ts @@ -0,0 +1,76 @@ + + + + + SelectWnd + + + LXQt Mouse Theme Configuration + LXQt 鼠标主题配置 + + + + Select the cursor theme you want to use (hover preview to test cursor). <b>LXQt session needs restart after this change</b>: + 选择要使用的游标主题(鼠标放到项目上可以预览)。<b>修改后需要重启LXQt 会话。</b>: + + + + &Install New Theme... + 安装新主题(&I)... + + + &Set Theme + 设置主题(&S) + + + + &Remove Theme + 删除主题(&R) + + + &Close + &关闭 + + + + XCurTheme error + XCurTheme 错误 + + + + You can't remove active theme! + 无法删除使用中的主题! + + + + WarningLabel + + + Form + + + + + LXQt could not find any cursor theme. The default X11 cursor theme will be used instead. LXQt looked in the following directories: + + + + + Show... + + + + + XCursorThemeModel + + + Name + 名称 + + + + Description + 描述 + + + diff --git a/liblxqt-config-cursor/translations/lxqt-config-cursor_zh_TW.ts b/liblxqt-config-cursor/translations/lxqt-config-cursor_zh_TW.ts new file mode 100644 index 0000000..e76d314 --- /dev/null +++ b/liblxqt-config-cursor/translations/lxqt-config-cursor_zh_TW.ts @@ -0,0 +1,77 @@ + + + + + SelectWnd + + + LXQt Mouse Theme Configuration + LXQt滑鼠游標主題設定 + + + + Select the cursor theme you want to use (hover preview to test cursor). <b>LXQt session needs restart after this change</b>: + 選擇您喜歡的游標主題 (檢視來回移動來測試游標) 。 +<b>套用改變需要重新啟動LXQt會話</b>: + + + + &Install New Theme... + 安裝新主題...(&I) + + + &Set Theme + 設為主題(&S) + + + + &Remove Theme + 移除主題(&R) + + + &Close + 關閉(&C) + + + + XCurTheme error + XCurTheme錯誤 + + + + You can't remove active theme! + 您無法移除正在套用的主題! + + + + WarningLabel + + + Form + + + + + LXQt could not find any cursor theme. The default X11 cursor theme will be used instead. LXQt looked in the following directories: + + + + + Show... + + + + + XCursorThemeModel + + + Name + 名稱 + + + + Description + 描述 + + + diff --git a/liblxqt-config-cursor/ui/selectwnd.ui b/liblxqt-config-cursor/ui/selectwnd.ui new file mode 100644 index 0000000..f6cd6b9 --- /dev/null +++ b/liblxqt-config-cursor/ui/selectwnd.ui @@ -0,0 +1,114 @@ + + + SelectWnd + + + + 0 + 0 + 384 + 353 + + + + LXQt Mouse Theme Configuration + + + + + + Select the cursor theme you want to use (hover preview to test cursor). <b>LXQt session needs restart after this change</b>: + + + true + + + + + + + + + + + 0 + 0 + + + + + 0 + 48 + + + + + + + + QAbstractItemView::NoEditTriggers + + + false + + + true + + + QAbstractItemView::ScrollPerPixel + + + + + + + Qt::Horizontal + + + + 174 + 20 + + + + + + + + false + + + &Install New Theme... + + + + + + + &Remove Theme + + + + + + + + PreviewWidget + QWidget +
previewwidget.h
+
+ + WarningLabel + QWidget +
warninglabel.h
+ 1 +
+
+ + lbThemes + btInstall + btRemove + + + +
diff --git a/liblxqt-config-cursor/ui/warninglabel.ui b/liblxqt-config-cursor/ui/warninglabel.ui new file mode 100644 index 0000000..b58b367 --- /dev/null +++ b/liblxqt-config-cursor/ui/warninglabel.ui @@ -0,0 +1,64 @@ + + + WarningLabel + + + + 0 + 0 + 334 + 72 + + + + Form + + + + + + + + + 0 + 0 + + + + + 64 + 64 + + + + + + + + + 0 + 0 + + + + LXQt could not find any cursor theme. The default X11 cursor theme will be used instead. LXQt looked in the following directories: + + + true + + + + + + + Show... + + + + + + + + + + diff --git a/liblxqt-config-cursor/warninglabel.cpp b/liblxqt-config-cursor/warninglabel.cpp new file mode 100644 index 0000000..ea37b7e --- /dev/null +++ b/liblxqt-config-cursor/warninglabel.cpp @@ -0,0 +1,43 @@ +/* BEGIN_COMMON_COPYRIGHT_HEADER + * (c)LGPL2+ + * + * LXQt - a lightweight, Qt based, desktop toolset + * http://razor-qt.org + * + * Copyright: 2010-2012 Razor team + * Authors: + * Petr Vanek + * + * This program or library is free software; you can redistribute it + * and/or modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + * + * END_COMMON_COPYRIGHT_HEADER */ + +#include + +#include "warninglabel.h" + + + +WarningLabel::WarningLabel(QWidget *parent) + : QWidget(parent) +{ + setupUi(this); + + iconLabel->setPixmap(XdgIcon::fromTheme("dialog-warning").pixmap(64, 64)); + + connect(showDirButton, SIGNAL(pressed()), + this, SIGNAL(showDirInfo())); +} diff --git a/liblxqt-config-cursor/warninglabel.h b/liblxqt-config-cursor/warninglabel.h new file mode 100644 index 0000000..60fcf17 --- /dev/null +++ b/liblxqt-config-cursor/warninglabel.h @@ -0,0 +1,47 @@ +/* BEGIN_COMMON_COPYRIGHT_HEADER + * (c)LGPL2+ + * + * LXQt - a lightweight, Qt based, desktop toolset + * http://razor-qt.org + * + * Copyright: 2010-2012 Razor team + * Authors: + * Petr Vanek + * + * This program or library is free software; you can redistribute it + * and/or modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + * + * END_COMMON_COPYRIGHT_HEADER */ + +#ifndef WARNINGLABEL_H +#define WARNINGLABEL_H + +#include "ui_warninglabel.h" + + +class WarningLabel : public QWidget, public Ui::WarningLabel +{ + Q_OBJECT + +public: + WarningLabel (QWidget *parent=0); + + QPoint buttonPos() { return showDirButton->pos(); } + +signals: + void showDirInfo(); +}; + +#endif diff --git a/liblxqt-config-cursor/xcr/xcrimg.cpp b/liblxqt-config-cursor/xcr/xcrimg.cpp new file mode 100644 index 0000000..3caa8d0 --- /dev/null +++ b/liblxqt-config-cursor/xcr/xcrimg.cpp @@ -0,0 +1,262 @@ +/* coded by Ketmar // Vampire Avalon (psyc://ketmar.no-ip.org/~Ketmar) + * (c)DWTFYW + * + * This program is free software. It comes without any warranty, to + * the extent permitted by applicable law. You can redistribute it + * and/or modify it under the terms of the Do What The Fuck You Want + * To Public License, Version 2, as published by Sam Hocevar. See + * http://sam.zoy.org/wtfpl/COPYING for more details. + */ +#include + +#include "xcrimg.h" + +#include +#include +#include +#include +#include +#include + +#include + + +#include +#include +#include + + +inline static quint8 alphaPreMul (quint8 clr, quint8 alpha) { + quint32 c32 = clr, a32 = alpha; + c32 = c32*a32/255; + if (c32 > a32) c32 = a32; + return c32&0xff; +} + + +static int nominalCursorSize (int iconSize) { + for (int i = 512; i > 8; i /= 2) { + if (i < iconSize) return i; + if (int(i*0.75) < iconSize) return int(i*0.75); + } + return 8; +} + + +static void baPutDW (QByteArray &ba, quint32 v) { + ba.append('\0'); ba.append('\0'); + ba.append('\0'); ba.append('\0'); + uchar *d = (uchar *)ba.data(); + d += ba.size()-4; + for (int f = 4; f > 0; f--, d++) { + *d = (v&0xff); + v >>= 8; + } +} + + +void XCursorImage::convertARGB2PreMul (QImage &img) { + switch (img.format()) { + case QImage::Format_ARGB32_Premultiplied: return; + case QImage::Format_ARGB32: break; + default: img.convertToFormat(QImage::Format_ARGB32/*_Premultiplied*/); + } + img.convertToFormat(QImage::Format_ARGB32_Premultiplied); // this shouldn't convert anything + // so convert it! + for (int y = img.height()-1; y >= 0; y--) { + quint8 *line = (quint8 *)img.scanLine(y); + for (int x = 0; x < img.width(); x++, line += 4) { + // convert to 'premultiplied' + line[0] = alphaPreMul(line[0], line[3]); + line[1] = alphaPreMul(line[1], line[3]); + line[2] = alphaPreMul(line[2], line[3]); + } + } +} + + +/////////////////////////////////////////////////////////////////////////////// +XCursorImage::XCursorImage (const QString &aName, const QImage &aImg, int aXHot, int aYHot, quint32 aDelay, quint32 aCSize) : + mIsValid(true), mName(aName), mImage(0), mDelay(aDelay), mXHot(aXHot), mYHot(aYHot), mCSize(aCSize) +{ + mImage = new QImage(aImg.copy()); + convertARGB2PreMul(*mImage); +} + + +XCursorImage::XCursorImage (const QString &aName) : + mIsValid(false), mName(aName), mImage(0), mDelay(50), mXHot(0), mYHot(0) +{ +} + + +XCursorImage::~XCursorImage () { + delete mImage; // or memory will leak! +} + + +QPixmap XCursorImage::icon () const { + if (mIcon.isNull()) mIcon = createIcon(); + return mIcon; +} + + +QCursor XCursorImage::cursor () const { + return QCursor(icon(), mXHot, mYHot); +} + + +QImage XCursorImage::image (int size) const { + if (size == -1) size = XcursorGetDefaultSize(QX11Info::display()); + if (!mImage) return QImage(); + return mImage->copy(); +} + + +QPixmap XCursorImage::createIcon () const { + QPixmap pixmap; + int iconSize = QApplication::style()->pixelMetric(QStyle::PM_LargeIconSize); + int cursorSize = nominalCursorSize(iconSize); + QSize size = QSize(iconSize, iconSize); + QImage img = image(cursorSize); + if (!img.isNull()) { + // Scale the image if it's larger than the preferred icon size + if (img.width() > size.width() || img.height() > size.height()) + img = img.scaled(size, Qt::KeepAspectRatio, Qt::SmoothTransformation); + pixmap = QPixmap::fromImage(img); + } + return pixmap; +} + + +quint32 XCursorImage::xcurSize () const { + if (!mImage || !mIsValid) return 0; + quint32 res = 9*4; // header + res += mImage->width()*mImage->height()*4; + return res; +} + + +void XCursorImage::genXCursorImg (QByteArray &res) const { + if (!mImage || !mIsValid) return; + baPutDW(res, 36); // header size + baPutDW(res, 0xfffd0002); // chunk type + baPutDW(res, mCSize); // subtype + baPutDW(res, 1); // version + baPutDW(res, (quint32)mImage->width()); + baPutDW(res, (quint32)mImage->height()); + baPutDW(res, (quint32)mXHot); + baPutDW(res, (quint32)mYHot); + baPutDW(res, (quint32)mDelay); + // now put the pixels + QImage i = mImage->copy(); + i.convertToFormat(QImage::Format_ARGB32_Premultiplied); + //i.convertToFormat(QImage::Format_ARGB32); + for (int y = 0; y < i.height(); y++) { + const uchar *sl = i.scanLine(y); + const quint32 *d = (const quint32 *)sl; + for (int x = 0; x < i.width(); x++, d++) baPutDW(res, *d); + } +} + + +/////////////////////////////////////////////////////////////////////////////// +XCursorImages::XCursorImages (const QString &aName, const QString &aPath) : + mName(aName), mPath(aPath), mTitle(""), mAuthor(""), mLicense(""), + mEMail(""), mSite(""), mDescr(""), mIM("") +{ +} + + +XCursorImages::~XCursorImages () { + qDeleteAll(mList); + mList.clear(); +} + + +QByteArray XCursorImages::genXCursor () const { + QByteArray res; + // build 'credits' block + QByteArray crdBA[7]; + { + QStringList crb; + crb << mAuthor << mLicense << mDescr << mTitle << mEMail << mSite << mIM; + for (int f = 0; f < crb.size(); f++) { + QString s(crb[f]); + if (s.isEmpty()) crdBA[f].clear(); else crdBA[f] = s.toUtf8(); + } + } + // + res.append("Xcur"); // signature + baPutDW(res, 16); // header size + baPutDW(res, 65536); // version number + // TOC + quint32 cnt = 0; + foreach (const XCursorImage *i, mList) if (i->xcurSize() > 0) cnt++; + // 'credits' + for (int f = 0; f < 7; f++) if (!crdBA[f].isEmpty()) cnt++; + // + baPutDW(res, cnt); // # of chunks + if (!cnt) return res; + quint32 dataOfs = cnt*(3*4)+16; + // add 'credits' chunks + for (int f = 0; f < 7; f++) { + if (crdBA[f].isEmpty()) continue; + baPutDW(res, 0xfffd0001); // entry type + baPutDW(res, f+1); // subtype + baPutDW(res, dataOfs); // offset + dataOfs += crdBA[f].size()+20; + } + // add image chunks + foreach (const XCursorImage *i, mList) { + quint32 isz = i->xcurSize(); + if (!isz) continue; + baPutDW(res, 0xfffd0002); // entry type + baPutDW(res, i->csize()); // subtype + baPutDW(res, dataOfs); // offset + dataOfs += isz; + } + // credits + for (int f = 0; f < 7; f++) { + if (crdBA[f].isEmpty()) continue; + baPutDW(res, 20); // header size + baPutDW(res, 0xfffd0001); // entry type + baPutDW(res, f+1); // subtype + baPutDW(res, 1); // version + baPutDW(res, crdBA[f].size()); // length + res.append(crdBA[f]); + } + // images + foreach (const XCursorImage *i, mList) { + quint32 isz = i->xcurSize(); + if (!isz) continue; + i->genXCursorImg(res); + } + return res; +} + + +QImage XCursorImages::buildImage () const { + int width = 0, height = 0, cnt = 0; + foreach (const XCursorImage *i, mList) { + if (i->xcurSize() > 0) { + QImage img = i->image(); + width = qMax(width, img.width()); + height = qMax(height, img.height()); + ++cnt; + } + } + //qDebug() << cnt << "images; size" << width << "by" << height; + + QImage res(width*cnt, height, QImage::Format_ARGB32); + QPainter p(&res); + int x = 0; + foreach (const XCursorImage *i, mList) { + if (i->xcurSize() > 0) { + QImage img = i->image(); + p.drawImage(QPoint(x, 0), img); + x += img.width(); + } + } + return res; +} diff --git a/liblxqt-config-cursor/xcr/xcrimg.h b/liblxqt-config-cursor/xcr/xcrimg.h new file mode 100644 index 0000000..efcfdbe --- /dev/null +++ b/liblxqt-config-cursor/xcr/xcrimg.h @@ -0,0 +1,116 @@ +/* coded by Ketmar // Vampire Avalon (psyc://ketmar.no-ip.org/~Ketmar) + * (c)DWTFYW + * + * This program is free software. It comes without any warranty, to + * the extent permitted by applicable law. You can redistribute it + * and/or modify it under the terms of the Do What The Fuck You Want + * To Public License, Version 2, as published by Sam Hocevar. See + * http://sam.zoy.org/wtfpl/COPYING for more details. + */ +#ifndef XCRIMG_H +#define XCRIMG_H + +#include +#include +#include + + +class XCursorImage { +public: + XCursorImage (const QString &aName, const QImage &aImg, int aXHot=0, int aYHot=0, quint32 aDelay=50, quint32 aCSize=1); + XCursorImage (const QString &aName); + virtual ~XCursorImage (); + + inline bool isValid () const { return mIsValid; } + inline const QString &name () const { return mName; } + inline quint32 delay () const { return mDelay; } + inline int xhot () const { return mXHot; } + inline int yhot () const { return mYHot; } + inline quint32 csize () const { return mCSize; } + + inline void setXHot (int v) { mXHot = v; } + inline void setYHot (int v) { mYHot = v; } + inline void setDelay (quint32 v) { mDelay = v; } + inline void setName (const QString &n) { mName = n; } + inline void setCSize (quint32 v) { mCSize = v; } + + virtual QPixmap icon () const; + virtual QCursor cursor () const; + virtual QImage image (int size=-1) const; + + quint32 xcurSize () const; // size in bytes + + virtual void genXCursorImg (QByteArray &res) const; // generate Xcursor image + + static void convertARGB2PreMul (QImage &img); + +protected: + virtual QPixmap createIcon () const; + +protected: + bool mIsValid; + QString mName; + QImage *mImage; + quint32 mDelay; // milliseconds + int mXHot; + int mYHot; + quint32 mCSize; + mutable QPixmap mIcon; +}; + + +class XCursorImages { +public: + XCursorImages (const QString &aName, const QString &aPath=""); + virtual ~XCursorImages (); + + inline const QString &name () const { return mName; } + inline const QString &path () const { return mPath; } + inline const QString &title () const { return mTitle; } + inline const QString &author () const { return mAuthor; } + inline const QString &license () const { return mLicense; } + inline const QString &mail () const { return mEMail; } + inline const QString &site () const { return mSite; } + inline const QString &descr () const { return mDescr; } + inline const QString &im () const { return mIM; } + inline const QString &script () const { return mScript; } + + inline void setName (const QString &v) { mName = v; } + inline void setPath (const QString &v) { mPath = v; } + inline void setTitle (const QString &v) { mTitle = v; } + inline void setAuthor (const QString &v) { mAuthor = v; } + inline void setLicense (const QString &v) { mLicense = v; } + inline void setMail (const QString &v) { mEMail = v; } + inline void setSite (const QString &v) { mSite = v; } + inline void setDescr (const QString &v) { mDescr = v; } + inline void setIM (const QString &v) { mIM = v; } + inline void setScript (const QString &v) { mScript = v; } + + inline const QList &list () const { return mList; } + inline XCursorImage *item (int idx) { return mList.at(idx); } + inline const XCursorImage *at (int idx) const { return mList.at(idx); } + inline int count () const { return mList.size(); } + inline int size () const { return mList.size(); } + + inline void append (XCursorImage *img) { mList << img; } + + QByteArray genXCursor () const; // generate Xcursor file + + QImage buildImage () const; + +protected: + QString mName; + QString mPath; + QString mTitle; + QString mAuthor; + QString mLicense; + QString mEMail; + QString mSite; + QString mDescr; + QString mIM; + QString mScript; // just for writing it back + QList mList; +}; + + +#endif diff --git a/liblxqt-config-cursor/xcr/xcrtheme.cpp b/liblxqt-config-cursor/xcr/xcrtheme.cpp new file mode 100644 index 0000000..454371d --- /dev/null +++ b/liblxqt-config-cursor/xcr/xcrtheme.cpp @@ -0,0 +1,742 @@ +/* coded by Ketmar // Vampire Avalon (psyc://ketmar.no-ip.org/~Ketmar) + * (c)DWTFYW + * + * This program is free software. It comes without any warranty, to + * the extent permitted by applicable law. You can redistribute it + * and/or modify it under the terms of the Do What The Fuck You Want + * To Public License, Version 2, as published by Sam Hocevar. See + * http://sam.zoy.org/wtfpl/COPYING for more details. + */ +#include +//#include + +#include "xcrtheme.h" + +#include + +#include +#include + +#include "xcrimg.h" +#include "xcrxcur.h" + +/* + 0 standard arrow + 1 help arrow (the one with '?') + 2 working arrow + 3 busy cursor + 4 precision select + 5 text select + 6 handwriting + 7 unavailable +8 north (vert) resize +9 south resize + 10 west (vert-means horiz???) resize +11 east resize + 12 north-west resize +13 south-east resize + 14 north-east resize +15 south-west resize + 16 move + 17 alternate select + 18 hand +19 button +*/ + + +static const char *nameTransTbl[] = { + // curFX idx, curXP name, [...altnames], finalname, 0 + // end with 0 + "", // standard arrow (it's \x00) + "Arrow", + "left_ptr", "X_cursor", "right_ptr", "top_left_arrow", "move", + "4498f0e0c1937ffe01fd06f973665830", + 0, + // + "\x04", // precision select + "Cross", + "tcross", "cross", "crosshair", "cross_reverse", + "draped_box", + 0, + // + "\x12", // hand + "Hand", + "hand", "hand1", "hand2", "9d800788f1b08800ae810202380a0822", + "e29285e634086352946a0e7090d73106", + 0, + // + "\x05", // text select + "IBeam", + "xterm", + 0, + // + "\x11", // alternate select + "UpArrow", + "center_ptr", + 0, + // + "\x0c", + "SizeNWSE", // north-west resize + "bottom_right_corner", "top_left_corner", "bd_double_arrow", "lr_angle", + "c7088f0f3e6c8088236ef8e1e3e70000", + 0, + // + "\x0e", // north-east resize + "SizeNESW", + "bottom_left_corner", "top_right_corner", "fd_double_arrow", "ll_angle", + "fcf1c3c7cd4491d801f1e1c78f100000", + 0, + // + "\x0a", // west resize + "SizeWE", + "sb_h_double_arrow", "left_side", "right_side", "h_double_arrow", "028006030e0e7ebffc7f7070c0600140", + "14fef782d02440884392942c11205230", + 0, + // + "\x08", // north resize + "SizeNS", + "double_arrow", "bottom_side", "top_side", "v_double_arrow", "sb_v_double_arrow", "00008160000006810000408080010102", + "2870a09082c103050810ffdffffe0204", + 0, + // + "\x01", // help arrow + "Help", + "question_arrow", + "d9ce0ab605698f320427677b458ad60b", + 0, + // + "\x06", // handwriting + "Handwriting", + "pencil", + 0, + // + "\x02", // working arrow + "AppStarting", + "left_ptr_watch", "08e8e1c95fe2fc01f976f1e063a24ccd", + "3ecb610c1bf2410f44200f48c40d3599", + 0, + // + "\x10", // move (???) + "SizeAll", + "fleur", + 0, + // + "\x03", // busy cursor + "Wait", + "watch", + 0, + // + "\x07", // unavailable + "NO", + "crossed_circle", + "03b6e0fcb3499374a867c041f52298f0", + 0, + 0 +}; + + +/* +static QString convertFXIndexToXPName (qint32 idx) { + int f = 0; + do { + if (nameTransTbl[f][0] == idx) return QString(nameTransTbl[f+1]); + f += 2; + while (nameTransTbl[f]) ++f; + ++f; + } while (nameTransTbl[f]); + return QString(); +} +*/ + + +static void removeFilesAndDirs (QDir &dir) { + //qDebug() << "dir:" << dir.path(); + // files + QFileInfoList lst = dir.entryInfoList(QDir::Files | QDir::NoDotAndDotDot | QDir::Hidden); + foreach (const QFileInfo &fi, lst) { + //qDebug() << "removing" << fi.fileName() << fi.absoluteFilePath(); + dir.remove(fi.fileName()); + } + // dirs + lst = dir.entryInfoList(QDir::AllDirs | QDir::NoDotAndDotDot | QDir::Hidden); + foreach (const QFileInfo &fi, lst) { + dir.cd(fi.fileName()); + removeFilesAndDirs(dir); + dir.cd(".."); + //qDebug() << "removing dir" << fi.fileName(); + dir.rmdir(fi.fileName()); + } +} + + +static void removeFiles (QDir &dir) { + // + QFileInfoList lst = dir.entryInfoList(QDir::Files | QDir::NoDotAndDotDot | QDir::Hidden); + foreach (const QFileInfo &fi, lst) { + qDebug() << "removing" << fi.fileName() << fi.absoluteFilePath(); + QFile fl(fi.absoluteFilePath()); + fl.remove(); + } + // +} + + +static void removeCursorFiles (QDir &dir) { + QString pt = dir.path(); + if (!pt.isEmpty() && pt != "/") pt += "/"; + const char **nlst = nameTransTbl; + while (*nlst) { + nlst += 2; // skip non-files + while (*nlst) { + QString n(*nlst); + QFile fl(pt+n); + qDebug() << "removing" << fl.fileName(); + fl.remove(); + nlst++; + } + nlst++; + } +} + + +/////////////////////////////////////////////////////////////////////////////// +const char **XCursorTheme::findCursorByFXId (int id) { + if (id < 0 || id > 19) return 0; // invalid id + const char **nlst = nameTransTbl; + while (*nlst) { + int lid = (**nlst)&0xff; + nlst += 2; // skip unnecessary + if (lid == id) return nlst; + while (nlst[-1]) nlst++ ; // skip + } + return 0; // none found +} + + +/* + * type: + * 0: by CursorXP name + * 1: by Xcursor name + * return: + * pointer to Xcursor name list + */ +const char **XCursorTheme::findCursorRecord (const QString &cname, int type) { + QByteArray ba(cname.toUtf8()); + const char *name = ba.constData(); + const char **nlst = nameTransTbl; + while (*nlst) { + nlst += 2; // skip unnecessary + if (!type) { + // by CursorXP name + if (!strcmp(name, nlst[-1])) return nlst; + } else { + // by Xcursor name + // find name + const char **nx = nlst; + while (*nx && strcmp(*nx, name)) nx++; + if (*nx) return nlst; // we got it! + } + while (nlst[-1]) nlst++ ; // skip + } + return 0; // none found +} + + +QString XCursorTheme::findCursorFile (const QDir &dir, const char *name) { + QString d(dir.path()); + if (d != "/") d += "/"; + d += "cursors/"; + const char **nlst = nameTransTbl; + while (*nlst) { + nlst += 2; // skip unnecessary + // find name + const char **nx = nlst; + while (*nx && strcmp(*nx, name)) nx++; + if (*nx) { + // we got it! + //qDebug() << "found" << *nx << "(" << *nlst << ")"; + nx = nlst; + while (*nx) { + QString s(*nx); + //qDebug() << "checking" << s; + QFileInfo fl(d+s); + if (fl.exists() && fl.isReadable()) { + //qDebug() << " ok" << s; + return s; + } + nx++; + } + } + while (nlst[-1]) nlst++ ; // skip + } + return QString(); // none found +} + + +/////////////////////////////////////////////////////////////////////////////// +XCursorTheme::XCursorTheme () : + mName(""), mPath(""), mTitle(""), mAuthor(""), mLicense(""), + mEMail(""), mSite(""), mDescr(""), mIM(""), mSample("left_ptr") +{ +} + + +XCursorTheme::XCursorTheme (const QDir &aDir, const QString &aName) : + mName(aName), mPath(aDir.path()), mTitle(""), mAuthor(""), mLicense(""), + mEMail(""), mSite(""), mDescr(""), mIM(""), mSample("left_ptr") +{ + parseXCursorTheme(aDir); +} + + +XCursorTheme::~XCursorTheme () { + qDeleteAll(mList); + mList.clear(); +} + + +bool XCursorTheme::writeToDir (const QDir &destDir) { + bool res = true; + QDir dir (destDir); + dir.mkdir("cursors"); + if (!dir.exists("cursors")) return false; + dir.cd("cursors"); + removeCursorFiles(dir); + // + foreach (const XCursorImages *ci, mList) { + const char **nlst = findCursorRecord(ci->name()); + if (!nlst) continue; // unknown cursor, skip it + qDebug() << "writing" << *nlst; + { + QByteArray ba(ci->genXCursor()); + QFile fo(dir.path()+"/"+ci->name()); + if (fo.open(QIODevice::WriteOnly)) { + fo.write(ba); + fo.close(); + } else { + res = false; + break; + } + } + // make symlinks + const char *orig = *nlst; + nlst++; + while (*nlst) { + qDebug() << "symlinking to" << orig << "as" << *nlst; + QByteArray newName(QFile::encodeName(dir.path()+"/"+(*nlst))); + qDebug() << "old" << orig << "new" << newName.constData(); + if (symlink(orig, newName.constData())) { + res = false; + break; + } + nlst++; + } + if (!res) break; + nlst++; + } + if (res) res = writeIndexTheme(destDir); + if (!res) removeCursorFiles(dir); + return res; +} + + +void XCursorTheme::parseThemeIndex (const QDir &dir) { + QString ifn = dir.path(); + if (!ifn.isEmpty() && ifn != "/") ifn += "/"; + ifn += "index.theme"; + qDebug() << "reading theme index:" << ifn; + QFile fl(ifn); + // + QString cmt; + mInherits.clear(); + // read config file, drop out 'icon theme' section (IT'S BAD!) + if (fl.open(QIODevice::ReadOnly)) { + QTextStream stream; + stream.setDevice(&fl); + stream.setCodec("UTF-8"); + bool inIconTheme = false; + QString curPath; + while (1) { + QString s = stream.readLine(); + if (s.isNull()) break; + QString orig(s); + s = s.trimmed(); + if (s.isEmpty() || s[0] == '#' || s[0] == ';') continue; + if (s[0] == '[') { + // new path + int len = s.length()-1; + if (s[len] == ']') len--; + s = s.mid(1, len).simplified(); + curPath = s.toLower(); + inIconTheme = (curPath == "icon theme"); + continue; + } + if (!inIconTheme) continue; + int eqp = s.indexOf('='); + if (eqp < 0) continue; // invalid entry + QString name = s.left(eqp).simplified().toLower(); + QString value = s.mid(eqp+1).simplified(); + qDebug() << name << value; + if (name == "name" && !value.isEmpty()) mTitle = value; + else if (name == "comment" && !value.isEmpty()) cmt = value; + else if (name == "author" && !value.isEmpty()) mAuthor = value; + else if (name == "url" && !value.isEmpty()) mSite = value; + else if (name == "description" && !value.isEmpty()) mDescr = value; + else if (name == "example" && !value.isEmpty()) mSample = value; + else if (name == "inherits" && !value.isEmpty()) mInherits << value; + } + fl.close(); + } + if (mDescr.isEmpty() && !cmt.isEmpty()) mDescr = cmt; + if (mSample.isEmpty()) mSample = "left_ptr"; + mInherits.removeDuplicates(); +} + + +void XCursorTheme::dumpInfo () { +/* + qDebug() << + "INFO:" << + "\n name:" << mName << + "\n path:" << mPath << + "\n title:" << mTitle << + "\n author:" << mAuthor << + "\n license:" << mLicense << + "\n mail:" << mEMail << + "\n site:" << mSite << + "\n dscr:" << mDescr << + "\n im:" << mIM << + "\n sample:" << mSample << + "\n inherits:" << mInherits + ; +*/ +} + + +void XCursorTheme::parseXCursorTheme (const QDir &dir) { + parseThemeIndex(dir); + dumpInfo(); + const char **nlst = nameTransTbl; + QDir dr(dir); dr.cd("cursors"); + while (*nlst) { + //qDebug() << "CurFX: (" << nlst[1] << ")"; + nlst += 2; // skip unnecessary + //qDebug() << "searching" << *nlst; + QString fn = findCursorFile(dir, *nlst); + if (fn.isEmpty()) continue; // no such file + //qDebug() << " Xcrusor: (" << nlst[0] << ")"; + while (nlst[-1]) nlst++ ; // skip + //qDebug() << " skiped: (" << nlst[1] << ")"; + qDebug() << "loading" << fn; + XCursorImages *ci = new XCursorImagesXCur(dr, fn); + if (ci->count()) { + qDebug() << " OK:" << fn << "name:" << ci->name(); + if (mTitle.isEmpty() && !ci->title().isEmpty()) mTitle = ci->title(); + if (mAuthor.isEmpty() && !ci->author().isEmpty()) mAuthor = ci->author(); + if (mLicense.isEmpty() && !ci->license().isEmpty()) mLicense = ci->license(); + if (mEMail.isEmpty() && !ci->mail().isEmpty()) mEMail = ci->mail(); + if (mSite.isEmpty() && !ci->site().isEmpty()) mSite = ci->site(); + if (mDescr.isEmpty() && !ci->descr().isEmpty()) mDescr = ci->descr(); + if (mIM.isEmpty() && !ci->im().isEmpty()) mIM = ci->im(); + mList << ci; + dumpInfo(); + } else { + qWarning() << "can't load" << fn << nlst[-2]; + delete ci; + } + } + dumpInfo(); + fixInfoFields(); + dumpInfo(); +} + + +void XCursorTheme::fixInfoFields () { + foreach (XCursorImages *ci, mList) { + if (!mTitle.isEmpty() && ci->title().isEmpty()) ci->setTitle(title()); + if (!mAuthor.isEmpty() && ci->author().isEmpty()) ci->setAuthor(author()); + if (!mLicense.isEmpty() && ci->license().isEmpty()) ci->setLicense(license()); + if (!mEMail.isEmpty() && ci->mail().isEmpty()) ci->setMail(mail()); + if (!mSite.isEmpty() && ci->site().isEmpty()) ci->setSite(site()); + if (!mDescr.isEmpty() && ci->descr().isEmpty()) ci->setDescr(descr()); + if (!mIM.isEmpty() && ci->im().isEmpty()) ci->setIM(im()); + } +} + + +bool XCursorTheme::writeIndexTheme (const QDir &destDir) { + QString ifn = destDir.path(); + if (!ifn.isEmpty() && ifn != "/") ifn += "/"; + ifn += "index.theme"; + qDebug() << "writing theme index:" << ifn; + QFile fl(ifn); + // + QStringList cfg, inhs, iconOther; + QString name, cmt, author, url, dscr, sample; + inhs.append(mInherits); + // read config file, drop out 'icon theme' section (IT'S BAD!) + if (fl.open(QIODevice::ReadOnly)) { + QTextStream stream; + stream.setDevice(&fl); + stream.setCodec("UTF-8"); + QString curPath; + while (1) { + QString s = stream.readLine(); + if (s.isNull()) break; + QString orig(s); + s = s.trimmed(); + if (s.isEmpty() || s[0] == '#' || s[0] == ';') { + if (curPath != "icon theme") cfg << orig; + continue; + } + if (s[0] == '[') { + // new path + int len = s.length()-1; + if (s[len] == ']') len--; + s = s.mid(1, len).simplified(); + curPath = s.toLower(); + if (curPath != "icon theme") cfg << orig; + continue; + } + if (curPath != "icon theme") cfg << orig; + else { + int eqp = s.indexOf('='); + if (eqp < 0) { + // invalid entry + iconOther << orig; + continue; + } + QString name = s.left(eqp).simplified(); + QString value = s.mid(eqp+1).simplified(); + if (name.isEmpty()) { + // invalid entry + iconOther << orig; + continue; + } + QString nn(name.toLower()); + if (nn == "name") name = value; + else if (nn == "comment") cmt = value; + else if (nn == "author") author = value; + else if (nn == "url") url = value; + else if (nn == "description") dscr = value; + else if (nn == "example") sample = value; + else if (nn == "inherits") { if (!value.isEmpty()) inhs << value; } + else iconOther << orig; +/* +Name=Fire Dragon +Comment=Fire Dragon Cursor Theme -- part of the 'Four Dragons' suite; (c) Sleeping Dragon, http://sleeping-dragon.deviantart.com/art/Fire-Dragon-30419542 +Author=Sleeping Dragon +Url=http://sleeping-dragon.deviantart.com/art/Fire-Dragon-30419542 +Description=Fire Dragon Cursor Theme -- part of the 'Four Dragons' suite +Example=left_ptr +Inherits=core +*/ + } + } + fl.close(); + } + // theme file parsed; rewrite it! + if (cfg.size() > 0 && !cfg.at(cfg.size()-1).isEmpty()) cfg << ""; + if (!fl.open(QIODevice::WriteOnly)) return false; + if (name.isEmpty()) name = mTitle; + if (author.isEmpty()) author = mAuthor; + if (url.isEmpty()) url = mSite; + if (dscr.isEmpty()) dscr = mDescr; + if (cmt.isEmpty()) cmt = dscr; + /*if (sample.isEmpty())*/ sample = "left_ptr"; + if (inhs.size() == 0) inhs << "core"; + inhs.removeDuplicates(); + dumpInfo(); +/* + qDebug() << + "***INFO:" << + "\n name:" << name << + "\n cmt:" << cmt << + "\n author:" << author << + "\n site:" << url << + "\n dscr:" << dscr << + "\n sample:" << mSample << + "\n inherits:" << inhs + ; +*/ + { + QTextStream stream; + stream.setDevice(&fl); + stream.setCodec("UTF-8"); + foreach (const QString &s, cfg) stream << s << "\n"; + stream << "[Icon Theme]\n"; + stream << "Name=" << name << "\n"; + stream << "Comment=" << cmt << "\n"; + stream << "Author=" << author << "\n"; + stream << "Url=" << url << "\n"; + stream << "Description=" << dscr << "\n"; + stream << "Example=" << mSample << "\n"; + foreach (const QString &s, inhs) stream << "Inherits=" << s << "\n"; + } + fl.close(); + return true; +} + + +/////////////////////////////////////////////////////////////////////////////// +static bool removeXCTheme (const QDir &thDir) { + if (thDir.exists("cursors")) { + QDir d(thDir); + d.cd("cursors"); + //removeCursorFiles(d); + removeFiles(d); + } + thDir.rmdir("cursors"); + // check if there are some other files + QFileInfoList lst = thDir.entryInfoList(QDir::AllDirs | QDir::Files | QDir::NoDotAndDotDot | QDir::Hidden); + bool cantKill = false; + foreach (const QFileInfo &fi, lst) { + QString s(fi.fileName()); + if (s != "icon-theme.cache" && s != "index.theme") { + cantKill = true; + break; + } + } + // can kill this? + if (!cantKill) { + QDir d(thDir); + d.remove("icon-theme.cache"); + d.remove("index.theme"); + } + return true; +} + + +bool removeXCursorTheme (const QDir &thDir, const QString &name) { + qDebug() << "to kill:" << thDir.path() << name; + QDir d(thDir); + if (!d.exists(name)) return false; + qDebug() << "removing" << d.path() << name; + d.cd(name); + removeXCTheme(d); + d.cd(".."); + d.rmdir(name); + return true; +} + + +bool removeXCursorTheme (const QString &name) { + QDir d(QDir::homePath()); + return removeXCursorTheme(d, name); +} + + +bool removeXCursorTheme (const QDir &thDir) { + QString name(thDir.path()); + while (!name.isEmpty() && name.endsWith('/')) name.chop(1); + int i = name.lastIndexOf('/'); + if (i < 1) return false; + name = name.mid(i+1); + QDir d(thDir); + d.cd(".."); + return removeXCursorTheme(d, name); +} + + +/////////////////////////////////////////////////////////////////////////////// +/* + * returns temporary dir or empty string + */ +static bool tarDir (const QString &destFName, const QDir &pth, const QString &dir) { + QStringList args; + + QFile fl(destFName); + fl.remove(); + + args << "-c"; // create archive... + args << "-z"; // and gzip it + QString ps(pth.path()); + if (!ps.isEmpty() && ps != ".") { + args << "-C"; // dir to go + args << ps; + } + args << "-f"; // to file + args << destFName; + QString s(dir); + if (!s.endsWith('/')) s += '/'; + args << s; + + QProcess pr; + pr.setStandardInputFile("/dev/null"); + pr.setStandardOutputFile("/dev/null"); + pr.setStandardErrorFile("/dev/null"); + + pr.start("tar", args); + + if (pr.waitForStarted()) { + if (pr.waitForFinished()) return true; + } + + // cleanup + fl.remove(); + return false; +} +//tar -c -C /home/ketmar/k8prj/xcurtheme/src -f z.tar xcr/ + + +bool packXCursorTheme (const QString &destFName, const QDir &thDir, const QString &thName, bool removeTheme) { + if (destFName.isEmpty() || thName.isEmpty()) return false; + QDir d(thDir); + if (!d.cd(thName)) return false; + + bool res = tarDir(destFName, thDir, thName); + if (res && removeTheme) { + removeFilesAndDirs(d); + d.cd(".."); + d.rmdir(thName); + } + return res; +} + + +bool XCursorTheme::writeXPTheme (const QDir &destDir) { + QString ifn = destDir.path(); + if (!ifn.isEmpty() && ifn != "/") ifn += '/'; + + QFile fl(ifn+"Scheme.ini"); + if (fl.open(QIODevice::WriteOnly)) { + QTextStream stream; + stream.setDevice(&fl); + stream.setCodec("UTF-8"); + stream << "[General]\r\n"; + stream << "Version=130\r\n"; + qDebug() << "writing images..."; + foreach (XCursorImages *ci, mList) { + const char **nlst = findCursorRecord(ci->name()); + if (!nlst) continue; // unknown cursor, skip it + qDebug() << "image:" << *(nlst-1); + QImage img(ci->buildImage()); + if (!img.save(ifn+(*(nlst-1))+".png")) return false; + stream << "["+QString(*(nlst-1))+"]\r\n"; + stream << "StdCursor=0\r\n"; + stream << "Frames=" << ci->count() << "\r\n"; + stream << "Hot spot x=" << ci->at(0)->xhot() << "\r\n"; + stream << "Hot spot y=" << ci->at(0)->yhot() << "\r\n"; + stream << "Interval=" << (ci->at(0)->delay() == 2147483647 ? 100 : ci->at(0)->delay()) << "\r\n"; + // x2, y2? wtf? + if (ci->count() > 1) { + stream << "Frames=" << ci->count() << "\r\n"; + stream << "Animation style=0\r\n"; + } else { + stream << "Frames=1\r\n"; + stream << "Animation style=0\r\n"; + } + } + stream << "[[Description]\r\n"; + if (!mName.isEmpty()) stream << mName << "\r\n"; + if (!mTitle.isEmpty()) stream << mTitle << "\r\n"; + if (!mAuthor.isEmpty()) stream << mAuthor << "\r\n"; + if (!mLicense.isEmpty()) stream << mLicense << "\r\n"; + if (!mEMail.isEmpty()) stream << mEMail << "\r\n"; + if (!mSite.isEmpty()) stream << mSite << "\r\n"; + if (!mDescr.isEmpty()) stream << mDescr << "\r\n"; + if (!mIM.isEmpty()) stream << mIM << "\r\n"; + } + fl.close(); + return true; +} diff --git a/liblxqt-config-cursor/xcr/xcrtheme.h b/liblxqt-config-cursor/xcr/xcrtheme.h new file mode 100644 index 0000000..e8dca8c --- /dev/null +++ b/liblxqt-config-cursor/xcr/xcrtheme.h @@ -0,0 +1,97 @@ +/* coded by Ketmar // Vampire Avalon (psyc://ketmar.no-ip.org/~Ketmar) + * (c)DWTFYW + * + * This program is free software. It comes without any warranty, to + * the extent permitted by applicable law. You can redistribute it + * and/or modify it under the terms of the Do What The Fuck You Want + * To Public License, Version 2, as published by Sam Hocevar. See + * http://sam.zoy.org/wtfpl/COPYING for more details. + */ +#ifndef XCRTHEME_H +#define XCRTHEME_H + +#include +#include +#include + +#include "xcrimg.h" + + +class XCursorTheme { +public: + XCursorTheme (const QDir &aDir, const QString &aName); + XCursorTheme (); + virtual ~XCursorTheme (); + + inline const QString &name () const { return mName; } + inline const QString &path () const { return mPath; } + inline const QString &title () const { return mTitle; } + inline const QString &author () const { return mAuthor; } + inline const QString &license () const { return mLicense; } + inline const QString &mail () const { return mEMail; } + inline const QString &site () const { return mSite; } + inline const QString &descr () const { return mDescr; } + inline const QString &im () const { return mIM; } + inline const QString &sample () const { return mSample; } + inline const QStringList &inherits () const { return mInherits; } + + inline void setName (const QString &v) { mName = v; } + inline void setPath (const QString &v) { mPath = v; } + inline void setTitle (const QString &v) { mTitle = v; } + inline void setAuthor (const QString &v) { mAuthor = v; } + inline void setLicense (const QString &v) { mLicense = v; } + inline void setMail (const QString &v) { mEMail = v; } + inline void setSite (const QString &v) { mSite = v; } + inline void setDescr (const QString &v) { mDescr = v; } + inline void setIM (const QString &v) { mIM = v; } + inline void setSample (const QString &v) { mSample = v; } + inline void setInherits (const QStringList &v) { mInherits.clear(); mInherits.append(v); } + + inline const QList &list () const { return mList; } + inline const XCursorImages *at (int idx) const { return mList.at(idx); } + inline int count () const { return mList.size(); } + inline int size () const { return mList.size(); } + + inline void append (XCursorImages *img) { mList << img; } + + bool writeToDir (const QDir &destDir); + + void fixInfoFields (); + + bool writeXPTheme (const QDir &destDir); + +protected: + static const char **findCursorByFXId (int id); + static QString findCursorFile (const QDir &dir, const char *name); + static const char **findCursorRecord (const QString &cname, int type=1); + + bool writeIndexTheme (const QDir &destDir); + void parseXCursorTheme (const QDir &dir); + void parseThemeIndex (const QDir &dir); + + void dumpInfo (); + +protected: + QString mName; + QString mPath; + QString mTitle; + QString mAuthor; + QString mLicense; + QString mEMail; + QString mSite; + QString mDescr; + QString mIM; + QString mSample; + QStringList mInherits; + QList mList; +}; + + +bool removeXCursorTheme (const QDir &thDir, const QString &name); +bool removeXCursorTheme (const QString &name); +bool removeXCursorTheme (const QDir &thDir); + +bool packXCursorTheme (const QString &destFName, const QDir &thDir, const QString &thName, bool removeTheme=false); + + +#endif diff --git a/liblxqt-config-cursor/xcr/xcrthemefx.cpp b/liblxqt-config-cursor/xcr/xcrthemefx.cpp new file mode 100644 index 0000000..6850320 --- /dev/null +++ b/liblxqt-config-cursor/xcr/xcrthemefx.cpp @@ -0,0 +1,400 @@ +/* coded by Ketmar // Vampire Avalon (psyc://ketmar.no-ip.org/~Ketmar) + * (c)DWTFYW + * + * This program is free software. It comes without any warranty, to + * the extent permitted by applicable law. You can redistribute it + * and/or modify it under the terms of the Do What The Fuck You Want + * To Public License, Version 2, as published by Sam Hocevar. See + * http://sam.zoy.org/wtfpl/COPYING for more details. + */ +#include +//#include + +#include "xcrthemefx.h" + +#include +#include + +#include +#include +#include + +#include "xcrimg.h" +#include "xcrxcur.h" +#include "xcrtheme.h" + + +static const char *curShapeName[] = { + "standard arrow", + "help arrow (the one with '?')", + "working arrow", + "busy cursor", + "precision select", + "text select", + "handwriting", + "unavailable", + "north (vert) resize", + "south resize", + "west (vert-means horiz?) resize", + "east resize", + "north-west resize", + "south-east resize", + "north-east resize", + "south-west resize", + "move", + "alternate select", + "hand", + "button" +}; + + +bool XCursorThemeFX::str2num (const QString &s, quint32 &res) { + quint64 n = 0; + if (s.isEmpty()) return false; + for (int f = 0; f < s.length(); f++) { + QChar ch = s.at(f); + if (!ch.isDigit()) return false; + n = n*10+ch.unicode()-'0'; + } + //if (n >= (quint64)0x100000000LL) n = 0xffffffffLL; + if (n >= (quint64)0x80000000LL) n = 0x7fffffffLL; + res = n; + return true; +} + + +QList XCursorThemeFX::parseScript (const QString &script, quint32 maxFrame) { + QList res; + QString scp = script; scp.replace("\r", "\n"); + QStringList scpL = scp.split('\n', QString::SkipEmptyParts); + foreach (QString s, scpL) { + s = s.simplified(); + //qDebug() << s; + QStringList fld = s.split(',', QString::SkipEmptyParts); //BUG!BUG!BUG! + if (fld.size() != 2) { + qDebug() << "script error:" << s; + qWarning() << "script error:" << s; + continue; + } + // frame[s] + int hyph = fld[0].indexOf('-'); + tAnimSeq a; + if (hyph == -1) { + // just a number + if (!str2num(fld[0], a.from)) { + qDebug() << "script error (frame):" << s; + qWarning() << "script error (frame):" << s; + continue; + } + a.from = qMax(qMin(maxFrame, a.from), (quint32)1)-1; + a.to = a.from; + } else { + // a..b + if (!str2num(fld[0].left(hyph), a.from)) { + qDebug() << "script error (frame from):" << s; + qWarning() << "script error (frame from):" << s; + continue; + } + a.from = qMax(qMin(maxFrame, a.from), (quint32)1)-1; + if (!str2num(fld[0].mid(hyph+1), a.to)) { + qDebug() << "script error (frame to):" << s; + qWarning() << "script error (frame to):" << s; + continue; + } + a.to = qMax(qMin(maxFrame, a.to), (quint32)1)-1; + } + // delay + if (!str2num(fld[1], a.delay)) { + qDebug() << "script error (delay):" << s; + qWarning() << "script error (delay):" << s; + continue; + } + if (a.delay < 10) a.delay = 10; + qDebug() << "from" << a.from << "to" << a.to << "delay" << a.delay; + res << a; + } + return res; +} + + +/////////////////////////////////////////////////////////////////////////////// +static QByteArray zlibInflate (const void *buf, int bufSz, int destSz) { + QByteArray res; + z_stream stream; + int err; + + res.resize(destSz+1); + stream.next_in = (Bytef *)buf; + stream.avail_in = bufSz; + stream.zalloc = (alloc_func)0; + stream.zfree = (free_func)0; + stream.next_out = (Bytef *)res.data(); + stream.avail_out = destSz; + + err = inflateInit(&stream); + if (err != Z_OK) return QByteArray(); + err = inflate(&stream, Z_SYNC_FLUSH); + fprintf(stderr, "inflate result: %i\n", err); + switch (err) { + case Z_STREAM_END: + err = inflateEnd(&stream); + fprintf(stderr, "Z_STREAM_END: inflate result: %i\n", err); + if (err != Z_OK) return QByteArray(); + break; + case Z_OK: + err = inflateEnd(&stream); + fprintf(stderr, "Z_OK: inflate result: %i\n", err); + if (err != Z_OK) return QByteArray(); + break; + default: return QByteArray(); + } + return res; +} + + +static quint32 baGetDW (QByteArray &ba, int &pos) { + const uchar *d = (const uchar *)ba.constData(); + d += pos+3; + pos += 4; + quint32 res = 0; + for (int f = 4; f > 0; f--, d--) { + res <<= 8; + res |= *d; + } + return res; +} + + +/////////////////////////////////////////////////////////////////////////////// +XCursorThemeFX::XCursorThemeFX (const QString &aFileName) : XCursorTheme() { + if (!parseCursorFXTheme(aFileName)) { + qDeleteAll(mList); + mList.clear(); + } +} + + +bool XCursorThemeFX::parseCursorFXTheme (const QString &aFileName) { + qDebug() << "loading" << aFileName; + QFile fl(aFileName); + if (!fl.open(QIODevice::ReadOnly)) return false; // shit! + QByteArray ba(fl.readAll()); + fl.close(); + if (ba.size() < 0xb8) return false; // shit! + int pos = 0; + if (baGetDW(ba, pos) != 1) return false; // invalid version + quint32 mainHdrSize = baGetDW(ba, pos); + if (mainHdrSize < 0xb8) return false; // invalid header size + quint32 unDataSize = baGetDW(ba, pos); + if (unDataSize < 0x4c) return false; // no cursors anyway + struct { + quint32 ofs; + quint32 len; + } infoFields[6]; + pos = 0x84; + for (int f = 0; f < 6; f++) { + infoFields[f].ofs = baGetDW(ba, pos); + infoFields[f].len = baGetDW(ba, pos); + } + pos = 0xb4; + quint32 ihdrSize = baGetDW(ba, pos); + // now read data + pos = mainHdrSize; + qDebug() << "reading data from" << pos; + QByteArray unp(zlibInflate(ba.constData()+pos, ba.size()-pos, unDataSize)); + if (unp.isEmpty()) { + qDebug() << "CursorFX: can't depack data"; + qWarning() << "CursorFX: can't depack data"; + return false; + } + // process info section + for (int f = 0; f < 6; f++) { + int len = infoFields[f].len; + if (!len) continue; + pos = infoFields[f].ofs; + if ((quint32)pos >= ihdrSize || (quint32)pos+len >= ihdrSize) continue; // skip invalid one + QByteArray sBA(unp.mid(pos, len)); + sBA.append('\0'); sBA.append('\0'); + QString s = QString::fromUtf16((const ushort *)sBA.constData()).simplified(); + switch (f) { + case 0: setTitle(s); break; + case 1: setAuthor(s); break; + //case 2: setVersion(s); break; + case 3: setSite(s); break; + case 4: setMail(s); break; + case 5: setDescr(s); break; + default: ; + } + } + // process resources + QSet shapesSeen; + pos = ihdrSize; + qDebug() << "resources started at hex" << QString::number(pos, 16); + while (pos <= unp.size()-12) { + quint32 ipos = pos; // will be fixed later + quint32 rtype = baGetDW(unp, pos); + quint32 basicHdrSize = baGetDW(unp, pos); + quint32 itemSize = baGetDW(unp, pos); + qDebug() << "pos hex:" << QString::number(pos, 16) << "rtype:" << rtype << "bhdrsz hex:" << QString::number(basicHdrSize, 16) << "itemsz hex:" << QString::number(itemSize, 16); + if (itemSize < 12) { + // invalid data + qDebug() << "CursorFX: invalid data chunk size"; + qWarning() << "CursorFX: invalid data chunk size"; + return false; + } + pos = ipos+itemSize; // skip it + if (rtype != 2) continue; // not cursor resource + if (itemSize < 0x4c) { + qDebug() << "CursorFX: invalid cursor chunk size:" << itemSize; + qWarning() << "CursorFX: invalid cursor chunk size:" << itemSize; + return false; + } + // cursor + int cps = ipos+3*4; + rtype = baGetDW(unp, cps); + if (rtype != 2) { + qDebug() << "CursorFX: invalid cursor chunk type:" << rtype; + qWarning() << "CursorFX: invalid cursor chunk type:" << rtype; + return false; + } + quint32 curShape = baGetDW(unp, cps); + quint32 curType = baGetDW(unp, cps); + if (curShape > 19) { + qDebug() << "CursorFX: unknown cursor shape:" << curShape; + qWarning() << "CursorFX: unknown cursor shape:" << curShape; + return false; + } + if (curType != 1) { + qDebug() << "skiping 'press' cursor; shape no" << curShape << "named" << curShapeName[curShape]; + continue; + // we need only 'normal' cursors + } + qDebug() << "cursor shape:" << curShape; + const char **nlst = findCursorByFXId((int)curShape); + if (!nlst) { + // unknown cursor type, skip it + qDebug() << "CursorFX: skiping cursor shape:" << curShapeName[curShape]; + qWarning() << "CursorFX: skiping cursor shape:" << curShapeName[curShape]; + continue; + } + if (shapesSeen.contains(curShape&0xff)) { + // unknown cursor type, skip it + qDebug() << "CursorFX: skiping duplicate cursor shape:" << curShapeName[curShape]; + qWarning() << "CursorFX: skiping duplicate cursor shape:" << curShapeName[curShape]; + continue; + } + shapesSeen << (curShape&0xff); + qDebug() << "importing cursor" << *nlst; + quint32 unk0 = baGetDW(unp, cps); // unknown field + quint32 frameCnt = baGetDW(unp, cps); + if (frameCnt < 1) frameCnt = 1; // just in case + quint32 imgWdt = baGetDW(unp, cps); + quint32 imgHgt = baGetDW(unp, cps); + quint32 imgDelay = baGetDW(unp, cps); + quint32 aniFlags = baGetDW(unp, cps); + quint32 unk1 = baGetDW(unp, cps); // unknown field + quint32 imgXHot = baGetDW(unp, cps); + quint32 imgYHot = baGetDW(unp, cps); + quint32 realHdrSize = baGetDW(unp, cps); + quint32 imgDataSize = baGetDW(unp, cps); + quint32 addonOfs = baGetDW(unp, cps); + quint32 addonLen = baGetDW(unp, cps); + if (imgDelay < 10) imgDelay = 10; + if (imgDelay >= (quint32)0x80000000LL) imgDelay = 0x7fffffffLL; + qDebug() << + "cursor data:" << + "\n frames:" << frameCnt << + "\n width:" << imgWdt << + "\n height:" << imgHgt << + "\n delay:" << imgDelay << + "\n flags:" << QString::number(aniFlags, 2) << + "\n xhot:" << imgXHot << + "\n yhot:" << imgYHot << + "\n unk0:" << unk0 << + "\n unk1:" << unk1 << + "\n rhdata:" << QString::number(realHdrSize, 16) << + "\n dataOfs:" << QString::number(ipos+realHdrSize, 16) << + "\n cdataOfs:" << QString::number(ipos+basicHdrSize+addonLen, 16) + ; + // now check if we have enought data + if (ipos+realHdrSize+imgDataSize > (quint32)pos) { + qDebug() << "CursorFX: cursor data too big"; + qWarning() << "CursorFX: cursor data too big"; + return false; + } + // addon is the script; parse it later + QList aseq; + QString script; + if (addonLen) { + // script + if (addonOfs < 0x4c || addonOfs > realHdrSize) { + qDebug() << "CursorFX: invalid addon data offset"; + qWarning() << "CursorFX: invalid addon data offset"; + return false; + } + QByteArray bs(unp.mid(ipos+addonOfs, addonLen)); + bs.append('\0'); bs.append('\0'); + script = QString::fromUtf16((const ushort *)bs.constData()); + qDebug() << "script:\n" << script; + // create animseq + aseq = parseScript(script, frameCnt); + } else { + // create 'standard' animseq + tAnimSeq a; + a.from = 0; a.to = frameCnt-1; a.delay = imgDelay; + aseq << a; + // and back if 'alternate' flag set + if (aniFlags&0x01) { + a.from = frameCnt-1; a.to = 0; + aseq << a; + } + } + if (imgWdt*imgHgt*4 != imgDataSize) { + qDebug() << "data size:" << imgDataSize << "but should be" << imgWdt*imgHgt*4; + continue; + } + // decode image + QImage img((const uchar *)unp.constData()+ipos+realHdrSize, imgWdt, imgHgt, QImage::Format_ARGB32); + img = img.mirrored(false, true); + // + XCursorImages *cim = new XCursorImages(*nlst); + cim->setScript(script); + //!!! + //!!!img.save(QString("_png/%1.png").arg(cim->name())); + //!!! + quint32 frameWdt = img.width()/frameCnt; + qDebug() << "frameWdt:" << frameWdt << "left:" << img.width()%(frameWdt*frameCnt); + // now build animation sequence + int fCnt = 0; + foreach (const tAnimSeq &a, aseq) { + bool back = a.from > a.to; // going backwards + quint32 fNo = a.from; + for (;; fCnt++) { + //k8:qDebug() << " frame:" << fNo << "delay:" << a.delay; + // copy frame + QImage frame(img.copy(fNo*frameWdt, 0, frameWdt, img.height())); + //frame.save(QString("_png/%1_%2.png").arg(cim->name()).arg(QString::number(f))); + XCursorImage *i = new XCursorImage(QString("%1%2").arg(cim->name()).arg(QString::number(fCnt)), + frame, imgXHot, imgYHot, a.delay, 1 + ); + cim->append(i); + // + if (fNo == a.to) break; + if (back) fNo--; else fNo++; + } + } + // append if not empty + if (cim->count()) { + // now check if it is looped and cancel looping if necessary + if ((aniFlags & 0x02) == 0) { + // not looped + qDebug() << " anti-loop fix"; + XCursorImage *i = cim->item(cim->count()-1); + i->setDelay(0x7fffffffL); + //i->setCSize(2); // ??? + } + mList << cim; + } + } + return true; +} diff --git a/liblxqt-config-cursor/xcr/xcrthemefx.h b/liblxqt-config-cursor/xcr/xcrthemefx.h new file mode 100644 index 0000000..c474ccd --- /dev/null +++ b/liblxqt-config-cursor/xcr/xcrthemefx.h @@ -0,0 +1,40 @@ +/* coded by Ketmar // Vampire Avalon (psyc://ketmar.no-ip.org/~Ketmar) + * (c)DWTFYW + * + * This program is free software. It comes without any warranty, to + * the extent permitted by applicable law. You can redistribute it + * and/or modify it under the terms of the Do What The Fuck You Want + * To Public License, Version 2, as published by Sam Hocevar. See + * http://sam.zoy.org/wtfpl/COPYING for more details. + */ +#ifndef XCRTHEMEFX_H +#define XCRTHEMEFX_H + +#include +#include +#include + +#include "xcrimg.h" +#include "xcrtheme.h" + + +class XCursorThemeFX : public XCursorTheme { +public: + XCursorThemeFX (const QString &aFileName); + +public: + class tAnimSeq { + public: + quint32 from, to; + quint32 delay; + }; + + static QList parseScript (const QString &script, quint32 maxFrame); + static bool str2num (const QString &s, quint32 &res); + +protected: + bool parseCursorFXTheme (const QString &aFileName); +}; + + +#endif diff --git a/liblxqt-config-cursor/xcr/xcrthemexp.cpp b/liblxqt-config-cursor/xcr/xcrthemexp.cpp new file mode 100644 index 0000000..9aec632 --- /dev/null +++ b/liblxqt-config-cursor/xcr/xcrthemexp.cpp @@ -0,0 +1,352 @@ +/* coded by Ketmar // Vampire Avalon (psyc://ketmar.no-ip.org/~Ketmar) + * (c)DWTFYW + * + * This program is free software. It comes without any warranty, to + * the extent permitted by applicable law. You can redistribute it + * and/or modify it under the terms of the Do What The Fuck You Want + * To Public License, Version 2, as published by Sam Hocevar. See + * http://sam.zoy.org/wtfpl/COPYING for more details. + */ +#include +//#include + +#include "xcrthemexp.h" + +#include +#include + +#include +#include +#include + +#include "xcrimg.h" +#include "xcrxcur.h" +#include "xcrtheme.h" +#include "xcrthemefx.h" + + +static const char *curShapeName[] = { + "Arrow", + "Cross", + "Hand", + "IBeam", + "UpArrow", + "SizeNWSE", + "SizeNESW", + "SizeWE", + "SizeNS", + "Help", + "Handwriting", + "AppStarting", + "SizeAll", + "Wait", + "NO", + 0 +}; + + +static const char *findCurShapeName (const QString &s) { + QByteArray ba(s.toUtf8()); + const char *name = ba.constData(); + const char **nlst = curShapeName; + while (*nlst) { + if (!strcasecmp(name, *nlst)) return *nlst; + nlst++; + } + return 0; +} + + +static QString findFile (const QDir &dir, const QString &name, bool fullName=false) { + QFileInfoList lst = dir.entryInfoList(QDir::Files | QDir::NoDotAndDotDot | QDir::Hidden); + foreach (const QFileInfo &fi, lst) { + if (!name.compare(fi.fileName(), Qt::CaseInsensitive)) { + if (fullName) return fi.absoluteFilePath(); + return fi.fileName(); + } + } + return QString(); +} + + +class CursorInfo { +public: + CursorInfo () { clear(); curSection.clear(); } + + void clear () { + frameCnt = 1; delay = 50; xhot = yhot = 0; + script.clear(); + wasFrameCnt = wasXHot = wasYHot = wasDelay = wasScript = wasAStyle = wasStdCur = false; + isStdCursor = false; + isLooped = true; is2way = false; + } + +public: + quint32 frameCnt, delay, xhot, yhot; + QString script; + bool wasFrameCnt, wasXHot, wasYHot, wasDelay, wasScript, wasAStyle, wasStdCur; + bool isStdCursor; + bool isLooped, is2way; + QString curSection; + QString nextSection; +}; + + +/* true: EOF */ +static bool readNextSection (QTextStream &stream, CursorInfo &info) { + info.clear(); + if (info.nextSection.isEmpty()) { + // find next section + //qDebug() << "searching section..."; + for (;;) { + QString s; + info.curSection.clear(); + info.nextSection.clear(); + for (;;) { + s = stream.readLine(); + if (s.isNull()) return true; + s = s.trimmed(); + //qDebug() << "*" << s; + if (s.isEmpty() || s[0] == '#' || s[0] == ';') continue; + if (s[0] == '[') break; + } + int len = s.length()-1; + if (s[len] == ']') len--; + s = s.mid(1, len); + const char *csn = findCurShapeName(s); + if (!csn) continue; + // section found + info.curSection = csn; + break; + } + } else { + info.curSection = info.nextSection; + info.nextSection.clear(); + } + // section found; read it + for (;;) { + QString s = stream.readLine(); + if (s.isNull()) return true; + s = s.trimmed(); + //qDebug() << "+" << s; + if (s.isEmpty() || s[0] == '#' || s[0] == ';') continue; + if (s[0] == '[') { + int len = s.length()-1; + if (s[len] == ']') len--; + s = s.mid(1, len); + const char *csn = findCurShapeName(s); + if (csn) info.nextSection = csn; else info.nextSection.clear(); + break; + } + QStringList nv(s.split('=')); + if (nv.size() != 2) continue; // invalid + QString name = nv[0].simplified().toLower(); + quint32 num = 0; + bool numOk = XCursorThemeFX::str2num(nv[1].trimmed(), num); + if (!numOk) num = 0; + if (name == "frames") { + info.frameCnt = qMax(num, (quint32)1); + info.wasFrameCnt = true; + } else if (name == "interval") { + info.delay = qMax(qMin(num, (quint32)0x7fffffffL), (quint32)10); + info.wasDelay = true; + } else if (name == "animation style") { + info.isLooped = true; + info.is2way = (num != 0); + info.wasAStyle = true; + } else if (name == "hot spot x") { + info.xhot = num; + info.wasXHot = true; + } else if (name == "hot spot y") { + info.yhot = num; + info.wasYHot = true; + } else if (name == "framescript") { + // 1 or 0 + } else if (name == "stdcursor") { + info.isStdCursor = (num!=0); + info.wasStdCur = true; + } else if (name == "hot spot x2" || name == "hot spot y2") { + } else if (name == "stdcursor" || name == "hot spot x2" || name == "hot spot y2") { + // nothing + } else { + qDebug() << "unknown param:" << name << nv[1]; + qWarning() << "unknown param:" << name << nv[1]; + } + } + return false; +} + + +static void removeFilesAndDirs (QDir &dir) { + //qDebug() << "dir:" << dir.path(); + // files + QFileInfoList lst = dir.entryInfoList(QDir::Files | QDir::NoDotAndDotDot | QDir::Hidden); + foreach (const QFileInfo &fi, lst) { + //qDebug() << "removing" << fi.fileName() << fi.absoluteFilePath(); + dir.remove(fi.fileName()); + } + // dirs + lst = dir.entryInfoList(QDir::AllDirs | QDir::NoDotAndDotDot | QDir::Hidden); + foreach (const QFileInfo &fi, lst) { + dir.cd(fi.fileName()); + removeFilesAndDirs(dir); + dir.cd(".."); + //qDebug() << "removing dir" << fi.fileName(); + dir.rmdir(fi.fileName()); + } +} + + +/* + * returns temporary dir or empty string + */ +static QString unzipFile (const QString &zipFile) { + QStringList args; + + char tmpDirName[18]; + strcpy(tmpDirName, "/tmp/unzXXXXXX"); + char *td = mkdtemp(tmpDirName); + if (!td) return QString(); + + QDir dir(td); + + args << "-b"; // all files are binary + args << "-D"; // skip timestamps + args << "-n"; // never overwrite (just in case) + args << "-qq"; // be very quiet + args << zipFile; + args << "-d" << dir.absolutePath(); // dest dir + + QProcess pr; + pr.setStandardInputFile("/dev/null"); + pr.setStandardOutputFile("/dev/null"); + pr.setStandardErrorFile("/dev/null"); + + pr.start("unzip", args); + + if (pr.waitForStarted()) { + if (pr.waitForFinished()) return QLatin1String(td); + } + + // cleanup + removeFilesAndDirs(dir); + dir.cd(".."); + QString s = QLatin1String(strchr(td+1, '/')+1); + //qDebug() << s; + dir.rmdir(s); + + return QString(); +} + + +/////////////////////////////////////////////////////////////////////////////// +XCursorThemeXP::XCursorThemeXP (const QString &aFileName) : XCursorTheme() { + QFileInfo fi(aFileName); + if (fi.exists() && fi.isReadable()) { + QString dst = unzipFile(aFileName); + if (!dst.isEmpty()) { + QDir d(dst); + if (!parseCursorXPTheme(d)) { + qDeleteAll(mList); + mList.clear(); + } + qDebug() << "doing cleanup..."; + dst.remove(0, dst.indexOf('/', 1)+1); + removeFilesAndDirs(d); + d.cd(".."); + qDebug() << dst; + d.rmdir(dst); + } + } +} + + +bool XCursorThemeXP::parseCursorXPTheme (const QDir &thDir) { + qDebug() << "loading" << thDir.path(); + QString ifn = findFile(thDir, "scheme.ini", true); + if (ifn.isEmpty()) return false; + qDebug() << "reading scheme:" << ifn; + // + QFile fl(ifn); + if (!fl.open(QIODevice::ReadOnly)) return false; // no scheme --> no fun! + QTextStream stream; + stream.setDevice(&fl); + stream.setCodec("UTF-8"); + CursorInfo info; + QSet sectionsSeen; + bool eof = false; + do { + eof = readNextSection(stream, info); + if (info.curSection.isEmpty()) break; +/* + qDebug() << "section:" << info.curSection << + "\n stdcr was:" << info.wasStdCur << "value:" << info.isStdCursor << + "\n frame was:" << info.wasFrameCnt << "value:" << info.frameCnt << + "\n delay was:" << info.wasDelay << "value:" << info.delay << + "\n xhot was:" << info.wasXHot << "value:" << info.xhot << + "\n yhot was:" << info.wasYHot << "value:" << info.yhot << + "\n style was:" << info.wasAStyle << "loop:" << info.isLooped << "2way:" << info.is2way << + "\n scrpt was:" << info.wasScript << "value:" << info.script << + "\n next section:" << info.nextSection + ; +*/ + const char ** nlst = XCursorTheme::findCursorRecord(info.curSection, 0); + QString imgFile = findFile(thDir, info.curSection+".png", true); + if (!sectionsSeen.contains(info.curSection) && nlst && !imgFile.isEmpty()) { + qDebug() << "section" << info.curSection << "file:" << imgFile; + sectionsSeen << info.curSection; + //TODO: script + QList aseq; + { + // create 'standard' animseq + XCursorThemeFX::tAnimSeq a; + a.from = 0; a.to = info.frameCnt-1; a.delay = info.delay; + aseq << a; + // and back if 'alternate' flag set + if (info.is2way) { + a.from = info.frameCnt-1; a.to = 0; + aseq << a; + } + } + // load image + QImage img(imgFile); + if (!img.isNull()) { + XCursorImages *cim = new XCursorImages(*nlst); + quint32 frameWdt = img.width()/info.frameCnt; + qDebug() << "frameWdt:" << frameWdt << "left:" << img.width()%(frameWdt*info.frameCnt); + // now build animation sequence + int fCnt = 0; + foreach (const XCursorThemeFX::tAnimSeq &a, aseq) { + bool back = a.from > a.to; // going backwards + quint32 fNo = a.from; + for (;; fCnt++) { + //k8:qDebug() << " frame:" << fNo << "delay:" << a.delay; + // copy frame + QImage frame(img.copy(fNo*frameWdt, 0, frameWdt, img.height())); + //frame.save(QString("_png/%1_%2.png").arg(cim->name()).arg(QString::number(f))); + XCursorImage *i = new XCursorImage(QString("%1%2").arg(cim->name()).arg(QString::number(fCnt)), + frame, info.xhot, info.yhot, a.delay, 1 + ); + cim->append(i); + // + if (fNo == a.to) break; + if (back) fNo--; else fNo++; + } + } + // append if not empty + if (cim->count()) { + // now check if it is looped and cancel looping if necessary + if (!info.isLooped) { + // not looped + qDebug() << " anti-loop fix"; + XCursorImage *i = cim->item(cim->count()-1); + i->setDelay(0x7fffffffL); + //i->setCSize(2); // ??? + } + mList << cim; + } + } + } + } while (!eof); + return true; +} diff --git a/liblxqt-config-cursor/xcr/xcrthemexp.h b/liblxqt-config-cursor/xcr/xcrthemexp.h new file mode 100644 index 0000000..fb97be3 --- /dev/null +++ b/liblxqt-config-cursor/xcr/xcrthemexp.h @@ -0,0 +1,31 @@ +/* coded by Ketmar // Vampire Avalon (psyc://ketmar.no-ip.org/~Ketmar) + * (c)DWTFYW + * + * This program is free software. It comes without any warranty, to + * the extent permitted by applicable law. You can redistribute it + * and/or modify it under the terms of the Do What The Fuck You Want + * To Public License, Version 2, as published by Sam Hocevar. See + * http://sam.zoy.org/wtfpl/COPYING for more details. + */ +#ifndef XCRTHEMEXP_H +#define XCRTHEMEXP_H + +#include +#include +#include + +#include "xcrimg.h" +#include "xcrtheme.h" +#include "xcrthemefx.h" + + +class XCursorThemeXP : public XCursorTheme { +public: + XCursorThemeXP (const QString &aFileName); + +protected: + bool parseCursorXPTheme (const QDir &thDir); +}; + + +#endif diff --git a/liblxqt-config-cursor/xcr/xcrxcur.cpp b/liblxqt-config-cursor/xcr/xcrxcur.cpp new file mode 100644 index 0000000..c1536c1 --- /dev/null +++ b/liblxqt-config-cursor/xcr/xcrxcur.cpp @@ -0,0 +1,247 @@ +/* coded by Ketmar // Vampire Avalon (psyc://ketmar.no-ip.org/~Ketmar) + * (c)DWTFYW + * + * This program is free software. It comes without any warranty, to + * the extent permitted by applicable law. You can redistribute it + * and/or modify it under the terms of the Do What The Fuck You Want + * To Public License, Version 2, as published by Sam Hocevar. See + * http://sam.zoy.org/wtfpl/COPYING for more details. + */ +#include +//#include + +#include "xcrxcur.h" + +#include +#include +#include +#include +#include + +#include + + +#include +#include +#include + + +/* +static QImage autoCropImage (const QImage &image) { + // Compute an autocrop rectangle for the image + QRect r(image.rect().bottomRight(), image.rect().topLeft()); + const quint32 *pixels = reinterpret_cast(image.bits()); + for (int y = 0; y < image.height(); y++) { + for (int x = 0; x < image.width(); x++) { + if (*(pixels++)) { + if (x < r.left()) r.setLeft(x); + if (x > r.right()) r.setRight(x); + if (y < r.top()) r.setTop(y); + if (y > r.bottom()) r.setBottom(y); + } + } + } + // Normalize the rectangle + return image.copy(r.normalized()); +} +*/ + + +inline static quint32 getDW (const void *data) { + const quint8 *d = (const quint8 *)data; + d += 3; + quint32 res = 0; + for (int f = 4; f > 0; f--, d--) { + res <<= 8; + res |= *d; + } + return res; +} + + +static quint32 baGetDW (QByteArray &ba, int &pos) { + const uchar *d = (const uchar *)ba.constData(); + d += pos+3; + pos += 4; + quint32 res = 0; + for (int f = 4; f > 0; f--, d--) { + res <<= 8; + res |= *d; + } + return res; +} + + +/////////////////////////////////////////////////////////////////////////////// +XCursorImageXCur::XCursorImageXCur (const QString &aName, const void *aImgData) : XCursorImage(aName) { + parseImgData(aImgData); +} + + +XCursorImageXCur::~XCursorImageXCur () { +} + + +void XCursorImageXCur::parseImgData (const void *aImgData) { + mIsValid = false; + if (mImage) delete mImage; mImage = 0; + const quint32 *data = (const quint32 *)aImgData; + if (getDW(data) != 36) return; // header size + if (getDW(data+1) != 0xfffd0002L) return; // magic + //if (getDW(data+2) != 1) return; // image subtype + if (getDW(data+3) != 1) return; // version + mCSize = getDW(data+2); + data += 4; + quint32 wdt = getDW(data++); // width + quint32 hgt = getDW(data++); // height + if (wdt > 0x7fff) return; + if (hgt > 0x7fff) return; +/* + quint32 xhot = getDW(data++); + quint32 yhot = getDW(data++); + assert(xhot <= wdt); + assert(yhot <= hgt); +*/ + mXHot = *((const qint32 *)data); data++; + mYHot = *((const qint32 *)data); data++; + mDelay = getDW(data++); // milliseconds + // got to pixels (ARGB) + QImage img((const uchar *)data, wdt, hgt, QImage::Format_ARGB32_Premultiplied); + mImage = new QImage(img.copy()); + mIsValid = true; +} + + +/////////////////////////////////////////////////////////////////////////////// +XCursorImagesXCur::XCursorImagesXCur (const QDir &aDir, const QString &aName) : XCursorImages(aName, aDir.path()) { + parseCursorFile(aDir.path()+"/"+aName); +} + + +XCursorImagesXCur::XCursorImagesXCur (const QString &aFileName) : XCursorImages("", "") { + QString name(aFileName); + if (name.isEmpty() || name.endsWith('/')) return; + int i = name.lastIndexOf('/'); + QString dir; + if (i < 0) dir = "./"; else dir = name.left(i); + name = name.mid(i+1); + setName(name); setPath(dir); + parseCursorFile(aFileName); +} + + +bool XCursorImagesXCur::parseCursorFile (const QString &fname) { + //qDebug() << fname; + qDeleteAll(mList); + mList.clear(); + QFile fl(fname); + if (!fl.open(QIODevice::ReadOnly)) return false; // shit! + QByteArray ba(fl.readAll()); + fl.close(); + if (ba.size() < 4*4) return false; // shit! + if (ba[0] != 'X' || ba[1] != 'c' || ba[2] != 'u' || ba[3] != 'r') return false; // shit! + //FIXME: add more checks! + int pos = 4; + quint32 hdrSize = baGetDW(ba, pos); + if (hdrSize < 16) return false; // invalid header size + quint32 version = baGetDW(ba, pos); + if (version != 65536) return false; // invalid version + quint32 ntoc = baGetDW(ba, pos); + if (!ntoc) return true; // nothing to parse + if (ntoc >= 65536) return false; // idiot or what? + quint32 tocEndOfs = hdrSize+(ntoc*(3*4)); + if (tocEndOfs > (quint32)ba.size()) return false; // out of data + pos = hdrSize; + // parse TOC + int cnt = -1; + bool wasTitle = false, wasAuthor = false, wasLic = false; + bool wasMail = false, wasSite = false, wasDescr = false, wasIM = false; + while (ntoc-- > 0) { + cnt++; + quint32 type = baGetDW(ba, pos); + pos += 4; // skip the shit + quint32 dataOfs = baGetDW(ba, pos); + if (type == 0xfffd0001) { + // text + if (dataOfs < tocEndOfs || dataOfs > (quint32)ba.size()-20) continue; // invalid text + // parse text + int ipos = dataOfs; + if (baGetDW(ba, ipos) != 20) continue; // invalid header size + if (baGetDW(ba, ipos) != 0xfffd0001) continue; // invalid type + quint32 subT = baGetDW(ba, ipos); + if (baGetDW(ba, ipos) != 1) continue; // invalid version + quint32 len = baGetDW(ba, ipos); + // check for data presence + if (ipos+len > (quint32)ba.size()) continue; // out of data + QByteArray stBA(ba.mid(ipos, len)); + QString s(QString::fromUtf8(stBA)); + switch (subT) { + case 1: // copyright (author) + if (!wasAuthor) { + wasAuthor = true; + mAuthor = s; + } + break; + case 2: // license + if (!wasLic) { + wasLic = true; + mLicense = s; + } + break; + case 3: // other (description) + if (!wasDescr) { + wasDescr = true; + mDescr = s; + } + break; + // my extensions + case 4: // title + if (!wasTitle) { + wasTitle = true; + mTitle = s; + } + break; + case 5: // e-mail + if (!wasMail) { + wasMail = true; + mEMail = s; + } + break; + case 6: // site + if (!wasSite) { + wasSite = true; + mSite = s; + } + break; + case 7: // IM + if (!wasIM) { + wasIM = true; + mIM = s; + } + break; + } + continue; + } + if (type != 0xfffd0002) continue; // not an image, skip this one + // image + // check + if (dataOfs < tocEndOfs || dataOfs > (quint32)ba.size()-36) continue; // invalid image + // parse image + int ipos = dataOfs; + if (baGetDW(ba, ipos) != 36) continue; // invalid image (header size) + if (baGetDW(ba, ipos) != 0xfffd0002) continue; // invalid type + ipos += 4; // skip the shit + if (baGetDW(ba, ipos) != 1) continue; // invalid image (version) + quint32 wdt = baGetDW(ba, ipos); + quint32 hgt = baGetDW(ba, ipos); + if (wdt > 0x7fff || hgt > 0x7fff) continue; // invalid sizes + // check for data presence + if ((ipos+3*4)+(wdt*hgt*4) > (quint32)ba.size()) continue; // out of data + // load image + const uchar *dta = (const uchar *)ba.constData(); + dta += dataOfs; + XCursorImage *img = new XCursorImageXCur(mName+"_"+QString::number(cnt), dta); + if (img->isValid()) mList << img; else delete img; + } + return true; +} diff --git a/liblxqt-config-cursor/xcr/xcrxcur.h b/liblxqt-config-cursor/xcr/xcrxcur.h new file mode 100644 index 0000000..96e862d --- /dev/null +++ b/liblxqt-config-cursor/xcr/xcrxcur.h @@ -0,0 +1,40 @@ +/* coded by Ketmar // Vampire Avalon (psyc://ketmar.no-ip.org/~Ketmar) + * (c)DWTFYW + * + * This program is free software. It comes without any warranty, to + * the extent permitted by applicable law. You can redistribute it + * and/or modify it under the terms of the Do What The Fuck You Want + * To Public License, Version 2, as published by Sam Hocevar. See + * http://sam.zoy.org/wtfpl/COPYING for more details. + */ +#ifndef XCRXCUR_H +#define XCRXCUR_H + +#include +#include +#include + +#include "xcrimg.h" + + +class XCursorImageXCur : public XCursorImage { +public: + XCursorImageXCur (const QString &aName, const void *aImgData); // create from Xcursor file contents (ptr to image) + virtual ~XCursorImageXCur (); + +protected: + void parseImgData (const void *aImgData); +}; + + +class XCursorImagesXCur : public XCursorImages { +public: + XCursorImagesXCur (const QDir &aDir, const QString &aName); + XCursorImagesXCur (const QString &aFileName); + +protected: + bool parseCursorFile (const QString &fname); +}; + + +#endif diff --git a/lxqt-config-appearance/CMakeLists.txt b/lxqt-config-appearance/CMakeLists.txt new file mode 100644 index 0000000..081fe56 --- /dev/null +++ b/lxqt-config-appearance/CMakeLists.txt @@ -0,0 +1,88 @@ +project(lxqt-config-appearance) + +include_directories( + "${CMAKE_CURRENT_BINARY_DIR}" + ${LXQT_INCLUDE_DIRS} + ${QTXDG_INCLUDE_DIRS} + "${CMAKE_SOURCE_DIR}/liblxqt-config-cursor" + "${CMAKE_BINARY_DIR}/liblxqt-config-cursor" +) + +set(H_FILES + iconthemeinfo.h +) + +set(MOC_FILES + iconthemeconfig.h + lxqtthemeconfig.h + fontsconfig.h + styleconfig.h + fontconfigfile.h +) + +set(CPP_FILES + main.cpp + iconthemeconfig.cpp + iconthemeinfo.cpp + lxqtthemeconfig.cpp + fontsconfig.cpp + styleconfig.cpp + fontconfigfile.cpp +) + +set(UI_FILES + iconthemeconfig.ui + lxqtthemeconfig.ui + fontsconfig.ui + styleconfig.ui +) + +set(QRC_FILES "") + +set(LIBRARIES + ${QTXDG_LIBRARIES} + ${LXQT_LIBRARIES} +) + + +# Translations ********************************** +lxqt_translate_ts(QM_FILES + UPDATE_TRANSLATIONS ${UPDATE_TRANSLATIONS} + SOURCES + ${H_FILES} + ${CPP_FILES} + ${UI_FILES} + INSTALL_DIR + "${LXQT_TRANSLATIONS_DIR}/${PROJECT_NAME}" +) + +lxqt_app_translation_loader(QM_LOADER ${PROJECT_NAME}) +lxqt_translate_desktop(DESKTOP_FILES SOURCES ${PROJECT_NAME}.desktop.in) + +#************************************************ + +qt5_wrap_ui(UI_HEADERS ${UI_FILES}) +qt5_add_resources(QRC_SOURCES ${QRC_FILES}) + +add_executable(${PROJECT_NAME} + ${CPP_FILES} + ${UI_FILES} + ${RESOURCES} + ${QRC_SOURCES} + ${QM_FILES} + ${QM_LOADER} + ${MOC_SOURCES} + ${DESKTOP_FILES} +) + +target_link_libraries(${PROJECT_NAME} + KF5::WindowSystem + Qt5::Widgets + Qt5::X11Extras + Qt5::Xml + ${LIBRARIES} + lxqt-config-cursor +) + +install(TARGETS ${PROJECT_NAME} RUNTIME DESTINATION bin) +install(FILES ${DESKTOP_FILES} DESTINATION ${CMAKE_INSTALL_PREFIX}/share/applications) diff --git a/lxqt-config-appearance/fontconfigfile.cpp b/lxqt-config-appearance/fontconfigfile.cpp new file mode 100644 index 0000000..d0dc852 --- /dev/null +++ b/lxqt-config-appearance/fontconfigfile.cpp @@ -0,0 +1,235 @@ +/* + * Copyright (C) 2014 Hong Jen Yee (PCMan) + * LXQt project: http://lxde.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) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "fontconfigfile.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +FontConfigFile::FontConfigFile(QObject* parent): + QObject(parent), + mAntialias(true), + mHinting(true), + mSubpixel("rgb"), + mHintStyle("hintslight"), + mDpi(96), + mAutohint(false), + mSaveTimer(NULL) +{ + mDirPath = QString::fromLocal8Bit(qgetenv("XDG_CONFIG_HOME")); + QString homeDir = QStandardPaths::writableLocation(QStandardPaths::HomeLocation); + if(mDirPath.isEmpty()) + mDirPath = homeDir % "/.config"; + mDirPath += "/fontconfig"; + mFilePath = mDirPath + "/fonts.conf"; + + load(); +} + +FontConfigFile::~FontConfigFile() +{ + if(mSaveTimer) // has pending save request + { + delete mSaveTimer; + mSaveTimer = NULL; + save(); + } +} + +void FontConfigFile::setAntialias(bool value) +{ + mAntialias = value; + queueSave(); +} + +void FontConfigFile::setSubpixel(QByteArray value) +{ + mSubpixel = value; + queueSave(); +} + +void FontConfigFile::setHinting(bool value) +{ + mHinting = value; + queueSave(); +} + +void FontConfigFile::setHintStyle(QByteArray value) +{ + mHintStyle = value; + queueSave(); +} + +void FontConfigFile::setDpi(int value) +{ + mDpi = value; + queueSave(); +} + +void FontConfigFile::setAutohint(bool value) +{ + mAutohint = value; + queueSave(); +} + +void FontConfigFile::load() +{ + QFile file(mFilePath); + if(file.open(QIODevice::ReadOnly)) + { + QByteArray buffer = file.readAll(); + file.close(); + if(buffer.contains("lxqt-config-appearance")) // the config file is created by us + { + // doing full xml parsing is over-kill. let's use some simpler brute-force methods. + QDomDocument doc; + doc.setContent(&file); + file.close(); + QDomElement docElem = doc.documentElement(); + QDomNodeList editNodes = docElem.elementsByTagName("edit"); + for(int i = 0; i < editNodes.count(); ++i) + { + QDomElement editElem = editNodes.at(i).toElement(); + QByteArray name = editElem.attribute("name").toLatin1(); + if(name == "antialias") + { + QString value = editElem.firstChildElement("bool").text(); + mAntialias = value[0] == 't' ? true : false; + } + else if(name == "rgba") + { + QString value = editElem.firstChildElement("const").text(); + mSubpixel = value.toLatin1(); + } + else if(name == "hinting") + { + QString value = editElem.firstChildElement("bool").text(); + mHinting = value[0] == 't' ? true : false; + } + else if(name == "hintstyle") + { + QString value = editElem.firstChildElement("const").text(); + mHintStyle = value.toLatin1(); + } + else if(name == "dpi") + { + QString value = editElem.firstChildElement("double").text(); + mDpi = value.toInt(); + } + else if(name == "autohint") + { + QString value = editElem.firstChildElement("bool").text(); + mAutohint = value[0] == 't' ? true : false; + } + } + } + else // the config file is created by others => make a backup and write our config + { + QFile backup(mFilePath + ".bak"); + if(backup.open(QIODevice::WriteOnly)) + { + backup.write(buffer); + backup.close(); + } + queueSave(); // overwrite with our file + } + } +} + +void FontConfigFile::save() +{ + if(mSaveTimer) + { + mSaveTimer->deleteLater(); + mSaveTimer = NULL; + } + + QFile file(mFilePath); + QDir().mkdir(mDirPath); + // References: https://wiki.archlinux.org/index.php/Font_Configuration + if(file.open(QIODevice::WriteOnly)) + { + QTextStream s(&file); + s << + "\n" + "\n" + "\n" + "\n" + " \n" + " \n" + " " << (mAntialias ? "true" : "false") << "\n" + " \n" + " \n" + " \n" + " \n" + " " << mSubpixel << "\n" + " \n" + " \n" + " \n" + " \n" + " lcddefault\n" + " \n" + " \n" + " \n" + " \n" + " " << (mHinting ? "true" : "false") << "\n" + " \n" + " \n" + " \n" + " \n" + " " << mHintStyle << "\n" + " \n" + " \n" + " \n" + " \n" + " " << (mAutohint ? "true" : "false") << "\n" + " \n" + " \n" + " \n" + " \n" + " " << mDpi << "\n" + " \n" + " \n" + ""; + s.flush(); + file.close(); + } +} + +void FontConfigFile::queueSave() +{ + if(mSaveTimer) + mSaveTimer->start(1500); + else + { + mSaveTimer = new QTimer(); + mSaveTimer->setSingleShot(true); + connect(mSaveTimer, SIGNAL(timeout()), this, SLOT(save())); + mSaveTimer->start(1500); + } +} + diff --git a/lxqt-config-appearance/fontconfigfile.h b/lxqt-config-appearance/fontconfigfile.h new file mode 100644 index 0000000..8001b62 --- /dev/null +++ b/lxqt-config-appearance/fontconfigfile.h @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2014 Hong Jen Yee (PCMan) + * LXQt project: http://lxde.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) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef FONTCONFIGFILE_H +#define FONTCONFIGFILE_H + +#include +#include +#include + +class QTimer; + +class FontConfigFile: public QObject +{ + Q_OBJECT +public: + explicit FontConfigFile(QObject* parent = 0); + virtual ~FontConfigFile(); + + bool antialias() const { + return mAntialias; + } + void setAntialias(bool value); + + bool hinting() const { + return mHinting; + } + void setHinting(bool value); + + QByteArray subpixel() const { + return mSubpixel; + } + void setSubpixel(QByteArray value); + + QByteArray hintStyle() const { + return mHintStyle; + } + void setHintStyle(QByteArray value); + + int dpi() const { + return mDpi; + } + void setDpi(int value); + + bool autohint() const { + return mAutohint; + } + void setAutohint(bool value); + +private Q_SLOTS: + void save(); + +private: + void load(); + void queueSave(); + +private: + bool mAntialias; + bool mHinting; + QByteArray mSubpixel; + QByteArray mHintStyle; + int mDpi; + bool mAutohint; + QString mDirPath; + QString mFilePath; + QTimer* mSaveTimer; +}; + +#endif // FONTCONFIGFILE_H diff --git a/lxqt-config-appearance/fontsconfig.cpp b/lxqt-config-appearance/fontsconfig.cpp new file mode 100644 index 0000000..ca10f66 --- /dev/null +++ b/lxqt-config-appearance/fontsconfig.cpp @@ -0,0 +1,196 @@ +/* BEGIN_COMMON_COPYRIGHT_HEADER + * (c)LGPL2+ + * + * LXQt - a lightweight, Qt based, desktop toolset + * http://lxde.org/ + * + * Copyright: 2014 LXQt team + * Authors: + * Hong Jen Yee (PCMan) + * + * This program or library is free software; you can redistribute it + * and/or modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + * + * END_COMMON_COPYRIGHT_HEADER */ + +#include "fontsconfig.h" +#include "ui_fontsconfig.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef Q_WS_X11 +extern void qt_x11_apply_settings_in_all_apps(); +#endif + +static const char* subpixelNames[] = {"none", "rgb", "bgr", "vrgb", "vbgr"}; +static const char* hintStyleNames[] = {"hintnone", "hintslight", "hintmedium", "hintfull"}; + +FontsConfig::FontsConfig(LxQt::Settings* settings, QSettings* qtSettings, QWidget* parent) : + QWidget(parent), + ui(new Ui::FontsConfig), + mSettings(settings), + mQtSettings(qtSettings), + mFontConfigFile() +{ + ui->setupUi(this); + + initControls(); + + connect(ui->fontName, SIGNAL(currentFontChanged(QFont)), SLOT(updateQtFont())); + connect(ui->fontStyle, SIGNAL(currentIndexChanged(int)), SLOT(updateQtFont())); + connect(ui->fontSize, SIGNAL(valueChanged(int)), SLOT(updateQtFont())); + + connect(ui->antialias, SIGNAL(toggled(bool)), SLOT(antialiasToggled(bool))); + connect(ui->subpixel, SIGNAL(currentIndexChanged(int)), SLOT(subpixelChanged(int))); + connect(ui->hinting, SIGNAL(toggled(bool)), SLOT(hintingToggled(bool))); + connect(ui->hintStyle, SIGNAL(currentIndexChanged(int)), SLOT(hintStyleChanged(int))); + connect(ui->dpi, SIGNAL(valueChanged(int)), SLOT(dpiChanged(int))); + connect(ui->autohint, SIGNAL(toggled(bool)), SLOT(autohintToggled(bool))); +} + + +FontsConfig::~FontsConfig() +{ + delete ui; +} + + +void FontsConfig::initControls() +{ + // read Qt style settings from Qt Trolltech.conf config + mQtSettings->beginGroup(QLatin1String("Qt")); + + QString fontName = mQtSettings->value("font").toString(); + QFont font; + font.fromString(fontName); + ui->fontName->setCurrentFont(font); + ui->fontSize->setValue(font.pointSize()); + int fontStyle = 0; + if(font.bold()) + fontStyle = font.italic() ? 3 : 1; + else if(font.italic()) + fontStyle = 2; + ui->fontStyle->setCurrentIndex(fontStyle); + + mQtSettings->endGroup(); + + // load fontconfig config + ui->antialias->setChecked(mFontConfigFile.antialias()); + ui->autohint->setChecked(mFontConfigFile.autohint()); + + QByteArray subpixelStr = mFontConfigFile.subpixel(); + int subpixel; + for(subpixel = 0; subpixel < 5; ++subpixel) + { + if(subpixelStr == subpixelNames[subpixel]) + break; + } + if(subpixel < 5) + ui->subpixel->setCurrentIndex(subpixel); + + ui->hinting->setChecked(mFontConfigFile.hinting()); + + QByteArray hintStyleStr = mFontConfigFile.hintStyle(); + int hintStyle; + for(hintStyle = 0; hintStyle < 4; ++hintStyle) + { + if(hintStyleStr == hintStyleNames[hintStyle]) + break; + } + if(hintStyle < 4) + ui->hintStyle->setCurrentIndex(hintStyle); + + int dpi = mFontConfigFile.dpi(); + ui->dpi->setValue(dpi); + + update(); +} + +void FontsConfig::antialiasToggled(bool toggled) +{ + mFontConfigFile.setAntialias(toggled); +} + +void FontsConfig::dpiChanged(int value) +{ + mFontConfigFile.setDpi(value); +} + +void FontsConfig::hintingToggled(bool toggled) +{ + mFontConfigFile.setHinting(toggled); +} + +void FontsConfig::subpixelChanged(int index) +{ + mFontConfigFile.setSubpixel(subpixelNames[index]); +} + +void FontsConfig::hintStyleChanged(int index) +{ + mFontConfigFile.setHintStyle(hintStyleNames[index]); +} + +void FontsConfig::autohintToggled(bool toggled) +{ + mFontConfigFile.setAutohint(toggled); +} + +void FontsConfig::updateQtFont() +{ + // FIXME: the change does not apply to some currently running Qt programs. + // FIXME: does not work with KDE apps + // TODO: also write the config values to GTK+ config files (gtk-2.0.rc and gtk3/settings.ini) + // FIXME: the selected font does not apply to our own application. Why? + + QFont font = ui->fontName->currentFont(); + int size = ui->fontSize->value(); + bool bold = false; + bool italic = false; + switch(ui->fontStyle->currentIndex()) + { + case 1: + bold = true; + break; + case 2: + italic = true; + break; + case 3: + bold = italic = true; + } + + font.setPointSize(size); + font.setBold(bold); + font.setItalic(italic); + + mQtSettings->beginGroup(QLatin1String("Qt")); + mQtSettings->setValue("font", font.toString()); + mQtSettings->endGroup(); + mQtSettings->sync(); + +#ifdef Q_WS_X11 + qt_x11_apply_settings_in_all_apps(); +#endif + + update(); +} diff --git a/lxqt-config-appearance/fontsconfig.h b/lxqt-config-appearance/fontsconfig.h new file mode 100644 index 0000000..945c8a7 --- /dev/null +++ b/lxqt-config-appearance/fontsconfig.h @@ -0,0 +1,70 @@ +/* BEGIN_COMMON_COPYRIGHT_HEADER + * (c)LGPL2+ + * + * LXQt - a lightweight, Qt based, desktop toolset + * http://razor-qt.org + * + * Copyright: 2012 Razor team + * Authors: + * Alexander Sokoloff + * + * This program or library is free software; you can redistribute it + * and/or modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + * + * END_COMMON_COPYRIGHT_HEADER */ + +#ifndef FONTSCONFIG_H +#define FONTSCONFIG_H + +#include +#include +#include +#include "fontconfigfile.h" + +class QTreeWidgetItem; +class QSettings; + +namespace Ui { + class FontsConfig; +} + +class FontsConfig : public QWidget +{ + Q_OBJECT + +public: + explicit FontsConfig(LxQt::Settings *settings, QSettings *qtSettings, QWidget *parent = 0); + ~FontsConfig(); + +public Q_SLOTS: + void initControls(); + +private Q_SLOTS: + void updateQtFont(); + void antialiasToggled(bool toggled); + void hintingToggled(bool toggled); + void subpixelChanged(int index); + void hintStyleChanged(int index); + void dpiChanged(int value); + void autohintToggled(bool toggled); + +private: + Ui::FontsConfig *ui; + QSettings *mQtSettings; + LxQt::Settings *mSettings; + FontConfigFile mFontConfigFile; +}; + +#endif // FONTSCONFIG_H diff --git a/lxqt-config-appearance/fontsconfig.ui b/lxqt-config-appearance/fontsconfig.ui new file mode 100644 index 0000000..cf066d0 --- /dev/null +++ b/lxqt-config-appearance/fontsconfig.ui @@ -0,0 +1,257 @@ + + + FontsConfig + + + + 0 + 0 + 421 + 379 + + + + + + + + 75 + true + + + + Font + + + + + + + Default font for user interface + + + + + + Font name: + + + + + + + + + + Style: + + + + + + + Point size: + + + + + + + + + + + Normal + + + + + Bold + + + + + Italic + + + + + Bold Italic + + + + + + + + + + + The following settings only affect newly started applications + + + + + + Use antialias fonts + + + + + + + Font hinting style: + + + + + + + false + + + + None + + + + + Slight + + + + + Medium + + + + + Full + + + + + + + + Font hinting + + + + + + + Resolution (DPI): + + + + + + + Autohint + + + + + + + -1 + + + 1048576 + + + + + + + Subpixel antialiasing: + + + + + + + false + + + + None + + + + + RGB + + + + + BGR + + + + + VRGB + + + + + VBGR + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + antialias + toggled(bool) + subpixel + setEnabled(bool) + + + 225 + 109 + + + 298 + 140 + + + + + hinting + toggled(bool) + hintStyle + setEnabled(bool) + + + 225 + 171 + + + 298 + 202 + + + + + diff --git a/lxqt-config-appearance/iconthemeconfig.cpp b/lxqt-config-appearance/iconthemeconfig.cpp new file mode 100644 index 0000000..e791cca --- /dev/null +++ b/lxqt-config-appearance/iconthemeconfig.cpp @@ -0,0 +1,133 @@ +/* BEGIN_COMMON_COPYRIGHT_HEADER + * (c)LGPL2+ + * + * LXQt - a lightweight, Qt based, desktop toolset + * http://razor-qt.org + * + * Copyright: 2010-2011 Razor team + * Authors: + * Petr Vanek + * + * This program or library is free software; you can redistribute it + * and/or modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + * + * END_COMMON_COPYRIGHT_HEADER */ + +#include "iconthemeconfig.h" + +#include +#include +#include +#include +#include +#include + + +IconThemeConfig::IconThemeConfig(LxQt::Settings* settings, QWidget* parent): + QWidget(parent), + m_settings(settings) +{ + setupUi(this); + + initIconsThemes(); + initControls(); + connect(iconThemeList, SIGNAL(itemClicked(QTreeWidgetItem*,int)), + this, SLOT(iconThemeSelected(QTreeWidgetItem*,int))); + + connect(LxQt::Settings::globalSettings(), SIGNAL(settingsChanged()), + this, SLOT(update())); +} + + +void IconThemeConfig::initIconsThemes() +{ + QStringList processed; + QStringList baseDirs = QIcon::themeSearchPaths(); + + foreach (QString baseDirName, baseDirs) + { + QDir baseDir(baseDirName); + if (!baseDir.exists()) + continue; + + QFileInfoList dirs = baseDir.entryInfoList(QDir::AllDirs | QDir::NoDotAndDotDot, QDir::Name); + foreach (QFileInfo dir, dirs) + { + if (!processed.contains(dir.canonicalFilePath())) + { + processed << dir.canonicalFilePath(); + + IconThemeInfo theme(QDir(dir.canonicalFilePath())); + if (theme.isValid() && (!theme.isHidden())) + { + QTreeWidgetItem *item = new QTreeWidgetItem(iconThemeList); + item->setSizeHint(0, QSize(42,42)); // make icons non-cropped + item->setData(0, Qt::UserRole, theme.name()); + + item->setIcon(0, theme.icon("document-open")); + item->setIcon(1, theme.icon("document-new")); + item->setIcon(2, theme.icon("edit-undo")); + item->setIcon(3, theme.icon("media-playback-start")); + + item->setText(4, theme.comment().isEmpty() ? theme.text() : theme.text() + " (" + theme.comment() + ")"); + } + } + } + } + + iconThemeList->setColumnCount(5); + for (int i=0; iheader()->count()-1; ++i) + { + iconThemeList->resizeColumnToContents(i); + } +} + + +void IconThemeConfig::initControls() +{ + QString currentTheme = LxQt::Settings::globalSettings()->value("icon_theme").toString(); + XdgIcon::setThemeName(currentTheme); + QTreeWidgetItemIterator it(iconThemeList); + while (*it) { + if ((*it)->data(0, Qt::UserRole).toString() == currentTheme) + { + iconThemeList->setCurrentItem((*it)); + break; + } + ++it; + } + + update(); +} + + +IconThemeConfig::~IconThemeConfig() +{ +} + + +void IconThemeConfig::iconThemeSelected(QTreeWidgetItem *item, int column) +{ + Q_UNUSED(column); + QString theme = item->data(0, Qt::UserRole).toString(); + if (!theme.isEmpty()) + { + XdgIcon::setThemeName(theme); + m_settings->setValue("icon_theme", theme); + m_settings->sync(); + } +} + + diff --git a/lxqt-config-appearance/iconthemeconfig.h b/lxqt-config-appearance/iconthemeconfig.h new file mode 100644 index 0000000..288cc6c --- /dev/null +++ b/lxqt-config-appearance/iconthemeconfig.h @@ -0,0 +1,58 @@ +/* BEGIN_COMMON_COPYRIGHT_HEADER + * (c)LGPL2+ + * + * LXQt - a lightweight, Qt based, desktop toolset + * http://razor-qt.org + * + * Copyright: 2010-2011 Razor team + * Authors: + * Petr Vanek + * + * This program or library is free software; you can redistribute it + * and/or modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + * + * END_COMMON_COPYRIGHT_HEADER */ + +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include "ui_iconthemeconfig.h" +#include "iconthemeinfo.h" + +namespace LxQt { +class Settings; +} + + +class IconThemeConfig : public QWidget, public Ui::IconThemeConfig +{ + Q_OBJECT + +public: + IconThemeConfig(LxQt::Settings *settings, QWidget *parent = 0); + ~IconThemeConfig(); + +private: + LxQt::Settings *m_settings; + void initIconsThemes(); + +public slots: + void initControls(); + +private slots: + void iconThemeSelected(QTreeWidgetItem *item, int column); +}; + +#endif diff --git a/lxqt-config-appearance/iconthemeconfig.ui b/lxqt-config-appearance/iconthemeconfig.ui new file mode 100644 index 0000000..a32ab73 --- /dev/null +++ b/lxqt-config-appearance/iconthemeconfig.ui @@ -0,0 +1,88 @@ + + + IconThemeConfig + + + + 0 + 0 + 450 + 327 + + + + LXQt Appearance Configuration + + + + + + + 75 + true + + + + Icons Theme + + + + + + + + 0 + 0 + + + + Qt::ScrollBarAlwaysOff + + + true + + + + 22 + 22 + + + + false + + + true + + + 4 + + + false + + + + 1 + + + + + 2 + + + + + 3 + + + + + 4 + + + + + + + + + diff --git a/lxqt-config-appearance/iconthemeinfo.cpp b/lxqt-config-appearance/iconthemeinfo.cpp new file mode 100644 index 0000000..0936c40 --- /dev/null +++ b/lxqt-config-appearance/iconthemeinfo.cpp @@ -0,0 +1,105 @@ +/* BEGIN_COMMON_COPYRIGHT_HEADER + * (c)LGPL2+ + * + * LXQt - a lightweight, Qt based, desktop toolset + * https://sourceforge.net/projects/lxde-qt/ + * + * Copyright: 2010-2011 Razor team + * Authors: + * Alexander Sokoloff + * + * This program or library is free software; you can redistribute it + * and/or modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + * + * END_COMMON_COPYRIGHT_HEADER */ + +#include "iconthemeinfo.h" +#include + + +#define PRIVIEW_ICON_SIZE 22 + + +IconThemeInfo::IconThemeInfo(const QDir &dir): + mValid(false), + mHidden(false) +{ + mName = dir.dirName(); + if (dir.exists("index.theme")) + load(dir.absoluteFilePath("index.theme")); +} + + +void IconThemeInfo::load(const QString &fileName) +{ + mFileName = fileName; + mValid = false; + QSettings file(mFileName, QSettings::IniFormat); + if (file.status() != QSettings::NoError) + return; + + if (file.value("Icon Theme/Directories").toStringList().join("").isEmpty()) + return; + + mHidden = file.value("Icon Theme/Hidden", false).toBool(); + mText = file.value("Icon Theme/Name").toString(); + mComment = file.value("Icon Theme/Comment").toString(); + mValid = true; + loadDirsInfo(file, QFileInfo(mFileName).dir().canonicalPath()); +} + + +void IconThemeInfo::loadDirsInfo(QSettings &file, const QString &path) +{ + foreach (QString i, file.value("Icon Theme/Directories", QStringList()).toStringList()) + { + file.beginGroup(i); + if (file.value("Size", 0).toInt() == PRIVIEW_ICON_SIZE && + file.value("Context").toString() == "Actions" + ) + { + mActionsDir = path + QDir::separator() + i; + file.endGroup(); + return; + } + file.endGroup(); + } +} + + +QIcon IconThemeInfo::icon(const QString &iconName) const +{ + QDir dir(mActionsDir); + + if (dir.exists(iconName + ".png")) + { + QIcon icon(mActionsDir + QDir::separator() + iconName + ".png"); + return icon; + } + + if (dir.exists(iconName + ".svg")) + { + QIcon icon(mActionsDir + QDir::separator() + iconName + ".svg"); + return icon; + } + + if (dir.exists(iconName + ".xpm")) + { + QIcon icon(mActionsDir + QDir::separator() + iconName + ".xpm"); + return icon; + } + + return QIcon(); +} diff --git a/lxqt-config-appearance/iconthemeinfo.h b/lxqt-config-appearance/iconthemeinfo.h new file mode 100644 index 0000000..1ae6dff --- /dev/null +++ b/lxqt-config-appearance/iconthemeinfo.h @@ -0,0 +1,64 @@ +/* BEGIN_COMMON_COPYRIGHT_HEADER + * (c)LGPL2+ + * + * LXQt - a lightweight, Qt based, desktop toolset + * https://sourceforge.net/projects/lxde-qt/ + * + * Copyright: 2010-2011 Razor team + * Authors: + * Alexander Sokoloff + * + * This program or library is free software; you can redistribute it + * and/or modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + * + * END_COMMON_COPYRIGHT_HEADER */ + +#ifndef ICONTHEMEINFO_H +#define ICONTHEMEINFO_H + +#include +#include +#include +#include + +class IconThemeInfo +{ +public: + IconThemeInfo(const QDir &dir); + + QString fileName() const { return mFileName; } + QString name() const { return mName; } + QString text() const { return mText; } + QString comment() const { return mComment; } + + bool isValid() const { return mValid; } + bool isHidden() const { return mHidden; } + QIcon icon(const QString &iconName) const; +private: + QString mFileName; + QString mName; + QString mText; + QString mComment; + QString mActionsDir; + + bool mValid; + bool mHidden; + + void load(const QString &fileName); + void loadDirsInfo(QSettings &file, const QString &path); +}; + + +#endif // ICONTHEMEINFO_H diff --git a/lxqt-config-appearance/lxqt-config-appearance.desktop.in b/lxqt-config-appearance/lxqt-config-appearance.desktop.in new file mode 100644 index 0000000..2fae068 --- /dev/null +++ b/lxqt-config-appearance/lxqt-config-appearance.desktop.in @@ -0,0 +1,11 @@ +[Desktop Entry] +Type=Application +Name=Appearance +GenericName=Appearance settings +Comment=Appearance settings for LXQt +Exec=lxqt-config-appearance +Icon=preferences-desktop-theme +Categories=Settings;DesktopSettings;Qt;LXQt; +OnlyShowIn=LXDE;LXQt; + +#TRANSLATIONS_DIR=translations diff --git a/lxqt-config-appearance/lxqtthemeconfig.cpp b/lxqt-config-appearance/lxqtthemeconfig.cpp new file mode 100644 index 0000000..06ebe13 --- /dev/null +++ b/lxqt-config-appearance/lxqtthemeconfig.cpp @@ -0,0 +1,109 @@ +/* BEGIN_COMMON_COPYRIGHT_HEADER + * (c)LGPL2+ + * + * LXQt - a lightweight, Qt based, desktop toolset + * http://razor-qt.org + * + * Copyright: 2012 Razor team + * Authors: + * Alexander Sokoloff + * + * This program or library is free software; you can redistribute it + * and/or modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + * + * END_COMMON_COPYRIGHT_HEADER */ + +#include "lxqtthemeconfig.h" +#include "ui_lxqtthemeconfig.h" +#include +#include +#include + +LxQtThemeConfig::LxQtThemeConfig(LxQt::Settings *settings, QWidget *parent) : + QWidget(parent), + ui(new Ui::LxQtThemeConfig), + mSettings(settings) +{ + ui->setupUi(this); + + connect(ui->lxqtThemeList, SIGNAL(itemClicked(QTreeWidgetItem*,int)), + this, SLOT(lxqtThemeSelected(QTreeWidgetItem*,int))); + + + QList themes = LxQt::LxQtTheme::allThemes(); + foreach(LxQt::LxQtTheme theme, themes) + { + QString themeName = theme.name(); + themeName[0] = themeName[0].toTitleCase(); + QTreeWidgetItem *item = new QTreeWidgetItem(QStringList(themeName)); + if (!theme.previewImage().isEmpty()) + { + item->setIcon(0, QIcon(theme.previewImage())); + } + item->setSizeHint(0, QSize(42,42)); // make icons non-cropped + item->setData(0, Qt::UserRole, theme.name()); + ui->lxqtThemeList->addTopLevelItem(item); + } + + initControls(); +} + + +LxQtThemeConfig::~LxQtThemeConfig() +{ + delete ui; +} + + +void LxQtThemeConfig::initControls() +{ + QString currentTheme = mSettings->value("theme").toString(); + + QTreeWidgetItemIterator it(ui->lxqtThemeList); + while (*it) { + if ((*it)->data(0, Qt::UserRole).toString() == currentTheme) + { + ui->lxqtThemeList->setCurrentItem((*it)); + break; + } + ++it; + } + + update(); +} + + +void LxQtThemeConfig::lxqtThemeSelected(QTreeWidgetItem* item, int column) +{ + Q_UNUSED(column); + if (!item) + return; + + QVariant themeName = item->data(0, Qt::UserRole); + mSettings->setValue("theme", themeName); + + LxQt::LxQtTheme theme(themeName.toString()); + if(theme.isValid()) { + QString wallpaper = theme.desktopBackground(); + if(!wallpaper.isEmpty()) { + // call pcmanfm-qt to update wallpaper + QProcess process; + QStringList args; + args << "--set-wallpaper" << wallpaper; + process.start("pcmanfm-qt", args, QIODevice::NotOpen); + process.waitForFinished(); + } + } +} diff --git a/lxqt-config-appearance/lxqtthemeconfig.h b/lxqt-config-appearance/lxqtthemeconfig.h new file mode 100644 index 0000000..f94e35d --- /dev/null +++ b/lxqt-config-appearance/lxqtthemeconfig.h @@ -0,0 +1,59 @@ +/* BEGIN_COMMON_COPYRIGHT_HEADER + * (c)LGPL2+ + * + * LXQt - a lightweight, Qt based, desktop toolset + * http://razor-qt.org + * + * Copyright: 2012 Razor team + * Authors: + * Alexander Sokoloff + * + * This program or library is free software; you can redistribute it + * and/or modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + * + * END_COMMON_COPYRIGHT_HEADER */ + +#ifndef LXQTTHEMECONFIG_H +#define LXQTTHEMECONFIG_H + +#include +#include + +class QTreeWidgetItem; + +namespace Ui { + class LxQtThemeConfig; +} + +class LxQtThemeConfig : public QWidget +{ + Q_OBJECT + +public: + explicit LxQtThemeConfig(LxQt::Settings *settings, QWidget *parent = 0); + ~LxQtThemeConfig(); + +public slots: + void initControls(); + +private slots: + void lxqtThemeSelected(QTreeWidgetItem* item, int column); + +private: + Ui::LxQtThemeConfig *ui; + LxQt::Settings *mSettings; +}; + +#endif // LXQTTHEMECONFIG_H diff --git a/lxqt-config-appearance/lxqtthemeconfig.ui b/lxqt-config-appearance/lxqtthemeconfig.ui new file mode 100644 index 0000000..d4a02c5 --- /dev/null +++ b/lxqt-config-appearance/lxqtthemeconfig.ui @@ -0,0 +1,58 @@ + + + LxQtThemeConfig + + + + 0 + 0 + 400 + 300 + + + + + + + + 75 + true + + + + LXQt Theme + + + + + + + true + + + + 100 + 32 + + + + false + + + true + + + false + + + + 1 + + + + + + + + + diff --git a/lxqt-config-appearance/main.cpp b/lxqt-config-appearance/main.cpp new file mode 100644 index 0000000..9a3691e --- /dev/null +++ b/lxqt-config-appearance/main.cpp @@ -0,0 +1,76 @@ +/* BEGIN_COMMON_COPYRIGHT_HEADER + * (c)LGPL2+ + * + * LXQt - a lightweight, Qt based, desktop toolset + * http://razor-qt.org + * + * Copyright: 2010-2011 Razor team + * Authors: + * Petr Vanek + * + * This program or library is free software; you can redistribute it + * and/or modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + * + * END_COMMON_COPYRIGHT_HEADER */ + +#include +#include + +#include +#include +#include +#include "iconthemeconfig.h" +#include "lxqtthemeconfig.h" +#include "styleconfig.h" +#include "fontsconfig.h" + +#include "../liblxqt-config-cursor/selectwnd.h" + +int main (int argc, char **argv) +{ + LxQt::SingleApplication app(argc, argv); + LxQt::Settings* settings = new LxQt::Settings("lxqt"); + LxQt::ConfigDialog* dialog = new LxQt::ConfigDialog(QObject::tr("LXQt Appearance Configuration"), settings); + + app.setActivationWindow(dialog); + + QSettings& qtSettings = *settings; // use lxqt config file for Qt settings in Qt5. + StyleConfig* stylePage = new StyleConfig(settings, &qtSettings, dialog); + dialog->addPage(stylePage, QObject::tr("Widget Style"), QStringList() << "preferences-desktop-theme" << "preferences-desktop"); + QObject::connect(dialog, SIGNAL(reset()), stylePage, SLOT(initControls())); + + IconThemeConfig* iconPage = new IconThemeConfig(settings, dialog); + dialog->addPage(iconPage, QObject::tr("Icons Theme"), QStringList() << "preferences-desktop-icons" << "preferences-desktop"); + QObject::connect(dialog, SIGNAL(reset()), iconPage, SLOT(initControls())); + + LxQtThemeConfig* themePage = new LxQtThemeConfig(settings, dialog); + dialog->addPage(themePage, QObject::tr("LXQt Theme"), QStringList() << "preferences-desktop-color" << "preferences-desktop"); + QObject::connect(dialog, SIGNAL(reset()), themePage, SLOT(initControls())); + + FontsConfig* fontsPage = new FontsConfig(settings, &qtSettings, dialog); + dialog->addPage(fontsPage, QObject::tr("Font"), QStringList() << "preferences-desktop-font" << "preferences-desktop"); + QObject::connect(dialog, SIGNAL(reset()), fontsPage, SLOT(initControls())); + + SelectWnd* cursorPage = new SelectWnd(settings, dialog); + cursorPage->setCurrent(); + dialog->addPage(cursorPage, QObject::tr("Cursor"), QStringList() << "input-mouse" << "preferences-desktop"); + + dialog->setAttribute(Qt::WA_DeleteOnClose); + dialog->setWindowIcon(QIcon::fromTheme("preferences-desktop-theme")); + dialog->show(); + + return app.exec(); +} + diff --git a/lxqt-config-appearance/man/lxqt-config-appearance.1 b/lxqt-config-appearance/man/lxqt-config-appearance.1 new file mode 100644 index 0000000..cd4f02f --- /dev/null +++ b/lxqt-config-appearance/man/lxqt-config-appearance.1 @@ -0,0 +1,50 @@ +.TH lxqt-config-appearance "1" "September 2012" "LXQt\ 0.7.0" "LXQt\ GUI settings" +.SH NAME +lxqt-config-appearance \- GUI appearance application of \fBLXQt\fR: the faster and lighter QT Desktop Environment +.SH SYNOPSIS +.B lxqt-config-appearance +.br +.SH DESCRIPTION +With this application you can setting and configuring qt/lxqt gui appearance of programs. +.P +The GUI applications in linux depends of their respective subsystem, in lxqt the overal aspect of +many apps relies on QT4 framework gui. The \fBlxqt-config-appearance\fR application its the configuration center +to provide all aspects of setting \fBLXQt\fR desktop in session settings related programs. +.P +All remaining mayor aspect for lxqt appearance relies over qt4 config application (\fBqtconfig\-qt4\fR), due +the \fBLXQt\fR DE are based on Qt framework. +.P +\fBLXQt\fR is an advanced, easy-to-use, and fast desktop environment based on Qt +technologies, ships several core desktop components, all of which are optional: +.P + * Panel + * Desktop + * Application launcher + * Settings center \fI(related to this)\fR + * Session handler + * Polkit handler + * SSH pasword manager + * Display manager handler + * Power manager +.P +These components perform similar actions to those available in other desktop +environments, and their name is self-descriptive. They are usually not launched +by hand but automatically, when choosing a \fBLXQt\-qt\fR session in the Display +Manager. +.P +.SH "REPORTING BUGS" +Report bugs to https://github.com/lxde/lxde-qt/issues +.SH "SEE ALSO" +\fBLXQt\fR it has been tailored for users who value simplicity, speed, and +an intuitive interface, also intended for less powerful machines. See also: +.\" any module must refers to session app, for more info on start it +.P +\fBlxqt-session.1\fR LXQt module for manage LXQt complete environment. +.P +\fBlxqt-config.1\fR LXQt application for general config and settings. +.P +\fBqtconfig-qt4.1\fR Qt4 application for gui and appereance settings over all qt4 based software. +.P +.SH AUTHOR +This manual page was created by \fBPICCORO Lenz McKAY\fR \fI\fR +for \fBLXQt\fR project and VENENUX GNU/Linux but can be used by others. diff --git a/lxqt-config-appearance/styleconfig.cpp b/lxqt-config-appearance/styleconfig.cpp new file mode 100644 index 0000000..2c747bb --- /dev/null +++ b/lxqt-config-appearance/styleconfig.cpp @@ -0,0 +1,142 @@ +/* BEGIN_COMMON_COPYRIGHT_HEADER + * (c)LGPL2+ + * + * LXQt - a lightweight, Qt based, desktop toolset + * http://lxde.org/ + * + * Copyright: 2014 LXQt team + * Authors: + * Hong Jen Yee (PCMan) + * + * This program or library is free software; you can redistribute it + * and/or modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + * + * END_COMMON_COPYRIGHT_HEADER */ + +#include "styleconfig.h" +#include "ui_styleconfig.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef Q_WS_X11 +extern void qt_x11_apply_settings_in_all_apps(); +#endif + +StyleConfig::StyleConfig(LxQt::Settings* settings, QSettings* qtSettings, QWidget* parent) : + QWidget(parent), + ui(new Ui::StyleConfig), + mSettings(settings), + mQtSettings(qtSettings) +{ + ui->setupUi(this); + + connect(ui->styleList, SIGNAL(itemClicked(QTreeWidgetItem*,int)), + this, SLOT(styleSelected(QTreeWidgetItem*,int))); + + Q_FOREACH(const QString& name, QStyleFactory::keys()) + { + QTreeWidgetItem *item = new QTreeWidgetItem(QStringList(name)); + ui->styleList->addTopLevelItem(item); + } + + initControls(); + + connect(ui->toolButtonStyle, SIGNAL(currentIndexChanged(int)), SLOT(toolButtonStyleSelected(int))); + connect(ui->singleClickActivate, SIGNAL(toggled(bool)), SLOT(singleClickActivateToggled(bool))); +} + + +StyleConfig::~StyleConfig() +{ + delete ui; +} + + +void StyleConfig::initControls() +{ + // read Qt style settings from Qt Trolltech.conf config + mQtSettings->beginGroup(QLatin1String("Qt")); + QString currentTheme = mQtSettings->value("style").toString(); + mQtSettings->endGroup(); + + QTreeWidgetItemIterator it(ui->styleList); + while (*it) { + if ((*it)->data(0, Qt::DisplayRole).toString() == currentTheme) + { + ui->styleList->setCurrentItem((*it)); + break; + } + ++it; + } + + // read other widget related settings form LxQt settings. + QByteArray tb_style = mSettings->value("tool_button_style").toByteArray(); + // convert toolbar style name to value + QMetaEnum me = QToolBar::staticMetaObject.property(QToolBar::staticMetaObject.indexOfProperty("toolButtonStyle")).enumerator(); + int val = me.keyToValue(tb_style.constData()); + if(val == -1) + val = Qt::ToolButtonTextBesideIcon; + ui->toolButtonStyle->setCurrentIndex(val); + + // activate item views with single click + ui->singleClickActivate->setChecked( mSettings->value("single_click_activate", false).toBool()); + + update(); +} + + +void StyleConfig::styleSelected(QTreeWidgetItem* item, int column) +{ + Q_UNUSED(column); + if (!item) + return; + QVariant themeName = item->data(0, Qt::DisplayRole); + mQtSettings->beginGroup(QLatin1String("Qt")); + mQtSettings->setValue("style", themeName); + mQtSettings->endGroup(); + mQtSettings->sync(); + +#ifdef Q_WS_X11 + qt_x11_apply_settings_in_all_apps(); +#endif +} + +void StyleConfig::toolButtonStyleSelected(int index) +{ + // convert style value to string + QMetaEnum me = QToolBar::staticMetaObject.property(QToolBar::staticMetaObject.indexOfProperty("toolButtonStyle")).enumerator(); + if(index == -1) + index = Qt::ToolButtonTextBesideIcon; + const char* str = me.valueToKey(index); + if(str) + { + mSettings->setValue("tool_button_style", str); + mSettings->sync(); + } +} + +void StyleConfig::singleClickActivateToggled(bool toggled) +{ + mSettings->setValue("single_click_activate", toggled); + mSettings->sync(); +} + diff --git a/lxqt-config-appearance/styleconfig.h b/lxqt-config-appearance/styleconfig.h new file mode 100644 index 0000000..4608a98 --- /dev/null +++ b/lxqt-config-appearance/styleconfig.h @@ -0,0 +1,63 @@ +/* BEGIN_COMMON_COPYRIGHT_HEADER + * (c)LGPL2+ + * + * LXQt - a lightweight, Qt based, desktop toolset + * http://razor-qt.org + * + * Copyright: 2012 Razor team + * Authors: + * Alexander Sokoloff + * + * This program or library is free software; you can redistribute it + * and/or modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + * + * END_COMMON_COPYRIGHT_HEADER */ + +#ifndef STYLECONFIG_H +#define STYLECONFIG_H + +#include +#include + +class QTreeWidgetItem; +class QSettings; + +namespace Ui { + class StyleConfig; +} + +class StyleConfig : public QWidget +{ + Q_OBJECT + +public: + explicit StyleConfig(LxQt::Settings *settings, QSettings *qtSettings, QWidget *parent = 0); + ~StyleConfig(); + +public slots: + void initControls(); + +private slots: + void styleSelected(QTreeWidgetItem* item, int column); + void toolButtonStyleSelected(int index); + void singleClickActivateToggled(bool toggled); + +private: + Ui::StyleConfig *ui; + QSettings *mQtSettings; + LxQt::Settings *mSettings; +}; + +#endif // STYLECONFIG_H diff --git a/lxqt-config-appearance/styleconfig.ui b/lxqt-config-appearance/styleconfig.ui new file mode 100644 index 0000000..9a086aa --- /dev/null +++ b/lxqt-config-appearance/styleconfig.ui @@ -0,0 +1,98 @@ + + + StyleConfig + + + + 0 + 0 + 490 + 363 + + + + + + + + 75 + true + + + + Widget Style + + + + + + + + 0 + 1 + + + + true + + + false + + + false + + + + 1 + + + + + + + + Toolbar button style: + + + + + + + + Only display the icon + + + + + Only display the text + + + + + The text appears beside the icon + + + + + The text appears under the icon + + + + + Default + + + + + + + + Activate item on single click + + + + + + + + diff --git a/lxqt-config-appearance/translations/lxqt-config-appearance.ts b/lxqt-config-appearance/translations/lxqt-config-appearance.ts new file mode 100644 index 0000000..5d92f68 --- /dev/null +++ b/lxqt-config-appearance/translations/lxqt-config-appearance.ts @@ -0,0 +1,225 @@ + + + + + FontsConfig + + + Font + + + + + Default font for user interface + + + + + Font name: + + + + + Style: + + + + + Point size: + + + + + Normal + + + + + Bold + + + + + Italic + + + + + Bold Italic + + + + + The following settings only affect newly started applications + + + + + Use antialias fonts + + + + + Font hinting style: + + + + + + None + + + + + Slight + + + + + Medium + + + + + Full + + + + + Font hinting + + + + + Resolution (DPI): + + + + + Autohint + + + + + Subpixel antialiasing: + + + + + RGB + + + + + BGR + + + + + VRGB + + + + + VBGR + + + + + IconThemeConfig + + + LXQt Appearance Configuration + + + + + Icons Theme + + + + + LxQtThemeConfig + + + LXQt Theme + + + + + QObject + + + LXQt Appearance Configuration + + + + + Widget Style + + + + + Icons Theme + + + + + LXQt Theme + + + + + Font + + + + + Cursor + + + + + StyleConfig + + + Widget Style + + + + + Toolbar button style: + + + + + Only display the icon + + + + + Only display the text + + + + + The text appears beside the icon + + + + + The text appears under the icon + + + + + Default + + + + + Activate item on single click + + + + diff --git a/lxqt-config-appearance/translations/lxqt-config-appearance_ar.desktop b/lxqt-config-appearance/translations/lxqt-config-appearance_ar.desktop new file mode 100644 index 0000000..c2f28a2 --- /dev/null +++ b/lxqt-config-appearance/translations/lxqt-config-appearance_ar.desktop @@ -0,0 +1,4 @@ +# Translations +Comment[ar]=تهيئة مظهر سطح المكتب ريزر +GenericName[ar]=تهيئة مظهر ريزر +Name[ar]=تهيئة مظهر ريزر diff --git a/lxqt-config-appearance/translations/lxqt-config-appearance_ar.ts b/lxqt-config-appearance/translations/lxqt-config-appearance_ar.ts new file mode 100644 index 0000000..a748aa2 --- /dev/null +++ b/lxqt-config-appearance/translations/lxqt-config-appearance_ar.ts @@ -0,0 +1,232 @@ + + + + + FontsConfig + + + Font + + + + + Default font for user interface + + + + + Font name: + + + + + Style: + + + + + Point size: + + + + + Normal + + + + + Bold + + + + + Italic + + + + + Bold Italic + + + + + The following settings only affect newly started applications + + + + + Use antialias fonts + + + + + Font hinting style: + + + + + + None + + + + + Slight + + + + + Medium + + + + + Full + + + + + Font hinting + + + + + Resolution (DPI): + + + + + Autohint + + + + + Subpixel antialiasing: + + + + + RGB + + + + + BGR + + + + + VRGB + + + + + VBGR + + + + + IconThemeConfig + + + LXQt Appearance Configuration + تهيئة مظهر ريزر + + + + Icons Theme + نماذج اﻷيقونات + + + + LXQtThemeConfig + + LXQt Theme + واجهة ريزر المخصَّصة + + + + LxQtThemeConfig + + + LXQt Theme + واجهة ريزر المخصَّصة + + + + QObject + + + LXQt Appearance Configuration + تهيئة مظهر ريزر + + + + Widget Style + + + + + Icons Theme + نماذج اﻷيقونات + + + + LXQt Theme + واجهة ريزر المخصَّصة + + + + Font + + + + + Cursor + + + + + StyleConfig + + + Widget Style + + + + + Toolbar button style: + + + + + Only display the icon + + + + + Only display the text + + + + + The text appears beside the icon + + + + + The text appears under the icon + + + + + Default + + + + + Activate item on single click + + + + diff --git a/lxqt-config-appearance/translations/lxqt-config-appearance_cs.desktop b/lxqt-config-appearance/translations/lxqt-config-appearance_cs.desktop new file mode 100644 index 0000000..520ed07 --- /dev/null +++ b/lxqt-config-appearance/translations/lxqt-config-appearance_cs.desktop @@ -0,0 +1,4 @@ +# Translations +Comment[cs]=Nastavit vzhled pracovní plochy LxQt +GenericName[cs]=Nastavení vzhledu +Name[cs]=Nastavení vzhledu diff --git a/lxqt-config-appearance/translations/lxqt-config-appearance_cs.ts b/lxqt-config-appearance/translations/lxqt-config-appearance_cs.ts new file mode 100644 index 0000000..05e4034 --- /dev/null +++ b/lxqt-config-appearance/translations/lxqt-config-appearance_cs.ts @@ -0,0 +1,232 @@ + + + + + FontsConfig + + + Font + + + + + Default font for user interface + + + + + Font name: + + + + + Style: + + + + + Point size: + + + + + Normal + + + + + Bold + + + + + Italic + + + + + Bold Italic + + + + + The following settings only affect newly started applications + + + + + Use antialias fonts + + + + + Font hinting style: + + + + + + None + + + + + Slight + + + + + Medium + + + + + Full + + + + + Font hinting + + + + + Resolution (DPI): + + + + + Autohint + + + + + Subpixel antialiasing: + + + + + RGB + + + + + BGR + + + + + VRGB + + + + + VBGR + + + + + IconThemeConfig + + + LXQt Appearance Configuration + Nastavení vzhledu + + + + Icons Theme + Téma ikon + + + + LXQtThemeConfig + + LXQt Theme + Motiv LXQt + + + + LxQtThemeConfig + + + LXQt Theme + Motiv LXQt + + + + QObject + + + LXQt Appearance Configuration + Nastavení vzhledu + + + + Widget Style + + + + + Icons Theme + Téma ikon + + + + LXQt Theme + Motiv LXQt + + + + Font + + + + + Cursor + + + + + StyleConfig + + + Widget Style + + + + + Toolbar button style: + + + + + Only display the icon + + + + + Only display the text + + + + + The text appears beside the icon + + + + + The text appears under the icon + + + + + Default + + + + + Activate item on single click + + + + diff --git a/lxqt-config-appearance/translations/lxqt-config-appearance_cs_CZ.desktop b/lxqt-config-appearance/translations/lxqt-config-appearance_cs_CZ.desktop new file mode 100644 index 0000000..45646d0 --- /dev/null +++ b/lxqt-config-appearance/translations/lxqt-config-appearance_cs_CZ.desktop @@ -0,0 +1,4 @@ +# Translations +Comment[cs_CZ]=Nastavit vzhled pracovní plochy LXQt +GenericName[cs_CZ]=Nastavení vzhledu +Name[cs_CZ]=Nastavení vzhledu diff --git a/lxqt-config-appearance/translations/lxqt-config-appearance_cs_CZ.ts b/lxqt-config-appearance/translations/lxqt-config-appearance_cs_CZ.ts new file mode 100644 index 0000000..4848a25 --- /dev/null +++ b/lxqt-config-appearance/translations/lxqt-config-appearance_cs_CZ.ts @@ -0,0 +1,232 @@ + + + + + FontsConfig + + + Font + + + + + Default font for user interface + + + + + Font name: + + + + + Style: + + + + + Point size: + + + + + Normal + + + + + Bold + + + + + Italic + + + + + Bold Italic + + + + + The following settings only affect newly started applications + + + + + Use antialias fonts + + + + + Font hinting style: + + + + + + None + + + + + Slight + + + + + Medium + + + + + Full + + + + + Font hinting + + + + + Resolution (DPI): + + + + + Autohint + + + + + Subpixel antialiasing: + + + + + RGB + + + + + BGR + + + + + VRGB + + + + + VBGR + + + + + IconThemeConfig + + + LXQt Appearance Configuration + Nastavení vzhledu + + + + Icons Theme + Téma ikon + + + + LXQtThemeConfig + + LXQt Theme + Motiv LXQt + + + + LxQtThemeConfig + + + LXQt Theme + Motiv LXQt + + + + QObject + + + LXQt Appearance Configuration + Nastavení vzhledu + + + + Widget Style + + + + + Icons Theme + Téma ikon + + + + LXQt Theme + Motiv LXQt + + + + Font + + + + + Cursor + + + + + StyleConfig + + + Widget Style + + + + + Toolbar button style: + + + + + Only display the icon + + + + + Only display the text + + + + + The text appears beside the icon + + + + + The text appears under the icon + + + + + Default + + + + + Activate item on single click + + + + diff --git a/lxqt-config-appearance/translations/lxqt-config-appearance_da.desktop b/lxqt-config-appearance/translations/lxqt-config-appearance_da.desktop new file mode 100644 index 0000000..375f0b9 --- /dev/null +++ b/lxqt-config-appearance/translations/lxqt-config-appearance_da.desktop @@ -0,0 +1,4 @@ +# Translations +Comment[da]=Indstilling af LXQt udseende +GenericName[da]=Indstilling af LXQt Udseende +Name[da]=Indstilling af LXQt Udseende diff --git a/lxqt-config-appearance/translations/lxqt-config-appearance_da.ts b/lxqt-config-appearance/translations/lxqt-config-appearance_da.ts new file mode 100644 index 0000000..f1862c0 --- /dev/null +++ b/lxqt-config-appearance/translations/lxqt-config-appearance_da.ts @@ -0,0 +1,232 @@ + + + + + FontsConfig + + + Font + + + + + Default font for user interface + + + + + Font name: + + + + + Style: + + + + + Point size: + + + + + Normal + + + + + Bold + + + + + Italic + + + + + Bold Italic + + + + + The following settings only affect newly started applications + + + + + Use antialias fonts + + + + + Font hinting style: + + + + + + None + + + + + Slight + + + + + Medium + + + + + Full + + + + + Font hinting + + + + + Resolution (DPI): + + + + + Autohint + + + + + Subpixel antialiasing: + + + + + RGB + + + + + BGR + + + + + VRGB + + + + + VBGR + + + + + IconThemeConfig + + + LXQt Appearance Configuration + LXQt Indstillinger for Udseende + + + + Icons Theme + Ikontema + + + + LXQtThemeConfig + + LXQt Theme + LXQt Tema + + + + LxQtThemeConfig + + + LXQt Theme + LXQt Tema + + + + QObject + + + LXQt Appearance Configuration + LXQt Indstillinger for Udseende + + + + Widget Style + + + + + Icons Theme + Ikontema + + + + LXQt Theme + LXQt Tema + + + + Font + + + + + Cursor + + + + + StyleConfig + + + Widget Style + + + + + Toolbar button style: + + + + + Only display the icon + + + + + Only display the text + + + + + The text appears beside the icon + + + + + The text appears under the icon + + + + + Default + + + + + Activate item on single click + + + + diff --git a/lxqt-config-appearance/translations/lxqt-config-appearance_da_DK.desktop b/lxqt-config-appearance/translations/lxqt-config-appearance_da_DK.desktop new file mode 100644 index 0000000..cf332b5 --- /dev/null +++ b/lxqt-config-appearance/translations/lxqt-config-appearance_da_DK.desktop @@ -0,0 +1,4 @@ +# Translations +Comment[da_DK]=Indstil udseende på LXQt skrivebord +GenericName[da_DK]=Indstilling af LXQt Udseende +Name[da_DK]=Indstilling af LXQt Udseende diff --git a/lxqt-config-appearance/translations/lxqt-config-appearance_da_DK.ts b/lxqt-config-appearance/translations/lxqt-config-appearance_da_DK.ts new file mode 100644 index 0000000..b36803e --- /dev/null +++ b/lxqt-config-appearance/translations/lxqt-config-appearance_da_DK.ts @@ -0,0 +1,232 @@ + + + + + FontsConfig + + + Font + + + + + Default font for user interface + + + + + Font name: + + + + + Style: + + + + + Point size: + + + + + Normal + + + + + Bold + + + + + Italic + + + + + Bold Italic + + + + + The following settings only affect newly started applications + + + + + Use antialias fonts + + + + + Font hinting style: + + + + + + None + + + + + Slight + + + + + Medium + + + + + Full + + + + + Font hinting + + + + + Resolution (DPI): + + + + + Autohint + + + + + Subpixel antialiasing: + + + + + RGB + + + + + BGR + + + + + VRGB + + + + + VBGR + + + + + IconThemeConfig + + + LXQt Appearance Configuration + LXQt Indstillinger for Udseende + + + + Icons Theme + Ikontema + + + + LXQtThemeConfig + + LXQt Theme + LXQt Tema + + + + LxQtThemeConfig + + + LXQt Theme + LXQt Tema + + + + QObject + + + LXQt Appearance Configuration + LXQt Indstillinger for Udseende + + + + Widget Style + + + + + Icons Theme + Ikontema + + + + LXQt Theme + LXQt Tema + + + + Font + + + + + Cursor + + + + + StyleConfig + + + Widget Style + + + + + Toolbar button style: + + + + + Only display the icon + + + + + Only display the text + + + + + The text appears beside the icon + + + + + The text appears under the icon + + + + + Default + + + + + Activate item on single click + + + + diff --git a/lxqt-config-appearance/translations/lxqt-config-appearance_de.desktop b/lxqt-config-appearance/translations/lxqt-config-appearance_de.desktop new file mode 100644 index 0000000..38fef45 --- /dev/null +++ b/lxqt-config-appearance/translations/lxqt-config-appearance_de.desktop @@ -0,0 +1,4 @@ +# Translations +Comment[de]=Einstellungen zum Aussehen der LXQt Arbeitsfläche +GenericName[de]=LXQt Erscheinungsbild Einstellungen +Name[de]=LXQt Erscheinungsbild Einstellungen diff --git a/lxqt-config-appearance/translations/lxqt-config-appearance_de.ts b/lxqt-config-appearance/translations/lxqt-config-appearance_de.ts new file mode 100644 index 0000000..ce30a9d --- /dev/null +++ b/lxqt-config-appearance/translations/lxqt-config-appearance_de.ts @@ -0,0 +1,225 @@ + + + + + FontsConfig + + + Font + Schriftart + + + + Default font for user interface + Standardschriftart der Bedienoberfläche + + + + Font name: + Name: + + + + Style: + Stil: + + + + Point size: + Punktgröße: + + + + Normal + Normal + + + + Bold + Fett + + + + Italic + Kursiv + + + + Bold Italic + Fett und kursiv + + + + The following settings only affect newly started applications + Folgende Einstellungen wirken nur auf neu gestartete Programme + + + + Use antialias fonts + Kantenglättung bei Schriften verwenden + + + + Font hinting style: + Hinting-Stil: + + + + + None + Keine + + + + Slight + Leicht + + + + Medium + Mittel + + + + Full + Vollständig + + + + Font hinting + Schrift-Hinting + + + + Resolution (DPI): + Auflösung (DPI): + + + + Autohint + Autohint + + + + Subpixel antialiasing: + Subpixel-Anordnung: + + + + RGB + RGB + + + + BGR + BGR + + + + VRGB + VRGB + + + + VBGR + VBGR + + + + IconThemeConfig + + + LXQt Appearance Configuration + LXQt Erscheinungsbild-Konfiguration + + + + Icons Theme + Symboldesign + + + + LxQtThemeConfig + + + LXQt Theme + LXQt-Design + + + + QObject + + + LXQt Appearance Configuration + LXQt Erscheinungsbild-Konfiguration + + + + Widget Style + Stil der Bedienelemente + + + + Icons Theme + Symboldesign + + + + LXQt Theme + LXQt-Design + + + + Font + Schriftart + + + + Cursor + Mauszeiger + + + + StyleConfig + + + Widget Style + Stil der Bedienelemente + + + + Toolbar button style: + Werkzeugleistenstil: + + + + Only display the icon + Nur Symbol + + + + Only display the text + Nur Text + + + + The text appears beside the icon + Text neben dem Symbol + + + + The text appears under the icon + Text unterhalb des Symbols + + + + Default + Default + + + + Activate item on single click + Einfacher Klick aktiviert Elemente + + + diff --git a/lxqt-config-appearance/translations/lxqt-config-appearance_el_GR.desktop b/lxqt-config-appearance/translations/lxqt-config-appearance_el_GR.desktop new file mode 100644 index 0000000..850a708 --- /dev/null +++ b/lxqt-config-appearance/translations/lxqt-config-appearance_el_GR.desktop @@ -0,0 +1,4 @@ +# Translations +Comment[el_GR]=Διαμόρφωση εμφάνισης της επιφάνειας εργασίας LXQt +GenericName[el_GR]=Διαμόρφωση εμφάνισης LXQt +Name[el_GR]=Διαμόρφωση εμφάνισης LXQt diff --git a/lxqt-config-appearance/translations/lxqt-config-appearance_el_GR.ts b/lxqt-config-appearance/translations/lxqt-config-appearance_el_GR.ts new file mode 100644 index 0000000..7d571bd --- /dev/null +++ b/lxqt-config-appearance/translations/lxqt-config-appearance_el_GR.ts @@ -0,0 +1,232 @@ + + + + + FontsConfig + + + Font + + + + + Default font for user interface + + + + + Font name: + + + + + Style: + + + + + Point size: + + + + + Normal + + + + + Bold + + + + + Italic + + + + + Bold Italic + + + + + The following settings only affect newly started applications + + + + + Use antialias fonts + + + + + Font hinting style: + + + + + + None + + + + + Slight + + + + + Medium + + + + + Full + + + + + Font hinting + + + + + Resolution (DPI): + + + + + Autohint + + + + + Subpixel antialiasing: + + + + + RGB + + + + + BGR + + + + + VRGB + + + + + VBGR + + + + + IconThemeConfig + + + LXQt Appearance Configuration + Διαμόρφωση εμφάνισης LXQt + + + + Icons Theme + Θέμα εικονιδίων + + + + LXQtThemeConfig + + LXQt Theme + Θέμα LXQt + + + + LxQtThemeConfig + + + LXQt Theme + Θέμα LXQt + + + + QObject + + + LXQt Appearance Configuration + Διαμόρφωση εμφάνισης LXQt + + + + Widget Style + + + + + Icons Theme + Θέμα εικονιδίων + + + + LXQt Theme + Θέμα LXQt + + + + Font + + + + + Cursor + + + + + StyleConfig + + + Widget Style + + + + + Toolbar button style: + + + + + Only display the icon + + + + + Only display the text + + + + + The text appears beside the icon + + + + + The text appears under the icon + + + + + Default + + + + + Activate item on single click + + + + diff --git a/lxqt-config-appearance/translations/lxqt-config-appearance_eo.desktop b/lxqt-config-appearance/translations/lxqt-config-appearance_eo.desktop new file mode 100644 index 0000000..9e90feb --- /dev/null +++ b/lxqt-config-appearance/translations/lxqt-config-appearance_eo.desktop @@ -0,0 +1,4 @@ +# Translations +Comment[eo]=Agordi aperon de LXQt-labortablo +GenericName[eo]=Agordoj de apero de LXQt +Name[eo]=Agordoj de apero de LXQt diff --git a/lxqt-config-appearance/translations/lxqt-config-appearance_eo.ts b/lxqt-config-appearance/translations/lxqt-config-appearance_eo.ts new file mode 100644 index 0000000..d5e842c --- /dev/null +++ b/lxqt-config-appearance/translations/lxqt-config-appearance_eo.ts @@ -0,0 +1,232 @@ + + + + + FontsConfig + + + Font + + + + + Default font for user interface + + + + + Font name: + + + + + Style: + + + + + Point size: + + + + + Normal + + + + + Bold + + + + + Italic + + + + + Bold Italic + + + + + The following settings only affect newly started applications + + + + + Use antialias fonts + + + + + Font hinting style: + + + + + + None + + + + + Slight + + + + + Medium + + + + + Full + + + + + Font hinting + + + + + Resolution (DPI): + + + + + Autohint + + + + + Subpixel antialiasing: + + + + + RGB + + + + + BGR + + + + + VRGB + + + + + VBGR + + + + + IconThemeConfig + + + LXQt Appearance Configuration + Agordoj de apero de LXQto + + + + Icons Theme + Etoso de piktogramoj + + + + LXQtThemeConfig + + LXQt Theme + Etoso de LXQt + + + + LxQtThemeConfig + + + LXQt Theme + Etoso de LXQt + + + + QObject + + + LXQt Appearance Configuration + Agordoj de apero de LXQto + + + + Widget Style + + + + + Icons Theme + Etoso de piktogramoj + + + + LXQt Theme + Etoso de LXQt + + + + Font + + + + + Cursor + + + + + StyleConfig + + + Widget Style + + + + + Toolbar button style: + + + + + Only display the icon + + + + + Only display the text + + + + + The text appears beside the icon + + + + + The text appears under the icon + + + + + Default + + + + + Activate item on single click + + + + diff --git a/lxqt-config-appearance/translations/lxqt-config-appearance_es.desktop b/lxqt-config-appearance/translations/lxqt-config-appearance_es.desktop new file mode 100644 index 0000000..a45f295 --- /dev/null +++ b/lxqt-config-appearance/translations/lxqt-config-appearance_es.desktop @@ -0,0 +1,4 @@ +# Translations +Comment[es]=Configura el aspecto del escritorio LXQt +GenericName[es]=Configuración de Aspecto LXQt +Name[es]=Configuración de Aspecto LXQt diff --git a/lxqt-config-appearance/translations/lxqt-config-appearance_es.ts b/lxqt-config-appearance/translations/lxqt-config-appearance_es.ts new file mode 100644 index 0000000..9be60dd --- /dev/null +++ b/lxqt-config-appearance/translations/lxqt-config-appearance_es.ts @@ -0,0 +1,232 @@ + + + + + FontsConfig + + + Font + + + + + Default font for user interface + + + + + Font name: + + + + + Style: + + + + + Point size: + + + + + Normal + + + + + Bold + + + + + Italic + + + + + Bold Italic + + + + + The following settings only affect newly started applications + + + + + Use antialias fonts + + + + + Font hinting style: + + + + + + None + + + + + Slight + + + + + Medium + + + + + Full + + + + + Font hinting + + + + + Resolution (DPI): + + + + + Autohint + + + + + Subpixel antialiasing: + + + + + RGB + + + + + BGR + + + + + VRGB + + + + + VBGR + + + + + IconThemeConfig + + + LXQt Appearance Configuration + Configuración de apariencia de LXQt + + + + Icons Theme + Tema de iconos + + + + LXQtThemeConfig + + LXQt Theme + Tema de LXQt + + + + LxQtThemeConfig + + + LXQt Theme + Tema de LXQt + + + + QObject + + + LXQt Appearance Configuration + Configuración de apariencia de LXQt + + + + Widget Style + + + + + Icons Theme + Tema de iconos + + + + LXQt Theme + Tema de LXQt + + + + Font + + + + + Cursor + + + + + StyleConfig + + + Widget Style + + + + + Toolbar button style: + + + + + Only display the icon + + + + + Only display the text + + + + + The text appears beside the icon + + + + + The text appears under the icon + + + + + Default + + + + + Activate item on single click + + + + diff --git a/lxqt-config-appearance/translations/lxqt-config-appearance_es_VE.desktop b/lxqt-config-appearance/translations/lxqt-config-appearance_es_VE.desktop new file mode 100644 index 0000000..bfb3e11 --- /dev/null +++ b/lxqt-config-appearance/translations/lxqt-config-appearance_es_VE.desktop @@ -0,0 +1,4 @@ +# Translations +Comment[es_VE]=Configurar apariencia del escritorio LXQt +GenericName[es_VE]=Configuración de apariencia de LXQt +Name[es_VE]=Configuración de apariencia de LXQt diff --git a/lxqt-config-appearance/translations/lxqt-config-appearance_es_VE.ts b/lxqt-config-appearance/translations/lxqt-config-appearance_es_VE.ts new file mode 100644 index 0000000..8418038 --- /dev/null +++ b/lxqt-config-appearance/translations/lxqt-config-appearance_es_VE.ts @@ -0,0 +1,232 @@ + + + + + FontsConfig + + + Font + + + + + Default font for user interface + + + + + Font name: + + + + + Style: + + + + + Point size: + + + + + Normal + + + + + Bold + + + + + Italic + + + + + Bold Italic + + + + + The following settings only affect newly started applications + + + + + Use antialias fonts + + + + + Font hinting style: + + + + + + None + + + + + Slight + + + + + Medium + + + + + Full + + + + + Font hinting + + + + + Resolution (DPI): + + + + + Autohint + + + + + Subpixel antialiasing: + + + + + RGB + + + + + BGR + + + + + VRGB + + + + + VBGR + + + + + IconThemeConfig + + + LXQt Appearance Configuration + Configuración de apariencia de LXQt + + + + Icons Theme + Tema de iconos + + + + LXQtThemeConfig + + LXQt Theme + Tema LXQt + + + + LxQtThemeConfig + + + LXQt Theme + Tema LXQt + + + + QObject + + + LXQt Appearance Configuration + Configuración de apariencia de LXQt + + + + Widget Style + + + + + Icons Theme + Tema de iconos + + + + LXQt Theme + Tema LXQt + + + + Font + + + + + Cursor + + + + + StyleConfig + + + Widget Style + + + + + Toolbar button style: + + + + + Only display the icon + + + + + Only display the text + + + + + The text appears beside the icon + + + + + The text appears under the icon + + + + + Default + + + + + Activate item on single click + + + + diff --git a/lxqt-config-appearance/translations/lxqt-config-appearance_eu.desktop b/lxqt-config-appearance/translations/lxqt-config-appearance_eu.desktop new file mode 100644 index 0000000..d630fb7 --- /dev/null +++ b/lxqt-config-appearance/translations/lxqt-config-appearance_eu.desktop @@ -0,0 +1,4 @@ +# Translations +Comment[eu]=Konfiguratu LXQt mahaigainaren itxura +GenericName[eu]=LXQt itxuraren konfigurazioa +Name[eu]=LXQt itxuraren konfigurazioa diff --git a/lxqt-config-appearance/translations/lxqt-config-appearance_eu.ts b/lxqt-config-appearance/translations/lxqt-config-appearance_eu.ts new file mode 100644 index 0000000..1401c10 --- /dev/null +++ b/lxqt-config-appearance/translations/lxqt-config-appearance_eu.ts @@ -0,0 +1,232 @@ + + + + + FontsConfig + + + Font + + + + + Default font for user interface + + + + + Font name: + + + + + Style: + + + + + Point size: + + + + + Normal + + + + + Bold + + + + + Italic + + + + + Bold Italic + + + + + The following settings only affect newly started applications + + + + + Use antialias fonts + + + + + Font hinting style: + + + + + + None + + + + + Slight + + + + + Medium + + + + + Full + + + + + Font hinting + + + + + Resolution (DPI): + + + + + Autohint + + + + + Subpixel antialiasing: + + + + + RGB + + + + + BGR + + + + + VRGB + + + + + VBGR + + + + + IconThemeConfig + + + LXQt Appearance Configuration + LXQt itxuraren konfigurazioa + + + + Icons Theme + Ikonoen gaia + + + + LXQtThemeConfig + + LXQt Theme + LXQt gaia + + + + LxQtThemeConfig + + + LXQt Theme + LXQt gaia + + + + QObject + + + LXQt Appearance Configuration + LXQt itxuraren konfigurazioa + + + + Widget Style + + + + + Icons Theme + Ikonoen gaia + + + + LXQt Theme + LXQt gaia + + + + Font + + + + + Cursor + + + + + StyleConfig + + + Widget Style + + + + + Toolbar button style: + + + + + Only display the icon + + + + + Only display the text + + + + + The text appears beside the icon + + + + + The text appears under the icon + + + + + Default + + + + + Activate item on single click + + + + diff --git a/lxqt-config-appearance/translations/lxqt-config-appearance_fi.desktop b/lxqt-config-appearance/translations/lxqt-config-appearance_fi.desktop new file mode 100644 index 0000000..f332a5b --- /dev/null +++ b/lxqt-config-appearance/translations/lxqt-config-appearance_fi.desktop @@ -0,0 +1,4 @@ +# Translations +Comment[fi]=Hallitse LXQt-työpöydän ulkoasua +GenericName[fi]=LXQtin ulkoasun hallinta +Name[fi]=LXQtin ulkoasun hallinta diff --git a/lxqt-config-appearance/translations/lxqt-config-appearance_fi.ts b/lxqt-config-appearance/translations/lxqt-config-appearance_fi.ts new file mode 100644 index 0000000..48785aa --- /dev/null +++ b/lxqt-config-appearance/translations/lxqt-config-appearance_fi.ts @@ -0,0 +1,232 @@ + + + + + FontsConfig + + + Font + + + + + Default font for user interface + + + + + Font name: + + + + + Style: + + + + + Point size: + + + + + Normal + + + + + Bold + + + + + Italic + + + + + Bold Italic + + + + + The following settings only affect newly started applications + + + + + Use antialias fonts + + + + + Font hinting style: + + + + + + None + + + + + Slight + + + + + Medium + + + + + Full + + + + + Font hinting + + + + + Resolution (DPI): + + + + + Autohint + + + + + Subpixel antialiasing: + + + + + RGB + + + + + BGR + + + + + VRGB + + + + + VBGR + + + + + IconThemeConfig + + + LXQt Appearance Configuration + LXQtin ulkoasun hallinta + + + + Icons Theme + Kuvaketeema + + + + LXQtThemeConfig + + LXQt Theme + LXQt-teema + + + + LxQtThemeConfig + + + LXQt Theme + LXQt-teema + + + + QObject + + + LXQt Appearance Configuration + LXQtin ulkoasun hallinta + + + + Widget Style + + + + + Icons Theme + Kuvaketeema + + + + LXQt Theme + LXQt-teema + + + + Font + + + + + Cursor + + + + + StyleConfig + + + Widget Style + + + + + Toolbar button style: + + + + + Only display the icon + + + + + Only display the text + + + + + The text appears beside the icon + + + + + The text appears under the icon + + + + + Default + + + + + Activate item on single click + + + + diff --git a/lxqt-config-appearance/translations/lxqt-config-appearance_fr_FR.desktop b/lxqt-config-appearance/translations/lxqt-config-appearance_fr_FR.desktop new file mode 100644 index 0000000..ad84542 --- /dev/null +++ b/lxqt-config-appearance/translations/lxqt-config-appearance_fr_FR.desktop @@ -0,0 +1,4 @@ +# Translations +Comment[fr_FR]=Configurer l'apparence du bureau LXQt +GenericName[fr_FR]=Configuration de l'apparence de LXQt +Name[fr_FR]=Configuration de l'apparence de LXQt diff --git a/lxqt-config-appearance/translations/lxqt-config-appearance_fr_FR.ts b/lxqt-config-appearance/translations/lxqt-config-appearance_fr_FR.ts new file mode 100644 index 0000000..435ccb9 --- /dev/null +++ b/lxqt-config-appearance/translations/lxqt-config-appearance_fr_FR.ts @@ -0,0 +1,232 @@ + + + + + FontsConfig + + + Font + + + + + Default font for user interface + + + + + Font name: + + + + + Style: + + + + + Point size: + + + + + Normal + + + + + Bold + + + + + Italic + + + + + Bold Italic + + + + + The following settings only affect newly started applications + + + + + Use antialias fonts + + + + + Font hinting style: + + + + + + None + + + + + Slight + + + + + Medium + + + + + Full + + + + + Font hinting + + + + + Resolution (DPI): + + + + + Autohint + + + + + Subpixel antialiasing: + + + + + RGB + + + + + BGR + + + + + VRGB + + + + + VBGR + + + + + IconThemeConfig + + + LXQt Appearance Configuration + Configuration de l'apparence de LXQt + + + + Icons Theme + Thème d'icones + + + + LXQtThemeConfig + + LXQt Theme + Thème de LXQt + + + + LxQtThemeConfig + + + LXQt Theme + Thème de LXQt + + + + QObject + + + LXQt Appearance Configuration + Configuration de l'apparence de LXQt + + + + Widget Style + + + + + Icons Theme + Thème d'icones + + + + LXQt Theme + Thème de LXQt + + + + Font + + + + + Cursor + + + + + StyleConfig + + + Widget Style + + + + + Toolbar button style: + + + + + Only display the icon + + + + + Only display the text + + + + + The text appears beside the icon + + + + + The text appears under the icon + + + + + Default + + + + + Activate item on single click + + + + diff --git a/lxqt-config-appearance/translations/lxqt-config-appearance_hu.desktop b/lxqt-config-appearance/translations/lxqt-config-appearance_hu.desktop new file mode 100644 index 0000000..c3f22db --- /dev/null +++ b/lxqt-config-appearance/translations/lxqt-config-appearance_hu.desktop @@ -0,0 +1,4 @@ +# Translations +Comment[hu]=A LXQt asztal megjelenésének beállítása +GenericName[hu]=LXQt megjelenésbeállító +Name[hu]=LXQt megjelenésbeállító diff --git a/lxqt-config-appearance/translations/lxqt-config-appearance_hu.ts b/lxqt-config-appearance/translations/lxqt-config-appearance_hu.ts new file mode 100644 index 0000000..ecba8ed --- /dev/null +++ b/lxqt-config-appearance/translations/lxqt-config-appearance_hu.ts @@ -0,0 +1,232 @@ + + + + + FontsConfig + + + Font + + + + + Default font for user interface + + + + + Font name: + + + + + Style: + + + + + Point size: + + + + + Normal + + + + + Bold + + + + + Italic + + + + + Bold Italic + + + + + The following settings only affect newly started applications + + + + + Use antialias fonts + + + + + Font hinting style: + + + + + + None + + + + + Slight + + + + + Medium + + + + + Full + + + + + Font hinting + + + + + Resolution (DPI): + + + + + Autohint + + + + + Subpixel antialiasing: + + + + + RGB + + + + + BGR + + + + + VRGB + + + + + VBGR + + + + + IconThemeConfig + + + LXQt Appearance Configuration + Alkalmazásmenü + + + + Icons Theme + Ikontéma + + + + LXQtThemeConfig + + LXQt Theme + LXQt téma + + + + LxQtThemeConfig + + + LXQt Theme + LXQt téma + + + + QObject + + + LXQt Appearance Configuration + Alkalmazásmenü + + + + Widget Style + + + + + Icons Theme + Ikontéma + + + + LXQt Theme + LXQt téma + + + + Font + + + + + Cursor + + + + + StyleConfig + + + Widget Style + + + + + Toolbar button style: + + + + + Only display the icon + + + + + Only display the text + + + + + The text appears beside the icon + + + + + The text appears under the icon + + + + + Default + + + + + Activate item on single click + + + + diff --git a/lxqt-config-appearance/translations/lxqt-config-appearance_hu_HU.ts b/lxqt-config-appearance/translations/lxqt-config-appearance_hu_HU.ts new file mode 100644 index 0000000..e99b098 --- /dev/null +++ b/lxqt-config-appearance/translations/lxqt-config-appearance_hu_HU.ts @@ -0,0 +1,236 @@ + + + + + FontsConfig + + + Font + + + + + Default font for user interface + + + + + Font name: + + + + + Style: + + + + + Point size: + + + + + Normal + + + + + Bold + + + + + Italic + + + + + Bold Italic + + + + + The following settings only affect newly started applications + + + + + Use antialias fonts + + + + + Font hinting style: + + + + + + None + + + + + Slight + + + + + Medium + + + + + Full + + + + + Font hinting + + + + + Resolution (DPI): + + + + + Autohint + + + + + Subpixel antialiasing: + + + + + RGB + + + + + BGR + + + + + VRGB + + + + + VBGR + + + + + IconThemeConfig + + + LXQt Appearance Configuration + LXQt megjelenésbeállító + + + + Icons Theme + Ikontémák + + + + LxQtThemeConfig + + + LXQt Theme + + + + + MainWindow + + LXQt Appearance Configuration + LXQt megjelenésbeállító + + + Icons Theme + Ikontémák + + + + QObject + + + LXQt Appearance Configuration + LXQt megjelenésbeállító + + + + Widget Style + + + + + Icons Theme + Ikontémák + + + + LXQt Theme + + + + + Font + + + + + Cursor + + + + + StyleConfig + + + Widget Style + + + + + Toolbar button style: + + + + + Only display the icon + + + + + Only display the text + + + + + The text appears beside the icon + + + + + The text appears under the icon + + + + + Default + + + + + Activate item on single click + + + + diff --git a/lxqt-config-appearance/translations/lxqt-config-appearance_ia.desktop b/lxqt-config-appearance/translations/lxqt-config-appearance_ia.desktop new file mode 100644 index 0000000..26b0d99 --- /dev/null +++ b/lxqt-config-appearance/translations/lxqt-config-appearance_ia.desktop @@ -0,0 +1 @@ +# Translations diff --git a/lxqt-config-appearance/translations/lxqt-config-appearance_ia.ts b/lxqt-config-appearance/translations/lxqt-config-appearance_ia.ts new file mode 100644 index 0000000..e2cccf8 --- /dev/null +++ b/lxqt-config-appearance/translations/lxqt-config-appearance_ia.ts @@ -0,0 +1,225 @@ + + + + + FontsConfig + + + Font + + + + + Default font for user interface + + + + + Font name: + + + + + Style: + + + + + Point size: + + + + + Normal + + + + + Bold + + + + + Italic + + + + + Bold Italic + + + + + The following settings only affect newly started applications + + + + + Use antialias fonts + + + + + Font hinting style: + + + + + + None + + + + + Slight + + + + + Medium + + + + + Full + + + + + Font hinting + + + + + Resolution (DPI): + + + + + Autohint + + + + + Subpixel antialiasing: + + + + + RGB + + + + + BGR + + + + + VRGB + + + + + VBGR + + + + + IconThemeConfig + + + LXQt Appearance Configuration + + + + + Icons Theme + + + + + LxQtThemeConfig + + + LXQt Theme + + + + + QObject + + + LXQt Appearance Configuration + + + + + Widget Style + + + + + Icons Theme + + + + + LXQt Theme + + + + + Font + + + + + Cursor + + + + + StyleConfig + + + Widget Style + + + + + Toolbar button style: + + + + + Only display the icon + + + + + Only display the text + + + + + The text appears beside the icon + + + + + The text appears under the icon + + + + + Default + + + + + Activate item on single click + + + + diff --git a/lxqt-config-appearance/translations/lxqt-config-appearance_id_ID.desktop b/lxqt-config-appearance/translations/lxqt-config-appearance_id_ID.desktop new file mode 100644 index 0000000..26b0d99 --- /dev/null +++ b/lxqt-config-appearance/translations/lxqt-config-appearance_id_ID.desktop @@ -0,0 +1 @@ +# Translations diff --git a/lxqt-config-appearance/translations/lxqt-config-appearance_id_ID.ts b/lxqt-config-appearance/translations/lxqt-config-appearance_id_ID.ts new file mode 100644 index 0000000..d537dec --- /dev/null +++ b/lxqt-config-appearance/translations/lxqt-config-appearance_id_ID.ts @@ -0,0 +1,225 @@ + + + + + FontsConfig + + + Font + + + + + Default font for user interface + + + + + Font name: + + + + + Style: + + + + + Point size: + + + + + Normal + + + + + Bold + + + + + Italic + + + + + Bold Italic + + + + + The following settings only affect newly started applications + + + + + Use antialias fonts + + + + + Font hinting style: + + + + + + None + + + + + Slight + + + + + Medium + + + + + Full + + + + + Font hinting + + + + + Resolution (DPI): + + + + + Autohint + + + + + Subpixel antialiasing: + + + + + RGB + + + + + BGR + + + + + VRGB + + + + + VBGR + + + + + IconThemeConfig + + + LXQt Appearance Configuration + Konfigurasi Penampilan LXQt + + + + Icons Theme + Tema Ikon + + + + LxQtThemeConfig + + + LXQt Theme + + + + + QObject + + + LXQt Appearance Configuration + Konfigurasi Penampilan LXQt + + + + Widget Style + + + + + Icons Theme + Tema Ikon + + + + LXQt Theme + + + + + Font + + + + + Cursor + + + + + StyleConfig + + + Widget Style + + + + + Toolbar button style: + + + + + Only display the icon + + + + + Only display the text + + + + + The text appears beside the icon + + + + + The text appears under the icon + + + + + Default + + + + + Activate item on single click + + + + diff --git a/lxqt-config-appearance/translations/lxqt-config-appearance_it.desktop b/lxqt-config-appearance/translations/lxqt-config-appearance_it.desktop new file mode 100644 index 0000000..4e35f23 --- /dev/null +++ b/lxqt-config-appearance/translations/lxqt-config-appearance_it.desktop @@ -0,0 +1,6 @@ +# Translations +GenericName[it]=Aspetto +Name[it]=Aspetto +Comment[it]=Configura l'aspetto di LXQt + + diff --git a/lxqt-config-appearance/translations/lxqt-config-appearance_it.ts b/lxqt-config-appearance/translations/lxqt-config-appearance_it.ts new file mode 100644 index 0000000..8f39285 --- /dev/null +++ b/lxqt-config-appearance/translations/lxqt-config-appearance_it.ts @@ -0,0 +1,226 @@ + + + + + FontsConfig + + + Font + Caratteri + + + + Default font for user interface + Carattere generale + + + + Font name: + Carattere: + + + + Style: + Stile: + + + + Point size: + Dimensione: + + + + Normal + Normale + + + + Bold + Grassetto + + + + Italic + Corsivo + + + + Bold Italic + Grassetto corsivo + + + + The following settings only affect newly started applications + Le impostazioni riguardano solo le applicazioni avviate nuovamente + + + + Use antialias fonts + Utilizza anti-aliasing per i caratteri + + + + Font hinting style: + Stile di hinting + + + + + None + Nessuno + + + + Slight + Leggero + + + + Medium + Medio + + + + Full + Forte + + + + Font hinting + Hinting caratteri + + + + Resolution (DPI): + Resoluzione (DPI): + + + + Autohint + Hinting automatico + + + + Subpixel antialiasing: + no idea how to translate that + + + + + RGB + + + + + BGR + + + + + VRGB + + + + + VBGR + + + + + IconThemeConfig + + + LXQt Appearance Configuration + Centro di Configurazione LXQt + + + + Icons Theme + Temi delle icone + + + + LxQtThemeConfig + + + LXQt Theme + Tema di LXQt + + + + QObject + + + LXQt Appearance Configuration + Centro di Configurazione LXQt + + + + Widget Style + Stile degli elementi + + + + Icons Theme + Tema delle icone + + + + LXQt Theme + Tema di LXQt + + + + Font + Caratteri + + + + Cursor + Cursore + + + + StyleConfig + + + Widget Style + Stile degli elementi + + + + Toolbar button style: + Stile della barra delle applicazioni: + + + + Only display the icon + Mostra solo icone + + + + Only display the text + Mostra solo testo + + + + The text appears beside the icon + Testo accanto le icone + + + + The text appears under the icon + Testo sotto le icone + + + + Default + + + + + Activate item on single click + Attiva elementi con clic singolo + + + diff --git a/lxqt-config-appearance/translations/lxqt-config-appearance_it_IT.desktop b/lxqt-config-appearance/translations/lxqt-config-appearance_it_IT.desktop new file mode 100644 index 0000000..6f62c55 --- /dev/null +++ b/lxqt-config-appearance/translations/lxqt-config-appearance_it_IT.desktop @@ -0,0 +1,4 @@ +# Translations +Comment[it_IT]=Configura l'aspetto del desktop LXQt +GenericName[it_IT]=Configurazione dell'aspetto di LXQt +Name[it_IT]=Configurazione dell'aspetto di LXQt diff --git a/lxqt-config-appearance/translations/lxqt-config-appearance_it_IT.ts b/lxqt-config-appearance/translations/lxqt-config-appearance_it_IT.ts new file mode 100644 index 0000000..8f39285 --- /dev/null +++ b/lxqt-config-appearance/translations/lxqt-config-appearance_it_IT.ts @@ -0,0 +1,226 @@ + + + + + FontsConfig + + + Font + Caratteri + + + + Default font for user interface + Carattere generale + + + + Font name: + Carattere: + + + + Style: + Stile: + + + + Point size: + Dimensione: + + + + Normal + Normale + + + + Bold + Grassetto + + + + Italic + Corsivo + + + + Bold Italic + Grassetto corsivo + + + + The following settings only affect newly started applications + Le impostazioni riguardano solo le applicazioni avviate nuovamente + + + + Use antialias fonts + Utilizza anti-aliasing per i caratteri + + + + Font hinting style: + Stile di hinting + + + + + None + Nessuno + + + + Slight + Leggero + + + + Medium + Medio + + + + Full + Forte + + + + Font hinting + Hinting caratteri + + + + Resolution (DPI): + Resoluzione (DPI): + + + + Autohint + Hinting automatico + + + + Subpixel antialiasing: + no idea how to translate that + + + + + RGB + + + + + BGR + + + + + VRGB + + + + + VBGR + + + + + IconThemeConfig + + + LXQt Appearance Configuration + Centro di Configurazione LXQt + + + + Icons Theme + Temi delle icone + + + + LxQtThemeConfig + + + LXQt Theme + Tema di LXQt + + + + QObject + + + LXQt Appearance Configuration + Centro di Configurazione LXQt + + + + Widget Style + Stile degli elementi + + + + Icons Theme + Tema delle icone + + + + LXQt Theme + Tema di LXQt + + + + Font + Caratteri + + + + Cursor + Cursore + + + + StyleConfig + + + Widget Style + Stile degli elementi + + + + Toolbar button style: + Stile della barra delle applicazioni: + + + + Only display the icon + Mostra solo icone + + + + Only display the text + Mostra solo testo + + + + The text appears beside the icon + Testo accanto le icone + + + + The text appears under the icon + Testo sotto le icone + + + + Default + + + + + Activate item on single click + Attiva elementi con clic singolo + + + diff --git a/lxqt-config-appearance/translations/lxqt-config-appearance_ja.desktop b/lxqt-config-appearance/translations/lxqt-config-appearance_ja.desktop new file mode 100644 index 0000000..1209541 --- /dev/null +++ b/lxqt-config-appearance/translations/lxqt-config-appearance_ja.desktop @@ -0,0 +1,4 @@ +# Translations +Comment[ja]=LXQtデスクトップの外観を設定 +GenericName[ja]=LXQt外観の設定 +Name[ja]=LXQt外観の設定 diff --git a/lxqt-config-appearance/translations/lxqt-config-appearance_ja.ts b/lxqt-config-appearance/translations/lxqt-config-appearance_ja.ts new file mode 100644 index 0000000..cab3a0b --- /dev/null +++ b/lxqt-config-appearance/translations/lxqt-config-appearance_ja.ts @@ -0,0 +1,225 @@ + + + + + FontsConfig + + + Font + フォント + + + + Default font for user interface + ユーザーインターフェースのデフォルトのフォント + + + + Font name: + フォント名: + + + + Style: + スタイル: + + + + Point size: + ポイントサイズ: + + + + Normal + ノーマル + + + + Bold + 太字 + + + + Italic + 斜体 + + + + Bold Italic + 太字・斜体 + + + + The following settings only affect newly started applications + 以下の設定は、これから新たに実行されたアプリケーションに適用されます + + + + Use antialias fonts + アンチエイリアスされたフォントを用いる + + + + Font hinting style: + フォントのヒンティング形式: + + + + + None + なし + + + + Slight + 軽微 + + + + Medium + 中間 + + + + Full + 完全 + + + + Font hinting + フォントのヒンティング + + + + Resolution (DPI): + 解像度 (DPI): + + + + Autohint + 自動ヒンティング + + + + Subpixel antialiasing: + サブピクセルアンチエイリアス: + + + + RGB + RGB + + + + BGR + BGR + + + + VRGB + VRGB + + + + VBGR + VBGR + + + + IconThemeConfig + + + LXQt Appearance Configuration + LXQt外観の設定 + + + + Icons Theme + アイコンテーマ + + + + LxQtThemeConfig + + + LXQt Theme + LXQtテーマ + + + + QObject + + + LXQt Appearance Configuration + LXQt外観の設定 + + + + Widget Style + ウィジェットのスタイル + + + + Icons Theme + アイコンテーマ + + + + LXQt Theme + LXQtテーマ + + + + Font + フォント + + + + Cursor + カーソル + + + + StyleConfig + + + Widget Style + ウィジェットのスタイル + + + + Toolbar button style: + ツールバーボタンのスタイル: + + + + Only display the icon + アイコンのみを表示 + + + + Only display the text + テキストのみを表示 + + + + The text appears beside the icon + アイコンの横にテキスト + + + + The text appears under the icon + アイコンの下にテキスト + + + + Default + デフォルト + + + + Activate item on single click + シングルクリックでアイテムを有効にする + + + diff --git a/lxqt-config-appearance/translations/lxqt-config-appearance_ko.desktop b/lxqt-config-appearance/translations/lxqt-config-appearance_ko.desktop new file mode 100644 index 0000000..26b0d99 --- /dev/null +++ b/lxqt-config-appearance/translations/lxqt-config-appearance_ko.desktop @@ -0,0 +1 @@ +# Translations diff --git a/lxqt-config-appearance/translations/lxqt-config-appearance_ko.ts b/lxqt-config-appearance/translations/lxqt-config-appearance_ko.ts new file mode 100644 index 0000000..53a63c1 --- /dev/null +++ b/lxqt-config-appearance/translations/lxqt-config-appearance_ko.ts @@ -0,0 +1,225 @@ + + + + + FontsConfig + + + Font + + + + + Default font for user interface + + + + + Font name: + + + + + Style: + + + + + Point size: + + + + + Normal + + + + + Bold + + + + + Italic + + + + + Bold Italic + + + + + The following settings only affect newly started applications + + + + + Use antialias fonts + + + + + Font hinting style: + + + + + + None + + + + + Slight + + + + + Medium + + + + + Full + + + + + Font hinting + + + + + Resolution (DPI): + + + + + Autohint + + + + + Subpixel antialiasing: + + + + + RGB + + + + + BGR + + + + + VRGB + + + + + VBGR + + + + + IconThemeConfig + + + LXQt Appearance Configuration + + + + + Icons Theme + + + + + LxQtThemeConfig + + + LXQt Theme + + + + + QObject + + + LXQt Appearance Configuration + + + + + Widget Style + + + + + Icons Theme + + + + + LXQt Theme + + + + + Font + + + + + Cursor + + + + + StyleConfig + + + Widget Style + + + + + Toolbar button style: + + + + + Only display the icon + + + + + Only display the text + + + + + The text appears beside the icon + + + + + The text appears under the icon + + + + + Default + + + + + Activate item on single click + + + + diff --git a/lxqt-config-appearance/translations/lxqt-config-appearance_lt.desktop b/lxqt-config-appearance/translations/lxqt-config-appearance_lt.desktop new file mode 100644 index 0000000..a9f88d6 --- /dev/null +++ b/lxqt-config-appearance/translations/lxqt-config-appearance_lt.desktop @@ -0,0 +1,4 @@ +# Translations +Comment[lt]=Konfigūruoti LXQt darbalaukio išvaizdą +GenericName[lt]=LXQt išvaizdos konfigūravimas +Name[lt]=LXQt išvaizdos konfigūravimas diff --git a/lxqt-config-appearance/translations/lxqt-config-appearance_lt.ts b/lxqt-config-appearance/translations/lxqt-config-appearance_lt.ts new file mode 100644 index 0000000..a963ad3 --- /dev/null +++ b/lxqt-config-appearance/translations/lxqt-config-appearance_lt.ts @@ -0,0 +1,232 @@ + + + + + FontsConfig + + + Font + + + + + Default font for user interface + + + + + Font name: + + + + + Style: + + + + + Point size: + + + + + Normal + + + + + Bold + + + + + Italic + + + + + Bold Italic + + + + + The following settings only affect newly started applications + + + + + Use antialias fonts + + + + + Font hinting style: + + + + + + None + + + + + Slight + + + + + Medium + + + + + Full + + + + + Font hinting + + + + + Resolution (DPI): + + + + + Autohint + + + + + Subpixel antialiasing: + + + + + RGB + + + + + BGR + + + + + VRGB + + + + + VBGR + + + + + IconThemeConfig + + + LXQt Appearance Configuration + LXQt išvaizdos nustatymai + + + + Icons Theme + Piktogramų tema + + + + LXQtThemeConfig + + LXQt Theme + LXQt apipavidalinimas + + + + LxQtThemeConfig + + + LXQt Theme + LXQt apipavidalinimas + + + + QObject + + + LXQt Appearance Configuration + LXQt išvaizdos nustatymai + + + + Widget Style + + + + + Icons Theme + Piktogramų tema + + + + LXQt Theme + LXQt apipavidalinimas + + + + Font + + + + + Cursor + + + + + StyleConfig + + + Widget Style + + + + + Toolbar button style: + + + + + Only display the icon + + + + + Only display the text + + + + + The text appears beside the icon + + + + + The text appears under the icon + + + + + Default + + + + + Activate item on single click + + + + diff --git a/lxqt-config-appearance/translations/lxqt-config-appearance_nl.desktop b/lxqt-config-appearance/translations/lxqt-config-appearance_nl.desktop new file mode 100644 index 0000000..0c56d11 --- /dev/null +++ b/lxqt-config-appearance/translations/lxqt-config-appearance_nl.desktop @@ -0,0 +1,4 @@ +# Translations +Comment[nl]=Configureer het uiterlijk van het LXQt bureaublad +GenericName[nl]=LXQt Uiterlijk Configuratie +Name[nl]=LXQt Uiterlijk Configuratie diff --git a/lxqt-config-appearance/translations/lxqt-config-appearance_nl.ts b/lxqt-config-appearance/translations/lxqt-config-appearance_nl.ts new file mode 100644 index 0000000..2a21bdf --- /dev/null +++ b/lxqt-config-appearance/translations/lxqt-config-appearance_nl.ts @@ -0,0 +1,232 @@ + + + + + FontsConfig + + + Font + + + + + Default font for user interface + + + + + Font name: + + + + + Style: + + + + + Point size: + + + + + Normal + + + + + Bold + + + + + Italic + + + + + Bold Italic + + + + + The following settings only affect newly started applications + + + + + Use antialias fonts + + + + + Font hinting style: + + + + + + None + + + + + Slight + + + + + Medium + + + + + Full + + + + + Font hinting + + + + + Resolution (DPI): + + + + + Autohint + + + + + Subpixel antialiasing: + + + + + RGB + + + + + BGR + + + + + VRGB + + + + + VBGR + + + + + IconThemeConfig + + + LXQt Appearance Configuration + LXQt Uiterlijk Configuratie + + + + Icons Theme + Pictogram Thema + + + + LXQtThemeConfig + + LXQt Theme + LXQt Thema + + + + LxQtThemeConfig + + + LXQt Theme + LXQt Thema + + + + QObject + + + LXQt Appearance Configuration + LXQt Uiterlijk Configuratie + + + + Widget Style + + + + + Icons Theme + Pictogram Thema + + + + LXQt Theme + LXQt Thema + + + + Font + + + + + Cursor + + + + + StyleConfig + + + Widget Style + + + + + Toolbar button style: + + + + + Only display the icon + + + + + Only display the text + + + + + The text appears beside the icon + + + + + The text appears under the icon + + + + + Default + + + + + Activate item on single click + + + + diff --git a/lxqt-config-appearance/translations/lxqt-config-appearance_pl.ts b/lxqt-config-appearance/translations/lxqt-config-appearance_pl.ts new file mode 100644 index 0000000..4141764 --- /dev/null +++ b/lxqt-config-appearance/translations/lxqt-config-appearance_pl.ts @@ -0,0 +1,225 @@ + + + + + FontsConfig + + + Font + + + + + Default font for user interface + + + + + Font name: + + + + + Style: + + + + + Point size: + + + + + Normal + + + + + Bold + + + + + Italic + + + + + Bold Italic + + + + + The following settings only affect newly started applications + + + + + Use antialias fonts + + + + + Font hinting style: + + + + + + None + + + + + Slight + + + + + Medium + + + + + Full + + + + + Font hinting + + + + + Resolution (DPI): + + + + + Autohint + + + + + Subpixel antialiasing: + + + + + RGB + + + + + BGR + + + + + VRGB + + + + + VBGR + + + + + IconThemeConfig + + + LXQt Appearance Configuration + Menu + + + + Icons Theme + + + + + LxQtThemeConfig + + + LXQt Theme + + + + + QObject + + + LXQt Appearance Configuration + Menu + + + + Widget Style + + + + + Icons Theme + + + + + LXQt Theme + + + + + Font + + + + + Cursor + + + + + StyleConfig + + + Widget Style + + + + + Toolbar button style: + + + + + Only display the icon + + + + + Only display the text + + + + + The text appears beside the icon + + + + + The text appears under the icon + + + + + Default + + + + + Activate item on single click + + + + diff --git a/lxqt-config-appearance/translations/lxqt-config-appearance_pl_PL.desktop b/lxqt-config-appearance/translations/lxqt-config-appearance_pl_PL.desktop new file mode 100644 index 0000000..2987540 --- /dev/null +++ b/lxqt-config-appearance/translations/lxqt-config-appearance_pl_PL.desktop @@ -0,0 +1,4 @@ +# Translations +Comment[pl_PL]=Konfiguruj wylgąd pulpitu LXQt +GenericName[pl_PL]=Konfiguracja wyglądu LXQt +Name[pl_PL]=Konfiguracja wyglądu LXQt diff --git a/lxqt-config-appearance/translations/lxqt-config-appearance_pl_PL.ts b/lxqt-config-appearance/translations/lxqt-config-appearance_pl_PL.ts new file mode 100644 index 0000000..8d0e22f --- /dev/null +++ b/lxqt-config-appearance/translations/lxqt-config-appearance_pl_PL.ts @@ -0,0 +1,232 @@ + + + + + FontsConfig + + + Font + + + + + Default font for user interface + + + + + Font name: + + + + + Style: + + + + + Point size: + + + + + Normal + + + + + Bold + + + + + Italic + + + + + Bold Italic + + + + + The following settings only affect newly started applications + + + + + Use antialias fonts + + + + + Font hinting style: + + + + + + None + + + + + Slight + + + + + Medium + + + + + Full + + + + + Font hinting + + + + + Resolution (DPI): + + + + + Autohint + + + + + Subpixel antialiasing: + + + + + RGB + + + + + BGR + + + + + VRGB + + + + + VBGR + + + + + IconThemeConfig + + + LXQt Appearance Configuration + Konfiguracja wyglądu LXQt + + + + Icons Theme + Motyw ikon + + + + LXQtThemeConfig + + LXQt Theme + Motyw LXQt + + + + LxQtThemeConfig + + + LXQt Theme + Motyw LXQt + + + + QObject + + + LXQt Appearance Configuration + Konfiguracja wyglądu LXQt + + + + Widget Style + + + + + Icons Theme + Motyw ikon + + + + LXQt Theme + Motyw LXQt + + + + Font + + + + + Cursor + + + + + StyleConfig + + + Widget Style + + + + + Toolbar button style: + + + + + Only display the icon + + + + + Only display the text + + + + + The text appears beside the icon + + + + + The text appears under the icon + + + + + Default + + + + + Activate item on single click + + + + diff --git a/lxqt-config-appearance/translations/lxqt-config-appearance_pt.desktop b/lxqt-config-appearance/translations/lxqt-config-appearance_pt.desktop new file mode 100644 index 0000000..f114950 --- /dev/null +++ b/lxqt-config-appearance/translations/lxqt-config-appearance_pt.desktop @@ -0,0 +1,4 @@ +# Translations +Comment[pt]=Configurar o aspeto do LXQt +GenericName[pt]=Configuração da aparência do LXQt +Name[pt]=Configuração da aparência do LXQt diff --git a/lxqt-config-appearance/translations/lxqt-config-appearance_pt.ts b/lxqt-config-appearance/translations/lxqt-config-appearance_pt.ts new file mode 100644 index 0000000..3f5b9c9 --- /dev/null +++ b/lxqt-config-appearance/translations/lxqt-config-appearance_pt.ts @@ -0,0 +1,232 @@ + + + + + FontsConfig + + + Font + + + + + Default font for user interface + + + + + Font name: + + + + + Style: + + + + + Point size: + + + + + Normal + + + + + Bold + + + + + Italic + + + + + Bold Italic + + + + + The following settings only affect newly started applications + + + + + Use antialias fonts + + + + + Font hinting style: + + + + + + None + + + + + Slight + + + + + Medium + + + + + Full + + + + + Font hinting + + + + + Resolution (DPI): + + + + + Autohint + + + + + Subpixel antialiasing: + + + + + RGB + + + + + BGR + + + + + VRGB + + + + + VBGR + + + + + IconThemeConfig + + + LXQt Appearance Configuration + Configuração da aparência do LXQt + + + + Icons Theme + Tema de ícones + + + + LXQtThemeConfig + + LXQt Theme + Tema LXQt + + + + LxQtThemeConfig + + + LXQt Theme + Tema LXQt + + + + QObject + + + LXQt Appearance Configuration + Configuração da aparência do LXQt + + + + Widget Style + + + + + Icons Theme + Tema de ícones + + + + LXQt Theme + Tema LXQt + + + + Font + + + + + Cursor + + + + + StyleConfig + + + Widget Style + + + + + Toolbar button style: + + + + + Only display the icon + + + + + Only display the text + + + + + The text appears beside the icon + + + + + The text appears under the icon + + + + + Default + + + + + Activate item on single click + + + + diff --git a/lxqt-config-appearance/translations/lxqt-config-appearance_pt_BR.desktop b/lxqt-config-appearance/translations/lxqt-config-appearance_pt_BR.desktop new file mode 100644 index 0000000..b26cf8c --- /dev/null +++ b/lxqt-config-appearance/translations/lxqt-config-appearance_pt_BR.desktop @@ -0,0 +1,4 @@ +# Translations +Comment[pt_BR]=Configure a aparência da área de trabalho LXQt +GenericName[pt_BR]=Configuração da aparência do LXQt +Name[pt_BR]=Configuração da aparência do LXQt diff --git a/lxqt-config-appearance/translations/lxqt-config-appearance_pt_BR.ts b/lxqt-config-appearance/translations/lxqt-config-appearance_pt_BR.ts new file mode 100644 index 0000000..0bd88fc --- /dev/null +++ b/lxqt-config-appearance/translations/lxqt-config-appearance_pt_BR.ts @@ -0,0 +1,232 @@ + + + + + FontsConfig + + + Font + + + + + Default font for user interface + + + + + Font name: + + + + + Style: + + + + + Point size: + + + + + Normal + + + + + Bold + + + + + Italic + + + + + Bold Italic + + + + + The following settings only affect newly started applications + + + + + Use antialias fonts + + + + + Font hinting style: + + + + + + None + + + + + Slight + + + + + Medium + + + + + Full + + + + + Font hinting + + + + + Resolution (DPI): + + + + + Autohint + + + + + Subpixel antialiasing: + + + + + RGB + + + + + BGR + + + + + VRGB + + + + + VBGR + + + + + IconThemeConfig + + + LXQt Appearance Configuration + Configuração da aparência do LXQt + + + + Icons Theme + Tema de ícones + + + + LXQtThemeConfig + + LXQt Theme + Tema do LXQt + + + + LxQtThemeConfig + + + LXQt Theme + Tema do LXQt + + + + QObject + + + LXQt Appearance Configuration + Configuração da aparência do LXQt + + + + Widget Style + + + + + Icons Theme + Tema de ícones + + + + LXQt Theme + Tema do LXQt + + + + Font + + + + + Cursor + + + + + StyleConfig + + + Widget Style + + + + + Toolbar button style: + + + + + Only display the icon + + + + + Only display the text + + + + + The text appears beside the icon + + + + + The text appears under the icon + + + + + Default + + + + + Activate item on single click + + + + diff --git a/lxqt-config-appearance/translations/lxqt-config-appearance_ro_RO.desktop b/lxqt-config-appearance/translations/lxqt-config-appearance_ro_RO.desktop new file mode 100644 index 0000000..20da510 --- /dev/null +++ b/lxqt-config-appearance/translations/lxqt-config-appearance_ro_RO.desktop @@ -0,0 +1,4 @@ +# Translations +Comment[ro_RO]=Configurează aspectul desktopului LXQt +GenericName[ro_RO]=Configurare aspect LXQt +Name[ro_RO]=Configurare aspect LXQt diff --git a/lxqt-config-appearance/translations/lxqt-config-appearance_ro_RO.ts b/lxqt-config-appearance/translations/lxqt-config-appearance_ro_RO.ts new file mode 100644 index 0000000..9d3d139 --- /dev/null +++ b/lxqt-config-appearance/translations/lxqt-config-appearance_ro_RO.ts @@ -0,0 +1,232 @@ + + + + + FontsConfig + + + Font + + + + + Default font for user interface + + + + + Font name: + + + + + Style: + + + + + Point size: + + + + + Normal + + + + + Bold + + + + + Italic + + + + + Bold Italic + + + + + The following settings only affect newly started applications + + + + + Use antialias fonts + + + + + Font hinting style: + + + + + + None + + + + + Slight + + + + + Medium + + + + + Full + + + + + Font hinting + + + + + Resolution (DPI): + + + + + Autohint + + + + + Subpixel antialiasing: + + + + + RGB + + + + + BGR + + + + + VRGB + + + + + VBGR + + + + + IconThemeConfig + + + LXQt Appearance Configuration + Părăsește + + + + Icons Theme + Temă pictograme + + + + LXQtThemeConfig + + LXQt Theme + Temă LXQt + + + + LxQtThemeConfig + + + LXQt Theme + Temă LXQt + + + + QObject + + + LXQt Appearance Configuration + Părăsește + + + + Widget Style + + + + + Icons Theme + Temă pictograme + + + + LXQt Theme + Temă LXQt + + + + Font + + + + + Cursor + + + + + StyleConfig + + + Widget Style + + + + + Toolbar button style: + + + + + Only display the icon + + + + + Only display the text + + + + + The text appears beside the icon + + + + + The text appears under the icon + + + + + Default + + + + + Activate item on single click + + + + diff --git a/lxqt-config-appearance/translations/lxqt-config-appearance_ru.desktop b/lxqt-config-appearance/translations/lxqt-config-appearance_ru.desktop new file mode 100644 index 0000000..2453235 --- /dev/null +++ b/lxqt-config-appearance/translations/lxqt-config-appearance_ru.desktop @@ -0,0 +1,4 @@ +# Translations +Comment[ru]=Настройки внешнего вида LXQt +GenericName[ru]=Настройка внешнего вида +Name[ru]=Внешний вид \ No newline at end of file diff --git a/lxqt-config-appearance/translations/lxqt-config-appearance_ru.ts b/lxqt-config-appearance/translations/lxqt-config-appearance_ru.ts new file mode 100644 index 0000000..d27fbfa --- /dev/null +++ b/lxqt-config-appearance/translations/lxqt-config-appearance_ru.ts @@ -0,0 +1,225 @@ + + + + + FontsConfig + + + Font + Шрифт + + + + Default font for user interface + Шрифт по умолчанию для пользовательского интерфейса + + + + Font name: + Название шрифта: + + + + Style: + Стиль: + + + + Point size: + Кегль: + + + + Normal + Нормальный + + + + Bold + Полужирный + + + + Italic + Наклонный + + + + Bold Italic + Полужирный наклонный + + + + The following settings only affect newly started applications + Следующие настройки подействуют только на вновь запущенные приложения + + + + Use antialias fonts + Использовать сглаживание шрифтов + + + + Font hinting style: + Стиль хинтинга шрифта: + + + + + None + Нет + + + + Slight + Слабое + + + + Medium + Среднее + + + + Full + Полное + + + + Font hinting + Хинтинг шрифта + + + + Resolution (DPI): + Разрешение (DPI): + + + + Autohint + + + + + Subpixel antialiasing: + Субпиксельное сглаживание: + + + + RGB + RGB + + + + BGR + BGR + + + + VRGB + VRGB + + + + VBGR + VBGR + + + + IconThemeConfig + + + LXQt Appearance Configuration + Меню программ + + + + Icons Theme + Иконки темы + + + + LxQtThemeConfig + + + LXQt Theme + Тема LXQt + + + + QObject + + + LXQt Appearance Configuration + Настройка внешнего вида LXQt + + + + Icons Theme + Тема иконок + + + + LXQt Theme + LXQt темы + + + + Widget Style + Стиль виджетов + + + + Font + Шрифт + + + + Cursor + Курсор + + + + StyleConfig + + + Widget Style + Стиль виджетов + + + + Toolbar button style: + Стиль кнопок панели: + + + + Only display the icon + Показывать только иконку + + + + Only display the text + Показывать только текст + + + + The text appears beside the icon + Текст появляется сбоку от иконки + + + + The text appears under the icon + Текст появляется под иконкой + + + + Default + По умолчанию + + + + Activate item on single click + Активировать элемент по одиночному щелчку мыши + + + diff --git a/lxqt-config-appearance/translations/lxqt-config-appearance_ru_RU.desktop b/lxqt-config-appearance/translations/lxqt-config-appearance_ru_RU.desktop new file mode 100644 index 0000000..4a9c58a --- /dev/null +++ b/lxqt-config-appearance/translations/lxqt-config-appearance_ru_RU.desktop @@ -0,0 +1,4 @@ +# Translations +Comment[ru_RU]=Настройки внешнего вида LXQt +GenericName[ru_RU]=Настройка внешнего вида +Name[ru_RU]=Внешний вид \ No newline at end of file diff --git a/lxqt-config-appearance/translations/lxqt-config-appearance_ru_RU.ts b/lxqt-config-appearance/translations/lxqt-config-appearance_ru_RU.ts new file mode 100644 index 0000000..d27fbfa --- /dev/null +++ b/lxqt-config-appearance/translations/lxqt-config-appearance_ru_RU.ts @@ -0,0 +1,225 @@ + + + + + FontsConfig + + + Font + Шрифт + + + + Default font for user interface + Шрифт по умолчанию для пользовательского интерфейса + + + + Font name: + Название шрифта: + + + + Style: + Стиль: + + + + Point size: + Кегль: + + + + Normal + Нормальный + + + + Bold + Полужирный + + + + Italic + Наклонный + + + + Bold Italic + Полужирный наклонный + + + + The following settings only affect newly started applications + Следующие настройки подействуют только на вновь запущенные приложения + + + + Use antialias fonts + Использовать сглаживание шрифтов + + + + Font hinting style: + Стиль хинтинга шрифта: + + + + + None + Нет + + + + Slight + Слабое + + + + Medium + Среднее + + + + Full + Полное + + + + Font hinting + Хинтинг шрифта + + + + Resolution (DPI): + Разрешение (DPI): + + + + Autohint + + + + + Subpixel antialiasing: + Субпиксельное сглаживание: + + + + RGB + RGB + + + + BGR + BGR + + + + VRGB + VRGB + + + + VBGR + VBGR + + + + IconThemeConfig + + + LXQt Appearance Configuration + Меню программ + + + + Icons Theme + Иконки темы + + + + LxQtThemeConfig + + + LXQt Theme + Тема LXQt + + + + QObject + + + LXQt Appearance Configuration + Настройка внешнего вида LXQt + + + + Icons Theme + Тема иконок + + + + LXQt Theme + LXQt темы + + + + Widget Style + Стиль виджетов + + + + Font + Шрифт + + + + Cursor + Курсор + + + + StyleConfig + + + Widget Style + Стиль виджетов + + + + Toolbar button style: + Стиль кнопок панели: + + + + Only display the icon + Показывать только иконку + + + + Only display the text + Показывать только текст + + + + The text appears beside the icon + Текст появляется сбоку от иконки + + + + The text appears under the icon + Текст появляется под иконкой + + + + Default + По умолчанию + + + + Activate item on single click + Активировать элемент по одиночному щелчку мыши + + + diff --git a/lxqt-config-appearance/translations/lxqt-config-appearance_sk.desktop b/lxqt-config-appearance/translations/lxqt-config-appearance_sk.desktop new file mode 100644 index 0000000..cace414 --- /dev/null +++ b/lxqt-config-appearance/translations/lxqt-config-appearance_sk.desktop @@ -0,0 +1,4 @@ +# Translations +Comment[sk]=Nastavenie vzhľadu prostredia LXQt +GenericName[sk]=Nastavenie vzhľadu +Name[sk]=Nastavenie vzhľadu diff --git a/lxqt-config-appearance/translations/lxqt-config-appearance_sk_SK.ts b/lxqt-config-appearance/translations/lxqt-config-appearance_sk_SK.ts new file mode 100644 index 0000000..565bd74 --- /dev/null +++ b/lxqt-config-appearance/translations/lxqt-config-appearance_sk_SK.ts @@ -0,0 +1,236 @@ + + + + + FontsConfig + + + Font + + + + + Default font for user interface + + + + + Font name: + + + + + Style: + + + + + Point size: + + + + + Normal + + + + + Bold + + + + + Italic + + + + + Bold Italic + + + + + The following settings only affect newly started applications + + + + + Use antialias fonts + + + + + Font hinting style: + + + + + + None + + + + + Slight + + + + + Medium + + + + + Full + + + + + Font hinting + + + + + Resolution (DPI): + + + + + Autohint + + + + + Subpixel antialiasing: + + + + + RGB + + + + + BGR + + + + + VRGB + + + + + VBGR + + + + + IconThemeConfig + + + LXQt Appearance Configuration + Nastavenie vzhľadu prostredia LXQt + + + + Icons Theme + Téma ikon + + + + LxQtThemeConfig + + + LXQt Theme + + + + + MainWindow + + LXQt Appearance Configuration + Nastavenie vzhľadu prostredia LXQt + + + Icons Theme + Téma ikon + + + + QObject + + + LXQt Appearance Configuration + Nastavenie vzhľadu prostredia LXQt + + + + Widget Style + + + + + Icons Theme + Téma ikon + + + + LXQt Theme + + + + + Font + + + + + Cursor + + + + + StyleConfig + + + Widget Style + + + + + Toolbar button style: + + + + + Only display the icon + + + + + Only display the text + + + + + The text appears beside the icon + + + + + The text appears under the icon + + + + + Default + + + + + Activate item on single click + + + + diff --git a/lxqt-config-appearance/translations/lxqt-config-appearance_sl.desktop b/lxqt-config-appearance/translations/lxqt-config-appearance_sl.desktop new file mode 100644 index 0000000..3fd428c --- /dev/null +++ b/lxqt-config-appearance/translations/lxqt-config-appearance_sl.desktop @@ -0,0 +1,4 @@ +# Translations +Comment[sl]=Nastavite videz namizja LXQt +GenericName[sl]=Nastavitev videza +Name[sl]=Nastavitev videza namizja LXQt diff --git a/lxqt-config-appearance/translations/lxqt-config-appearance_sl.ts b/lxqt-config-appearance/translations/lxqt-config-appearance_sl.ts new file mode 100644 index 0000000..392c45c --- /dev/null +++ b/lxqt-config-appearance/translations/lxqt-config-appearance_sl.ts @@ -0,0 +1,232 @@ + + + + + FontsConfig + + + Font + + + + + Default font for user interface + + + + + Font name: + + + + + Style: + + + + + Point size: + + + + + Normal + + + + + Bold + + + + + Italic + + + + + Bold Italic + + + + + The following settings only affect newly started applications + + + + + Use antialias fonts + + + + + Font hinting style: + + + + + + None + + + + + Slight + + + + + Medium + + + + + Full + + + + + Font hinting + + + + + Resolution (DPI): + + + + + Autohint + + + + + Subpixel antialiasing: + + + + + RGB + + + + + BGR + + + + + VRGB + + + + + VBGR + + + + + IconThemeConfig + + + LXQt Appearance Configuration + Nastavitev videza za LXQt + + + + Icons Theme + Tema ikon + + + + LXQtThemeConfig + + LXQt Theme + Tema za LXQt + + + + LxQtThemeConfig + + + LXQt Theme + Tema za LXQt + + + + QObject + + + LXQt Appearance Configuration + Nastavitev videza za LXQt + + + + Widget Style + + + + + Icons Theme + Tema ikon + + + + LXQt Theme + Tema za LXQt + + + + Font + + + + + Cursor + + + + + StyleConfig + + + Widget Style + + + + + Toolbar button style: + + + + + Only display the icon + + + + + Only display the text + + + + + The text appears beside the icon + + + + + The text appears under the icon + + + + + Default + + + + + Activate item on single click + + + + diff --git a/lxqt-config-appearance/translations/lxqt-config-appearance_sr.desktop b/lxqt-config-appearance/translations/lxqt-config-appearance_sr.desktop new file mode 100644 index 0000000..8a8351f --- /dev/null +++ b/lxqt-config-appearance/translations/lxqt-config-appearance_sr.desktop @@ -0,0 +1,4 @@ +# Translations +Comment[sr]=Подесите изглед Рејзорове радне површи +GenericName[sr]=Подешавање изгледа +Name[sr]=Подешавање изгледа Рејзора diff --git a/lxqt-config-appearance/translations/lxqt-config-appearance_sr@ijekavian.desktop b/lxqt-config-appearance/translations/lxqt-config-appearance_sr@ijekavian.desktop new file mode 100644 index 0000000..8943815 --- /dev/null +++ b/lxqt-config-appearance/translations/lxqt-config-appearance_sr@ijekavian.desktop @@ -0,0 +1,3 @@ +Name[sr@ijekavian]=Подешавање изгледа Рејзора +Comment[sr@ijekavian]=Подесите изглед Рејзорове радне површи +GenericName[sr@ijekavian]=Подешавање изгледа diff --git a/lxqt-config-appearance/translations/lxqt-config-appearance_sr@ijekavianlatin.desktop b/lxqt-config-appearance/translations/lxqt-config-appearance_sr@ijekavianlatin.desktop new file mode 100644 index 0000000..69661a6 --- /dev/null +++ b/lxqt-config-appearance/translations/lxqt-config-appearance_sr@ijekavianlatin.desktop @@ -0,0 +1,3 @@ +Name[sr@ijekavianlatin]=Podešavanje izgleda Rejzora +Comment[sr@ijekavianlatin]=Podesite izgled Rejzorove radne površi +GenericName[sr@ijekavianlatin]=Podešavanje izgleda diff --git a/lxqt-config-appearance/translations/lxqt-config-appearance_sr@latin.desktop b/lxqt-config-appearance/translations/lxqt-config-appearance_sr@latin.desktop new file mode 100644 index 0000000..3aebf95 --- /dev/null +++ b/lxqt-config-appearance/translations/lxqt-config-appearance_sr@latin.desktop @@ -0,0 +1,4 @@ +# Translations +Comment[sr@latin]=Podesite izgled Rejzorove radne površi +GenericName[sr@latin]=Podešavanje izgleda +Name[sr@latin]=Podešavanje izgleda Rejzora diff --git a/lxqt-config-appearance/translations/lxqt-config-appearance_sr@latin.ts b/lxqt-config-appearance/translations/lxqt-config-appearance_sr@latin.ts new file mode 100644 index 0000000..adbc92c --- /dev/null +++ b/lxqt-config-appearance/translations/lxqt-config-appearance_sr@latin.ts @@ -0,0 +1,225 @@ + + + + + FontsConfig + + + Font + + + + + Default font for user interface + + + + + Font name: + + + + + Style: + + + + + Point size: + + + + + Normal + + + + + Bold + + + + + Italic + + + + + Bold Italic + + + + + The following settings only affect newly started applications + + + + + Use antialias fonts + + + + + Font hinting style: + + + + + + None + + + + + Slight + + + + + Medium + + + + + Full + + + + + Font hinting + + + + + Resolution (DPI): + + + + + Autohint + + + + + Subpixel antialiasing: + + + + + RGB + + + + + BGR + + + + + VRGB + + + + + VBGR + + + + + IconThemeConfig + + + LXQt Appearance Configuration + Automatsko suspendovanje + + + + Icons Theme + + + + + LxQtThemeConfig + + + LXQt Theme + + + + + QObject + + + LXQt Appearance Configuration + Automatsko suspendovanje + + + + Widget Style + + + + + Icons Theme + + + + + LXQt Theme + + + + + Font + + + + + Cursor + + + + + StyleConfig + + + Widget Style + + + + + Toolbar button style: + + + + + Only display the icon + + + + + Only display the text + + + + + The text appears beside the icon + + + + + The text appears under the icon + + + + + Default + + + + + Activate item on single click + + + + diff --git a/lxqt-config-appearance/translations/lxqt-config-appearance_sr_BA.ts b/lxqt-config-appearance/translations/lxqt-config-appearance_sr_BA.ts new file mode 100644 index 0000000..fb36467 --- /dev/null +++ b/lxqt-config-appearance/translations/lxqt-config-appearance_sr_BA.ts @@ -0,0 +1,236 @@ + + + + + FontsConfig + + + Font + + + + + Default font for user interface + + + + + Font name: + + + + + Style: + + + + + Point size: + + + + + Normal + + + + + Bold + + + + + Italic + + + + + Bold Italic + + + + + The following settings only affect newly started applications + + + + + Use antialias fonts + + + + + Font hinting style: + + + + + + None + + + + + Slight + + + + + Medium + + + + + Full + + + + + Font hinting + + + + + Resolution (DPI): + + + + + Autohint + + + + + Subpixel antialiasing: + + + + + RGB + + + + + BGR + + + + + VRGB + + + + + VBGR + + + + + IconThemeConfig + + + LXQt Appearance Configuration + Подешавање изгледа Рејзора + + + + Icons Theme + Тема икона + + + + LxQtThemeConfig + + + LXQt Theme + + + + + MainWindow + + LXQt Appearance Configuration + Подешавање изгледа Рејзора + + + Icons Theme + Тема икона + + + + QObject + + + LXQt Appearance Configuration + Подешавање изгледа Рејзора + + + + Widget Style + + + + + Icons Theme + Тема икона + + + + LXQt Theme + + + + + Font + + + + + Cursor + + + + + StyleConfig + + + Widget Style + + + + + Toolbar button style: + + + + + Only display the icon + + + + + Only display the text + + + + + The text appears beside the icon + + + + + The text appears under the icon + + + + + Default + + + + + Activate item on single click + + + + diff --git a/lxqt-config-appearance/translations/lxqt-config-appearance_sr_RS.ts b/lxqt-config-appearance/translations/lxqt-config-appearance_sr_RS.ts new file mode 100644 index 0000000..1d67bd7 --- /dev/null +++ b/lxqt-config-appearance/translations/lxqt-config-appearance_sr_RS.ts @@ -0,0 +1,236 @@ + + + + + FontsConfig + + + Font + + + + + Default font for user interface + + + + + Font name: + + + + + Style: + + + + + Point size: + + + + + Normal + + + + + Bold + + + + + Italic + + + + + Bold Italic + + + + + The following settings only affect newly started applications + + + + + Use antialias fonts + + + + + Font hinting style: + + + + + + None + + + + + Slight + + + + + Medium + + + + + Full + + + + + Font hinting + + + + + Resolution (DPI): + + + + + Autohint + + + + + Subpixel antialiasing: + + + + + RGB + + + + + BGR + + + + + VRGB + + + + + VBGR + + + + + IconThemeConfig + + + LXQt Appearance Configuration + Подешавање изгледа Рејзора + + + + Icons Theme + Тема икона + + + + LxQtThemeConfig + + + LXQt Theme + + + + + MainWindow + + LXQt Appearance Configuration + Подешавање изгледа Рејзора + + + Icons Theme + Тема икона + + + + QObject + + + LXQt Appearance Configuration + Подешавање изгледа Рејзора + + + + Widget Style + + + + + Icons Theme + Тема икона + + + + LXQt Theme + + + + + Font + + + + + Cursor + + + + + StyleConfig + + + Widget Style + + + + + Toolbar button style: + + + + + Only display the icon + + + + + Only display the text + + + + + The text appears beside the icon + + + + + The text appears under the icon + + + + + Default + + + + + Activate item on single click + + + + diff --git a/lxqt-config-appearance/translations/lxqt-config-appearance_th_TH.desktop b/lxqt-config-appearance/translations/lxqt-config-appearance_th_TH.desktop new file mode 100644 index 0000000..f4b0fa1 --- /dev/null +++ b/lxqt-config-appearance/translations/lxqt-config-appearance_th_TH.desktop @@ -0,0 +1,4 @@ +# Translations +Comment[th_TH]=ตั้งค่ารูปลักษณ์ของเดสก์ท็อป LXQt +GenericName[th_TH]=การตั้งค่ารูปลักษณ์ LXQt +Name[th_TH]=การตั้งค่ารูปลักษณ์ LXQt diff --git a/lxqt-config-appearance/translations/lxqt-config-appearance_th_TH.ts b/lxqt-config-appearance/translations/lxqt-config-appearance_th_TH.ts new file mode 100644 index 0000000..a5f937b --- /dev/null +++ b/lxqt-config-appearance/translations/lxqt-config-appearance_th_TH.ts @@ -0,0 +1,232 @@ + + + + + FontsConfig + + + Font + + + + + Default font for user interface + + + + + Font name: + + + + + Style: + + + + + Point size: + + + + + Normal + + + + + Bold + + + + + Italic + + + + + Bold Italic + + + + + The following settings only affect newly started applications + + + + + Use antialias fonts + + + + + Font hinting style: + + + + + + None + + + + + Slight + + + + + Medium + + + + + Full + + + + + Font hinting + + + + + Resolution (DPI): + + + + + Autohint + + + + + Subpixel antialiasing: + + + + + RGB + + + + + BGR + + + + + VRGB + + + + + VBGR + + + + + IconThemeConfig + + + LXQt Appearance Configuration + ปรับแต่งรูปโฉม LXQt + + + + Icons Theme + ชุดตกแต่งไอคอน + + + + LXQtThemeConfig + + LXQt Theme + ชุดตกแต่ง LXQt + + + + LxQtThemeConfig + + + LXQt Theme + ชุดตกแต่ง LXQt + + + + QObject + + + LXQt Appearance Configuration + ปรับแต่งรูปโฉม LXQt + + + + Widget Style + + + + + Icons Theme + ชุดตกแต่งไอคอน + + + + LXQt Theme + ชุดตกแต่ง LXQt + + + + Font + + + + + Cursor + + + + + StyleConfig + + + Widget Style + + + + + Toolbar button style: + + + + + Only display the icon + + + + + Only display the text + + + + + The text appears beside the icon + + + + + The text appears under the icon + + + + + Default + + + + + Activate item on single click + + + + diff --git a/lxqt-config-appearance/translations/lxqt-config-appearance_tr.desktop b/lxqt-config-appearance/translations/lxqt-config-appearance_tr.desktop new file mode 100644 index 0000000..9d01a71 --- /dev/null +++ b/lxqt-config-appearance/translations/lxqt-config-appearance_tr.desktop @@ -0,0 +1,4 @@ +# Translations +Comment[tr]=LXQt masaüstünün görünümünü yapılandırın +GenericName[tr]=LXQt Görünüm Yapılandırıcı +Name[tr]=LXQt Görünüm Yapılandırıcı diff --git a/lxqt-config-appearance/translations/lxqt-config-appearance_tr.ts b/lxqt-config-appearance/translations/lxqt-config-appearance_tr.ts new file mode 100644 index 0000000..64fa286 --- /dev/null +++ b/lxqt-config-appearance/translations/lxqt-config-appearance_tr.ts @@ -0,0 +1,232 @@ + + + + + FontsConfig + + + Font + + + + + Default font for user interface + + + + + Font name: + + + + + Style: + + + + + Point size: + + + + + Normal + + + + + Bold + + + + + Italic + + + + + Bold Italic + + + + + The following settings only affect newly started applications + + + + + Use antialias fonts + + + + + Font hinting style: + + + + + + None + + + + + Slight + + + + + Medium + + + + + Full + + + + + Font hinting + + + + + Resolution (DPI): + + + + + Autohint + + + + + Subpixel antialiasing: + + + + + RGB + + + + + BGR + + + + + VRGB + + + + + VBGR + + + + + IconThemeConfig + + + LXQt Appearance Configuration + LXQt Görünüm Ayarları + + + + Icons Theme + Simge Teması + + + + LXQtThemeConfig + + LXQt Theme + LXQt Teması + + + + LxQtThemeConfig + + + LXQt Theme + LXQt Teması + + + + QObject + + + LXQt Appearance Configuration + LXQt Görünüm Ayarları + + + + Widget Style + + + + + Icons Theme + Simge Teması + + + + LXQt Theme + LXQt Teması + + + + Font + + + + + Cursor + + + + + StyleConfig + + + Widget Style + + + + + Toolbar button style: + + + + + Only display the icon + + + + + Only display the text + + + + + The text appears beside the icon + + + + + The text appears under the icon + + + + + Default + + + + + Activate item on single click + + + + diff --git a/lxqt-config-appearance/translations/lxqt-config-appearance_uk.desktop b/lxqt-config-appearance/translations/lxqt-config-appearance_uk.desktop new file mode 100644 index 0000000..3398c37 --- /dev/null +++ b/lxqt-config-appearance/translations/lxqt-config-appearance_uk.desktop @@ -0,0 +1,4 @@ +# Translations +Comment[uk]=Налаштувати вигляд стільниці LXQt +GenericName[uk]=Налаштування вигляду LXQt +Name[uk]=Налаштування вигляду LXQt diff --git a/lxqt-config-appearance/translations/lxqt-config-appearance_uk.ts b/lxqt-config-appearance/translations/lxqt-config-appearance_uk.ts new file mode 100644 index 0000000..8e52fb7 --- /dev/null +++ b/lxqt-config-appearance/translations/lxqt-config-appearance_uk.ts @@ -0,0 +1,232 @@ + + + + + FontsConfig + + + Font + + + + + Default font for user interface + + + + + Font name: + + + + + Style: + + + + + Point size: + + + + + Normal + + + + + Bold + + + + + Italic + + + + + Bold Italic + + + + + The following settings only affect newly started applications + + + + + Use antialias fonts + + + + + Font hinting style: + + + + + + None + + + + + Slight + + + + + Medium + + + + + Full + + + + + Font hinting + + + + + Resolution (DPI): + + + + + Autohint + + + + + Subpixel antialiasing: + + + + + RGB + + + + + BGR + + + + + VRGB + + + + + VBGR + + + + + IconThemeConfig + + + LXQt Appearance Configuration + Налаштування вигляду LXQt + + + + Icons Theme + Тема значків + + + + LXQtThemeConfig + + LXQt Theme + Тема LXQt + + + + LxQtThemeConfig + + + LXQt Theme + Тема LXQt + + + + QObject + + + LXQt Appearance Configuration + Налаштування вигляду LXQt + + + + Widget Style + + + + + Icons Theme + Тема значків + + + + LXQt Theme + Тема LXQt + + + + Font + + + + + Cursor + + + + + StyleConfig + + + Widget Style + + + + + Toolbar button style: + + + + + Only display the icon + + + + + Only display the text + + + + + The text appears beside the icon + + + + + The text appears under the icon + + + + + Default + + + + + Activate item on single click + + + + diff --git a/lxqt-config-appearance/translations/lxqt-config-appearance_zh_CN.GB2312.desktop b/lxqt-config-appearance/translations/lxqt-config-appearance_zh_CN.GB2312.desktop new file mode 100644 index 0000000..26b0d99 --- /dev/null +++ b/lxqt-config-appearance/translations/lxqt-config-appearance_zh_CN.GB2312.desktop @@ -0,0 +1 @@ +# Translations diff --git a/lxqt-config-appearance/translations/lxqt-config-appearance_zh_CN.desktop b/lxqt-config-appearance/translations/lxqt-config-appearance_zh_CN.desktop new file mode 100644 index 0000000..cc576f7 --- /dev/null +++ b/lxqt-config-appearance/translations/lxqt-config-appearance_zh_CN.desktop @@ -0,0 +1,4 @@ +# Translations +Comment[zh_CN]=配置 LXQt 桌面的外观 +GenericName[zh_CN]=LXQt 外观配置 +Name[zh_CN]=LXQt 外观配置 diff --git a/lxqt-config-appearance/translations/lxqt-config-appearance_zh_CN.ts b/lxqt-config-appearance/translations/lxqt-config-appearance_zh_CN.ts new file mode 100644 index 0000000..0d2c898 --- /dev/null +++ b/lxqt-config-appearance/translations/lxqt-config-appearance_zh_CN.ts @@ -0,0 +1,232 @@ + + + + + FontsConfig + + + Font + + + + + Default font for user interface + + + + + Font name: + + + + + Style: + + + + + Point size: + + + + + Normal + + + + + Bold + + + + + Italic + + + + + Bold Italic + + + + + The following settings only affect newly started applications + + + + + Use antialias fonts + + + + + Font hinting style: + + + + + + None + + + + + Slight + + + + + Medium + + + + + Full + + + + + Font hinting + + + + + Resolution (DPI): + + + + + Autohint + + + + + Subpixel antialiasing: + + + + + RGB + + + + + BGR + + + + + VRGB + + + + + VBGR + + + + + IconThemeConfig + + + LXQt Appearance Configuration + LXQt 外观配置 + + + + Icons Theme + 图标主题 + + + + LXQtThemeConfig + + LXQt Theme + LXQt 主题 + + + + LxQtThemeConfig + + + LXQt Theme + LXQt 主题 + + + + QObject + + + LXQt Appearance Configuration + LXQt 外观配置 + + + + Widget Style + + + + + Icons Theme + 图标主题 + + + + LXQt Theme + LXQt 主题 + + + + Font + + + + + Cursor + + + + + StyleConfig + + + Widget Style + + + + + Toolbar button style: + + + + + Only display the icon + + + + + Only display the text + + + + + The text appears beside the icon + + + + + The text appears under the icon + + + + + Default + + + + + Activate item on single click + + + + diff --git a/lxqt-config-appearance/translations/lxqt-config-appearance_zh_TW.desktop b/lxqt-config-appearance/translations/lxqt-config-appearance_zh_TW.desktop new file mode 100644 index 0000000..038f4b2 --- /dev/null +++ b/lxqt-config-appearance/translations/lxqt-config-appearance_zh_TW.desktop @@ -0,0 +1,4 @@ +# Translations +Comment[zh_TW]=自定LXQt桌面的外觀 +GenericName[zh_TW]=LXQt外觀設定 +Name[zh_TW]=LXQt外觀設定 diff --git a/lxqt-config-appearance/translations/lxqt-config-appearance_zh_TW.ts b/lxqt-config-appearance/translations/lxqt-config-appearance_zh_TW.ts new file mode 100644 index 0000000..2fa9c6e --- /dev/null +++ b/lxqt-config-appearance/translations/lxqt-config-appearance_zh_TW.ts @@ -0,0 +1,232 @@ + + + + + FontsConfig + + + Font + + + + + Default font for user interface + + + + + Font name: + + + + + Style: + + + + + Point size: + + + + + Normal + + + + + Bold + + + + + Italic + + + + + Bold Italic + + + + + The following settings only affect newly started applications + + + + + Use antialias fonts + + + + + Font hinting style: + + + + + + None + + + + + Slight + + + + + Medium + + + + + Full + + + + + Font hinting + + + + + Resolution (DPI): + + + + + Autohint + + + + + Subpixel antialiasing: + + + + + RGB + + + + + BGR + + + + + VRGB + + + + + VBGR + + + + + IconThemeConfig + + + LXQt Appearance Configuration + LXQt自訂外觀 + + + + Icons Theme + 圖示主題 + + + + LXQtThemeConfig + + LXQt Theme + LXQt主題 + + + + LxQtThemeConfig + + + LXQt Theme + LXQt主題 + + + + QObject + + + LXQt Appearance Configuration + LXQt自訂外觀 + + + + Widget Style + + + + + Icons Theme + 圖示主題 + + + + LXQt Theme + LXQt主題 + + + + Font + + + + + Cursor + + + + + StyleConfig + + + Widget Style + + + + + Toolbar button style: + + + + + Only display the icon + + + + + Only display the text + + + + + The text appears beside the icon + + + + + The text appears under the icon + + + + + Default + + + + + Activate item on single click + + + + diff --git a/lxqt-config-file-associations/CMakeLists.txt b/lxqt-config-file-associations/CMakeLists.txt new file mode 100644 index 0000000..c12e235 --- /dev/null +++ b/lxqt-config-file-associations/CMakeLists.txt @@ -0,0 +1,79 @@ +project(lxqt-config-file-associations) + +include_directories( + "${CMAKE_CURRENT_BINARY_DIR}" +) + +set(H_FILES + mimetypedata.h + mimetypeviewer.h + applicationchooser.h +) + +set(MOC_FILES + mimetypedata.h + mimetypeviewer.h + applicationchooser.h +) + +set(CPP_FILES + mimetypedata.cpp + mimetypeviewer.cpp + applicationchooser.cpp + main.cpp +) + +set(UI_FILES + mimetypeviewer.ui + applicationchooser.ui +) + +set(QRC_FILES "") + +set(LIBRARIES + ${QTXDG_LIBRARIES} + ${LXQT_LIBRARIES} +) + +# Translations ********************************** +lxqt_translate_ts(QM_FILES + UPDATE_TRANSLATIONS + ${UPDATE_TRANSLATIONS} + SOURCES + ${H_FILES} + ${CPP_FILES} + ${UI_FILES} + INSTALL_DIR + "${LXQT_TRANSLATIONS_DIR}/${PROJECT_NAME}" +) + +lxqt_app_translation_loader(QM_LOADER ${PROJECT_NAME}) +lxqt_translate_desktop(DESKTOP_FILES SOURCES ${PROJECT_NAME}.desktop.in) + +#************************************************ + +qt5_wrap_ui(UI_HEADERS ${UI_FILES}) +qt5_add_resources(QRC_SOURCES ${QRC_FILES}) + +add_executable(${PROJECT_NAME} + ${CPP_FILES} + ${UI_FILES} + ${RESOURCES} + ${QRC_SOURCES} + ${QM_FILES} + ${QM_LOADER} + ${MOC_SOURCES} + ${DESKTOP_FILES} +) + +target_link_libraries(${PROJECT_NAME} + KF5::WindowSystem + Qt5::Xml + Qt5::DBus + Qt5::Widgets + Qt5::Concurrent + ${LIBRARIES} +) + +install(TARGETS ${PROJECT_NAME} RUNTIME DESTINATION bin) +install(FILES ${DESKTOP_FILES} DESTINATION ${CMAKE_INSTALL_PREFIX}/share/applications) diff --git a/lxqt-config-file-associations/applicationchooser.cpp b/lxqt-config-file-associations/applicationchooser.cpp new file mode 100644 index 0000000..57fdaa6 --- /dev/null +++ b/lxqt-config-file-associations/applicationchooser.cpp @@ -0,0 +1,194 @@ +/* BEGIN_COMMON_COPYRIGHT_HEADER + * (c)LGPL2+ + * + * LXQt - a lightweight, Qt based, desktop toolset + * http://razor-qt.org + * + * Copyright: 2013 Christian Surlykke + * + * This program or library is free software; you can redistribute it + * and/or modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + * + * END_COMMON_COPYRIGHT_HEADER */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include "applicationchooser.h" + +Q_DECLARE_METATYPE(XdgDesktopFile*) + +ApplicationChooser::ApplicationChooser(const XdgMimeType& mimeInfo, bool showUseAlwaysCheckBox) +{ + m_MimeInfo = mimeInfo; + m_CurrentDefaultApplication = XdgDesktopFileCache::getDefaultApp(m_MimeInfo.name()); + widget.setupUi(this); + + widget.mimetypeIconLabel->setPixmap(m_MimeInfo.icon().pixmap(widget.mimetypeIconLabel->size())); + widget.mimetypeLabel->setText(m_MimeInfo.comment()); + widget.alwaysUseCheckBox->setVisible(showUseAlwaysCheckBox); + widget.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); +} + +ApplicationChooser::~ApplicationChooser() +{ +} + +int ApplicationChooser::exec() +{ + show(); + fillApplicationListWidget(); + + return QDialog::exec(); +} + + + +bool lessThan(XdgDesktopFile* a, XdgDesktopFile* b) +{ + return a && b && a->name().toLower() < b->name().toLower(); +} + +void ApplicationChooser::updateAllIcons() { + // loading all icons is very time-consuming... + QCoreApplication::processEvents(); + QTreeWidget* tree = widget.applicationTreeWidget; + int updated = 0; + int top_n = tree->topLevelItemCount(); + for(int top_i = 0; top_i < top_n; ++top_i) { + QTreeWidgetItem* parent = tree->topLevelItem(top_i); + int n = parent->childCount(); + for(int i = 0; i < n; ++i) { + QTreeWidgetItem* item = parent->child(i); + XdgDesktopFile* desktopFile = item->data(0, 32).value(); + if(Q_LIKELY(desktopFile != NULL && !desktopFile->icon().isNull())) { + item->setIcon(0, desktopFile->icon()); + ++updated; + if(updated % 8 == 0) // update the UI in batch is more efficient + QCoreApplication::processEvents(); + } + } + } + QCoreApplication::processEvents(); +} + +void ApplicationChooser::fillApplicationListWidget() +{ + widget.applicationTreeWidget->clear(); + + QSet addedApps; + QList applicationsThatHandleThisMimetype = XdgDesktopFileCache::getApps(m_MimeInfo.name()); + QList otherApplications; + + QStringList mimetypes; + mimetypes << m_MimeInfo.name() << m_MimeInfo.allAncestors(); + + // Adding all apps takes some time. Make the user aware by setting the + // cursor to Wait. + QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); + QMimeDatabase db; + foreach(const QString& mts, mimetypes) { + QMimeType mt = db.mimeTypeForName(mts); + QString heading; + heading = mt.name() == QLatin1String("application/octet-stream") ? + tr("Other applications") : + tr("Applications that handle %1").arg(mt.comment()); + + QList applications; + applications = mt.name() == QLatin1String("application/octet-stream") ? + XdgDesktopFileCache::getAllFiles() : + XdgDesktopFileCache::getApps(mt.name()); + + qSort(applications.begin(), applications.end(), lessThan); + + QTreeWidgetItem* headingItem = new QTreeWidgetItem(widget.applicationTreeWidget); + headingItem->setExpanded(true); + headingItem->setFlags(Qt::ItemIsEnabled); + headingItem->setText(0, heading); + headingItem->setSizeHint(0, QSize(0, 25)); + + addApplicationsToApplicationListWidget(headingItem, applications, addedApps); + } + connect(widget.applicationTreeWidget, SIGNAL(currentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*)), this, SLOT(selectionChanged())); + widget.applicationTreeWidget->setFocus(); + + QApplication::restoreOverrideCursor(); + if (!applicationsThatHandleThisMimetype.isEmpty()) { + widget.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true); + } + + // delay icon update for faster loading + QTimer::singleShot(0, this, SLOT(updateAllIcons())); +} + +void ApplicationChooser::addApplicationsToApplicationListWidget(QTreeWidgetItem* parent, + QList applications, + QSet& alreadyAdded) +{ + QIcon placeHolderIcon = QIcon::fromTheme("application-x-executable"); + + if (applications.isEmpty()) + { + QTreeWidgetItem* noAppsFoundItem = new QTreeWidgetItem(parent); + noAppsFoundItem->setText(0, tr("No applications found")); + noAppsFoundItem->setFlags(0); + QFont font = noAppsFoundItem->font(0); + font.setStyle(QFont::StyleItalic); + noAppsFoundItem->setFont(0, font); + } + else + { + // Insert applications in the listwidget, skipping already added applications + foreach (XdgDesktopFile* desktopFile, applications) + { + if (alreadyAdded.contains(desktopFile)) + continue; + + // Only applications + if (desktopFile->type() != XdgDesktopFile::ApplicationType) + continue; + + QTreeWidgetItem *item = new QTreeWidgetItem(parent); + item->setIcon(0, placeHolderIcon); + item->setText(0, desktopFile->name()); + item->setData(0, 32, QVariant::fromValue(desktopFile)); + + if (desktopFile == m_CurrentDefaultApplication) + { + widget.applicationTreeWidget->setCurrentItem(item); + } + + alreadyAdded.insert(desktopFile); + } + } +} + +void ApplicationChooser::selectionChanged() +{ + widget.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); + + QTreeWidgetItem* newItem = widget.applicationTreeWidget->currentItem(); + if (newItem && newItem->data(0, 32).value()) + { + widget.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true); + m_CurrentDefaultApplication = newItem->data(0, 32).value(); + } +} diff --git a/lxqt-config-file-associations/applicationchooser.h b/lxqt-config-file-associations/applicationchooser.h new file mode 100644 index 0000000..3191163 --- /dev/null +++ b/lxqt-config-file-associations/applicationchooser.h @@ -0,0 +1,61 @@ +/* BEGIN_COMMON_COPYRIGHT_HEADER + * (c)LGPL2+ + * + * LXQt - a lightweight, Qt based, desktop toolset + * http://razor-qt.org + * + * Copyright: 2013 Christian Surlykke + * + * This program or library is free software; you can redistribute it + * and/or modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + * + * END_COMMON_COPYRIGHT_HEADER */ + +#ifndef _APPLICATIONCHOOSER_H +#define _APPLICATIONCHOOSER_H + +#include "ui_applicationchooser.h" +#include +#include + +class QSettings; + +class ApplicationChooser : public QDialog +{ + Q_OBJECT +public: + ApplicationChooser(const XdgMimeType& mimeInfo, bool showUseAlwaysCheckBox = false); + + virtual ~ApplicationChooser(); + XdgDesktopFile* DefaultApplication() const { return m_CurrentDefaultApplication; } + + virtual int exec(); + +private slots: + void selectionChanged(); + void updateAllIcons(); + +private: + void fillApplicationListWidget(); + + void addApplicationsToApplicationListWidget(QTreeWidgetItem* parent, + QList applications, + QSet & alreadyAdded); + XdgMimeType m_MimeInfo; + Ui::ApplicationChooser widget; + XdgDesktopFile* m_CurrentDefaultApplication; +}; + +#endif /* _APPLICATIONCHOOSER_H */ diff --git a/lxqt-config-file-associations/applicationchooser.ui b/lxqt-config-file-associations/applicationchooser.ui new file mode 100644 index 0000000..3015234 --- /dev/null +++ b/lxqt-config-file-associations/applicationchooser.ui @@ -0,0 +1,207 @@ + + + ApplicationChooser + + + + 0 + 0 + 385 + 417 + + + + ApplicationChooser + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + + + + 0 + 0 + + + + + 0 + 30 + + + + + 12 + + + + Pick an application for: + + + + + + + + 0 + 0 + + + + + 30 + 30 + + + + Icon + + + + + + + Mimetype + + + + + + + + + + + 240 + 200 + + + + QAbstractItemView::NoEditTriggers + + + false + + + QAbstractItemView::SelectRows + + + false + + + false + + + true + + + false + + + + 1 + + + + + Applications that handle JPEG + + + + + + + + + New Subitem + + + + + New Subitem + + + + + + Other applications + + + + New Subitem + + + + + New Subitem + + + + + + + + + + + + + + + + Qt::LeftToRight + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + ApplicationChooser + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + ApplicationChooser + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/lxqt-config-file-associations/lxqt-config-file-associations.desktop.in b/lxqt-config-file-associations/lxqt-config-file-associations.desktop.in new file mode 100644 index 0000000..ca8ecd0 --- /dev/null +++ b/lxqt-config-file-associations/lxqt-config-file-associations.desktop.in @@ -0,0 +1,11 @@ +[Desktop Entry] +Type=Application +Name=File Associations +GenericName=File Association Settings +Comment=Configure applications associated with known file types +Exec=lxqt-config-file-associations +Icon=preferences-desktop-filetype-association +Categories=Settings;DesktopSettings;Qt;LXQt; +OnlyShowIn=LXDE;LXQt; + +#TRANSLATIONS_DIR=translations diff --git a/lxqt-config-file-associations/main.cpp b/lxqt-config-file-associations/main.cpp new file mode 100644 index 0000000..9c2bfed --- /dev/null +++ b/lxqt-config-file-associations/main.cpp @@ -0,0 +1,53 @@ +/* BEGIN_COMMON_COPYRIGHT_HEADER + * (c)LGPL2+ + * + * LXQt - a lightweight, Qt based, desktop toolset + * http://razor-qt.org + * + * Copyright: 2013 Christian Surlykke + * + * This program or library is free software; you can redistribute it + * and/or modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + * + * END_COMMON_COPYRIGHT_HEADER */ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include "mimetypeviewer.h" +#include + +int main (int argc, char **argv) +{ + LxQt::SingleApplication app(argc, argv); + + MimetypeViewer mimetypeViewer; + app.setActivationWindow(&mimetypeViewer); + mimetypeViewer.setWindowIcon(QIcon::fromTheme("preferences-desktop-filetype-association")); + mimetypeViewer.show(); + + return app.exec(); + qDebug() << "Efter exec"; +} + diff --git a/lxqt-config-file-associations/mimetypedata.cpp b/lxqt-config-file-associations/mimetypedata.cpp new file mode 100644 index 0000000..8967796 --- /dev/null +++ b/lxqt-config-file-associations/mimetypedata.cpp @@ -0,0 +1,52 @@ +/* BEGIN_COMMON_COPYRIGHT_HEADER + * (c)LGPL2+ + * + * LXQt - a lightweight, Qt based, desktop toolset + * http://lxqt.org + * + * Copyright: 2014 LXQt team + * Authors: + * Luís Pereira + * + * This program or library is free software; you can redistribute it + * and/or modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + * + * END_COMMON_COPYRIGHT_HEADER */ + + +#include "mimetypedata.h" + +MimeTypeData::MimeTypeData() +{ +} + + +MimeTypeData::MimeTypeData(const XdgMimeType& mime) +{ + mName = mime.name(); + mPatterns = mime.globPatterns().join(" "); + mComment = mime.comment(); +} + + +bool MimeTypeData::matches(const QString &filter) const +{ + if (mName.contains(filter) || mPatterns.contains(filter) || + mComment.contains(filter)) { + return true; + } else { + return false; + } +} diff --git a/lxqt-config-file-associations/mimetypedata.h b/lxqt-config-file-associations/mimetypedata.h new file mode 100644 index 0000000..47f33bc --- /dev/null +++ b/lxqt-config-file-associations/mimetypedata.h @@ -0,0 +1,54 @@ +/* BEGIN_COMMON_COPYRIGHT_HEADER + * (c)LGPL2+ + * + * LXQt - a lightweight, Qt based, desktop toolset + * http://lxqt.org + * + * Copyright: 2014 LXQt team + * Authors: + * Luís Pereira + * + * This program or library is free software; you can redistribute it + * and/or modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + * + * END_COMMON_COPYRIGHT_HEADER */ + + +#ifndef MIMETYPEDATA_H +#define MIMETYPEDATA_H + +#include +#include + + +class MimeTypeData { +public: + MimeTypeData(); + MimeTypeData(const XdgMimeType& mime); + + QString inline name() const { return mName; }; + QString inline patterns() const { return mPatterns; }; + QString inline comment() const { return mComment; }; + + bool matches(const QString& filter) const; + +private: + QString mName; + QString mPatterns; + QString mComment; +}; + +Q_DECLARE_METATYPE(MimeTypeData) +#endif // MIMETYPEDATA_H diff --git a/lxqt-config-file-associations/mimetypeitemmodel.cpp b/lxqt-config-file-associations/mimetypeitemmodel.cpp new file mode 100644 index 0000000..5c0bd2e --- /dev/null +++ b/lxqt-config-file-associations/mimetypeitemmodel.cpp @@ -0,0 +1,197 @@ +/* + * File: MimetypeItemModel.cpp + * Author: christian + * + * Created on 5. maj 2013, 09:18 + */ +#include +#include + +#include "mimetypeitemmodel.h" +#include + +/* + * Implementation note: + * + * MimetypeItemModel is an implementation of QAbstractItemModel with XdgMimeInfoCache as backing store. + * + * There are 2 levels of items in this model: mediatype ('application', 'audio', 'image' etc.) and + * subtype ('application/pdf' which is a child of 'application' or 'image/jpeg' which is a child of 'image'. + * + * A QModelIndex for a mediatype has a zero internal pointer. + * + * A QModelIndex for a subtype has an internal pointer to the XdgMimeInfo for that subtype - so the QModelIndex for + * 'image/jpeg' has an internal pointer that points to the XdgMineInfo for 'image/jpeg' which is held in XdgMimeInfoCache. + * + * QModelIndexes for mediatypes have no parents, and QModelIndexes for subtypes have no children. + */ + + +MimetypeItemModel::MimetypeItemModel(QObject *parent) : +QAbstractItemModel(parent) +{ +} + +MimetypeItemModel::~MimetypeItemModel() +{ +} + +QVariant MimetypeItemModel::data(const QModelIndex& index, int role) const +{ + if (!index.isValid()) + { + return QVariant(); + } + + XdgMimeInfo *mimeInfo = 0; + QString text; + + if (index.parent().isValid()) + { + mimeInfo = static_cast(index.internalPointer()); + text = mimeInfo->subType(); + } + else + { + text = XdgMimeInfoCache::mediatypes().value(index.row()); + } + + switch (role) + { + case Qt::DisplayRole : return QVariant(text); + case MimeInfoRole : return QVariant::fromValue(mimeInfo); + default : return QVariant(); + } +} + +QModelIndex MimetypeItemModel::index(int row, int column, const QModelIndex& parent) const +{ + if (column != 0) + { + return QModelIndex(); + } + + if (parent.isValid()) + { + if (parent.row() >= XdgMimeInfoCache::mediatypes().size()) + { + return QModelIndex(); + } + + QString mediatype = XdgMimeInfoCache::mediatypes().value(parent.row()); + + if (row >= XdgMimeInfoCache::subtypes(mediatype).size()) + { + return QModelIndex(); + } + + QString subtype = XdgMimeInfoCache::subtypes(mediatype).value(row); + + XdgMimeInfo* mimeInfo = XdgMimeInfoCache::xdgMimeInfo(mediatype, subtype); + return createIndex(row, 0, mimeInfo); + } + else + { + if (row >= XdgMimeInfoCache::mediatypes().size()) + { + return QModelIndex(); + } + + return createIndex(row, 0); + } +} + +QModelIndex MimetypeItemModel::parent(const QModelIndex& index) const +{ + if (index.isValid() && index.internalPointer()) + { + XdgMimeInfo* mimeInfo = static_cast(index.internalPointer()); + + int row = XdgMimeInfoCache::mediatypes().indexOf(mimeInfo->mediaType()); + return createIndex(row, 0); + } + else + { + return QModelIndex(); + } +} + + +int MimetypeItemModel::rowCount(const QModelIndex& parent) const +{ + if (parent.column() > 0) + { + return 0; + } + + if (parent.parent().isValid()) + { + return 0; + } + else if (parent.isValid()) + { + QString media = XdgMimeInfoCache::mediatypes().value(parent.row()); + return XdgMimeInfoCache::subtypes(media).size(); + } + else + { + return XdgMimeInfoCache::mediatypes().size(); + } +} + + +MimetypeFilterItemModel::MimetypeFilterItemModel(QObject* parent) : + QSortFilterProxyModel(parent) +{ +} + +bool MimetypeFilterItemModel::filterAcceptsRow(int source_row, const QModelIndex& source_parent) const +{ + QModelIndex index = sourceModel()->index(source_row, 0, source_parent); + + if (source_parent.isValid()) + { + return filterHelper(index); + } + else + { + for (int i = 0; i < sourceModel()->rowCount(index); i++) + { + if (filterAcceptsRow(i, index)) + { + return true; + } + } + } + + return false; +} + +bool MimetypeFilterItemModel::filterHelper(QModelIndex& source_index) const +{ + XdgMimeInfo* mimeInfo = source_index.data(MimeInfoRole).value(); + if (!mimeInfo) + { + return false; + } + + if (mimeInfo->mimeType().contains(filterRegExp())) + { + return true; + } + + if (mimeInfo->comment().contains(filterRegExp())) + { + return true; + } + + foreach (const QString pattern, mimeInfo->patterns()) + { + if (pattern.contains(filterRegExp())) + { + return true; + } + } + + return false; +} diff --git a/lxqt-config-file-associations/mimetypeitemmodel.h b/lxqt-config-file-associations/mimetypeitemmodel.h new file mode 100644 index 0000000..940ea9e --- /dev/null +++ b/lxqt-config-file-associations/mimetypeitemmodel.h @@ -0,0 +1,49 @@ +/* + * File: MimetypeItemModel.h + * Author: christian + * + * Created on 5. maj 2013, 09:18 + */ + +#ifndef MIMETYPEITEMMODEL_H +#define MIMETYPEITEMMODEL_H + +#include +#include + +#include + +// Used for MimetypeItemModel::data to return a QVariant wrapping an XdgMimeInfo* +#define MimeInfoRole 32 + +Q_DECLARE_METATYPE(XdgMimeInfo*) + +/*! + * + */ +class MimetypeItemModel : public QAbstractItemModel +{ +public: + MimetypeItemModel(QObject *parent = 0); + virtual ~MimetypeItemModel(); + + QVariant data(const QModelIndex &index, int role) const; + QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const; + QModelIndex parent(const QModelIndex &index) const; + int rowCount(const QModelIndex &parent = QModelIndex()) const; + int columnCount(const QModelIndex &parent = QModelIndex()) const {return 1;} +}; + +class MimetypeFilterItemModel : public QSortFilterProxyModel +{ +public: + MimetypeFilterItemModel(QObject *parent = 0); + + bool filterAcceptsRow(int source_row, const QModelIndex& source_parent) const; + + bool filterHelper(QModelIndex& source_index) const; +}; + + +#endif /* MIMETYPEITEMMODEL_H */ + diff --git a/lxqt-config-file-associations/mimetypeviewer.cpp b/lxqt-config-file-associations/mimetypeviewer.cpp new file mode 100644 index 0000000..4a7bac0 --- /dev/null +++ b/lxqt-config-file-associations/mimetypeviewer.cpp @@ -0,0 +1,271 @@ +/* BEGIN_COMMON_COPYRIGHT_HEADER + * (c)LGPL2+ + * + * LXQt - a lightweight, Qt based, desktop toolset + * http://razor-qt.org + * + * Copyright: 2013 Christian Surlykke + * 2014 Luís Pereira + * + * This program or library is free software; you can redistribute it + * and/or modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + * + * END_COMMON_COPYRIGHT_HEADER */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + + +#include "mimetypeviewer.h" +#include "ui_mimetypeviewer.h" + +#include "applicationchooser.h" + + +enum ItemTypeEntries { + GroupType = 1001, + EntrieType = 1002 +}; + +static bool mimeTypeLessThan(const QMimeType& m1, const QMimeType& m2) +{ + return m1.name() < m2.name(); +} + +void MimetypeViewer::loadAllMimeTypes() +{ + mediaTypes.clear(); + mGroupItems.clear(); + mItemList.clear(); + QStringList selectedMimeTypes; + + QMimeDatabase db; + QList mimetypes = db.allMimeTypes(); + + qSort(mimetypes.begin(), mimetypes.end(), mimeTypeLessThan); + foreach (const QMimeType &mt, mimetypes) { + const QString mimetype = mt.name(); + const int i = mimetype.indexOf(QLatin1Char('/')); + const QString mediaType = mimetype.left(i); + const QString subType = mimetype.mid(i + 1); + + MimeTypeData* data = new MimeTypeData(mt); + + if (!mediaTypes.contains(mediaType)) { // A new type of media + mediaTypes.append(mediaType); + QTreeWidgetItem *item = new QTreeWidgetItem(widget.mimetypeTreeWidget, GroupType); + item->setText(0, mediaType); + widget.mimetypeTreeWidget->insertTopLevelItem(0, item); + mGroupItems.insert(mediaType, item); + } + QTreeWidgetItem *item = new QTreeWidgetItem(mGroupItems.value(mediaType), EntrieType); + QVariant v; + v.setValue(*data); + item->setData(0, Qt::UserRole, v); + item->setText(0, subType); + mItemList.append(item); + } + + widget.mimetypeTreeWidget->resizeColumnToContents(1); + widget.mimetypeTreeWidget->show(); +} + + +MimetypeViewer::MimetypeViewer(QWidget *parent) + : QDialog(parent) +{ + widget.setupUi(this); + addSearchIcon(); + widget.searchTermLineEdit->setEnabled(false); + + connect(widget.searchTermLineEdit, SIGNAL(textChanged(const QString&)), + this, SLOT(filter(const QString&))); + + connect(widget.chooseApplicationsButton, SIGNAL(clicked()), this, SLOT(chooseApplication())); + connect(widget.dialogButtonBox, SIGNAL(clicked(QAbstractButton*)), this, SLOT(dialogButtonBoxClicked(QAbstractButton*))); + + QString mimeappsListPath(XdgDirs::dataHome(true) + "/applications/mimeapps.list"); + mDefaultsList = new QSettings(mimeappsListPath, XdgDesktopFileCache::desktopFileSettingsFormat(), this); + mSettingsCache = new LxQt::SettingsCache(mDefaultsList); + mSettingsCache->loadFromSettings(); + initializeMimetypeTreeView(); + loadAllMimeTypes(); + + connect(widget.mimetypeTreeWidget, SIGNAL(itemSelectionChanged()), + this, SLOT(currentMimetypeChanged())); +} + +MimetypeViewer::~MimetypeViewer() +{ +} + +void MimetypeViewer::addSearchIcon() +{ + QIcon searchIcon = QIcon::fromTheme("system-search"); + if (searchIcon.isNull()) + return; + + widget.searchTermLineEdit->setTextMargins(0, 0, 30, 0); + QHBoxLayout *hBoxLayout = new QHBoxLayout(widget.searchTermLineEdit); + hBoxLayout->setContentsMargins(0,0,0,0); + widget.searchTermLineEdit->setLayout(hBoxLayout); + QLabel *searchIconLabel = new QLabel(widget.searchTermLineEdit); + searchIconLabel->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter); + searchIconLabel->setMinimumHeight(30); + searchIconLabel->setMinimumWidth(30); + + searchIconLabel->setPixmap(searchIcon.pixmap(QSize(20,20))); + hBoxLayout->addWidget(searchIconLabel, 0, Qt::AlignRight | Qt::AlignVCenter); +} + + +void MimetypeViewer::initializeMimetypeTreeView() +{ + currentMimetypeChanged(); + widget.mimetypeTreeWidget->setColumnCount(2); + widget.mimetypeTreeWidget->setFocus(); + widget.searchTermLineEdit->setEnabled(true); +} + +void MimetypeViewer::currentMimetypeChanged() +{ + widget.iconLabel->hide(); + widget.descriptionLabel->setText(tr("None")); + widget.mimetypeGroupBox->setEnabled(false); + + widget.patternsLabel->clear(); + widget.patternsGroupBox->setEnabled(false); + + widget.appIcon->hide(); + widget.applicationLabel->clear(); + widget.applicationsGroupBox->setEnabled(false); + + QTreeWidgetItem *sel = widget.mimetypeTreeWidget->currentItem(); + + if (!sel || sel->type() == GroupType) { + return; + } + + MimeTypeData mimeData = sel->data(0, Qt::UserRole).value(); + + QMimeDatabase db; + XdgMimeType mt = db.mimeTypeForName(mimeData.name()); + if (mt.name().isEmpty()) + return; + + m_CurrentMime = mt; + + widget.descriptionLabel->setText(mimeData.comment()); + + QIcon icon = m_CurrentMime.icon(); + if (! icon.isNull()) + { + widget.iconLabel->setPixmap(icon.pixmap(widget.iconLabel->size())); + widget.iconLabel->show(); + } + + widget.mimetypeGroupBox->setEnabled(true); + widget.patternsLabel->setText(mimeData.patterns()); + widget.patternsGroupBox->setEnabled(true); + + XdgDesktopFile* defaultApp = XdgDesktopFileCache::getDefaultApp(m_CurrentMime.name()); + if (defaultApp && defaultApp->isValid()) + { + QString nonLocalizedName = defaultApp->value("Name").toString(); + QString localizedName = defaultApp->localizedValue("Name", nonLocalizedName).toString(); + QIcon appIcon = defaultApp->icon(); + widget.appIcon->setPixmap(appIcon.pixmap(widget.iconLabel->size())); + widget.appIcon->show(); + widget.applicationLabel->setText(localizedName); + widget.chooseApplicationsButton->setText(tr("&Change...")); + } + else + { + widget.applicationLabel->setText(tr("None")); + widget.chooseApplicationsButton->setText(tr("&Choose...")); + } + + widget.applicationsGroupBox->setEnabled(true); + +} + +void MimetypeViewer::filter(const QString& pattern) +{ + QMimeDatabase db; + MimeTypeData mimeData; + const int count = widget.mimetypeTreeWidget->topLevelItemCount(); + + for (int i = 0; i < widget.mimetypeTreeWidget->topLevelItemCount(); ++i) { + widget.mimetypeTreeWidget->topLevelItem(i)->setHidden(true); + } + + foreach(QTreeWidgetItem* it, mItemList) { + mimeData = it->data(0, Qt::UserRole).value(); + if (pattern.isEmpty() || mimeData.matches(pattern)) { + const int i = mimeData.name().indexOf(QLatin1Char('/')); + const QString mediaType = mimeData.name().left(i); + QTreeWidgetItem* groupItem = mGroupItems.value(mediaType); + Q_ASSERT(groupItem); + if (groupItem) { + groupItem->setHidden(false); + it->setHidden(false); + } + } else { + it->setHidden(true); + } + } +} + + +void MimetypeViewer::chooseApplication() +{ + ApplicationChooser applicationChooser(m_CurrentMime); + if (applicationChooser.exec() == QDialog::Accepted && applicationChooser.DefaultApplication()) + { + QString fileNameNoPath = QFileInfo(applicationChooser.DefaultApplication()->fileName()).fileName(); + mDefaultsList->beginGroup("Default Applications"); + mDefaultsList->setValue(m_CurrentMime.name(), fileNameNoPath); + mDefaultsList->endGroup(); + currentMimetypeChanged(); + } + widget.mimetypeTreeWidget->setFocus(); +} + +void MimetypeViewer::dialogButtonBoxClicked(QAbstractButton* button) +{ + QDialogButtonBox::ButtonRole role = widget.dialogButtonBox->buttonRole(button); + if (role == QDialogButtonBox::ResetRole) + { + mSettingsCache->loadToSettings(); + currentMimetypeChanged(); + } + else + { + close(); + } +} + diff --git a/lxqt-config-file-associations/mimetypeviewer.h b/lxqt-config-file-associations/mimetypeviewer.h new file mode 100644 index 0000000..7474f2f --- /dev/null +++ b/lxqt-config-file-associations/mimetypeviewer.h @@ -0,0 +1,69 @@ +/* BEGIN_COMMON_COPYRIGHT_HEADER + * (c)LGPL2+ + * + * LXQt - a lightweight, Qt based, desktop toolset + * http://razor-qt.org + * + * Copyright: 2013 Christian Surlykke + * 2014 Luís Pereira + * + * This program or library is free software; you can redistribute it + * and/or modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + * + * END_COMMON_COPYRIGHT_HEADER */ + +#ifndef _MIMETYPEVIEWER_H +#define _MIMETYPEVIEWER_H + +#include +#include + +#include + +#include "mimetypedata.h" +#include "ui_mimetypeviewer.h" + +class QSettings; + +namespace LxQt { +class SettingsCache; +} + +class MimetypeViewer : public QDialog { + Q_OBJECT +public: + MimetypeViewer(QWidget *parent = 0); + virtual ~MimetypeViewer(); + +private slots: + void initializeMimetypeTreeView(); + void currentMimetypeChanged(); + void filter(const QString&); + void chooseApplication(); + void dialogButtonBoxClicked(QAbstractButton *button); + +private: + void addSearchIcon(); + void loadAllMimeTypes(); + XdgMimeType m_CurrentMime; + QSettings* mDefaultsList; + LxQt::SettingsCache *mSettingsCache; + Ui::mimetypeviewer widget; + QStringList mediaTypes; + QList mItemList; + QMap mGroupItems; +}; + +#endif /* _MIMETYPEVIEWER_H */ diff --git a/lxqt-config-file-associations/mimetypeviewer.ui b/lxqt-config-file-associations/mimetypeviewer.ui new file mode 100644 index 0000000..2d1daa0 --- /dev/null +++ b/lxqt-config-file-associations/mimetypeviewer.ui @@ -0,0 +1,275 @@ + + + mimetypeviewer + + + + 0 + 0 + 565 + 370 + + + + + 530 + 370 + + + + File Associations + + + + + + true + + + + 0 + 0 + + + + + 280 + 260 + + + + QFrame::NoFrame + + + QFrame::Plain + + + + + 10 + 170 + 260 + 140 + + + + Default application + + + + + 140 + 90 + 110 + 30 + + + + &Choose... + + + + + + 10 + 20 + 241 + 51 + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + + 50 + 50 + + + + TextLabel + + + + + + + None + + + 10 + + + + + + + + + + 10 + 100 + 260 + 60 + + + + Patterns + + + + + 10 + 20 + 230 + 30 + + + + *.txt *.xml + + + true + + + + + + + 10 + 0 + 260 + 90 + + + + MIME type + + + + + + + 0 + 0 + + + + + 50 + 50 + + + + Icon + + + + + + + Description + + + true + + + + + + + + + + + + 0 + 30 + + + + + + + + + + + QDialogButtonBox::Close|QDialogButtonBox::Reset + + + + + + + + 0 + 0 + + + + + 180 + 275 + + + + QAbstractItemView::NoEditTriggers + + + false + + + true + + + false + + + 0 + + + false + + + 500 + + + + + + + searchTermLineEdit + mimetypeTreeWidget + chooseApplicationsButton + + + + diff --git a/lxqt-config-file-associations/translations/lxqt-config-file-associations.ts b/lxqt-config-file-associations/translations/lxqt-config-file-associations.ts new file mode 100644 index 0000000..3e2de58 --- /dev/null +++ b/lxqt-config-file-associations/translations/lxqt-config-file-associations.ts @@ -0,0 +1,123 @@ + + + + + ApplicationChooser + + + ApplicationChooser + + + + + Pick an application for: + + + + + 1 + + + + + Applications that handle JPEG + + + + + + + + New Subitem + + + + + + Other applications + + + + + Applications that handle %1 + + + + + No applications found + + + + + MimetypeViewer + + + + None + + + + + &Change... + + + + + &Choose... + + + + + mimetypeviewer + + + File Associations + + + + + Default application + + + + + &Choose... + + + + + TextLabel + + + + + None + + + + + Patterns + + + + + *.txt *.xml + + + + + MIME type + + + + + Icon + + + + + Description + + + + diff --git a/lxqt-config-file-associations/translations/lxqt-config-file-associations_de.desktop b/lxqt-config-file-associations/translations/lxqt-config-file-associations_de.desktop new file mode 100644 index 0000000..8c8ae89 --- /dev/null +++ b/lxqt-config-file-associations/translations/lxqt-config-file-associations_de.desktop @@ -0,0 +1,4 @@ +# Translations +Name[de]=Dateizuordnungen +GenericName[de]=Setzen von Dateizuordnungen +Comment[de]=Zuordnen von Dateitypen zu Anwendungsprogrammen diff --git a/lxqt-config-file-associations/translations/lxqt-config-file-associations_de.ts b/lxqt-config-file-associations/translations/lxqt-config-file-associations_de.ts new file mode 100644 index 0000000..cda850a --- /dev/null +++ b/lxqt-config-file-associations/translations/lxqt-config-file-associations_de.ts @@ -0,0 +1,123 @@ + + + + + ApplicationChooser + + + ApplicationChooser + Dateizuordnungen + + + + Pick an application for: + Anwendung auswählen für: + + + + 1 + 1 + + + + Applications that handle JPEG + Anwendungen die JPEG verarbeiten + + + + + + + New Subitem + Neuer Unterpunkt + + + + + Other applications + Andere Anwendung + + + + Applications that handle %1 + Anwendungen die %1 verarbeiten + + + + No applications found + Keine Anwendung gefunden + + + + MimetypeViewer + + + + None + Keine + + + + &Change... + Ä&ndern... + + + + &Choose... + &Auswählen... + + + + mimetypeviewer + + + File Associations + Dateizuordnungen + + + + Default application + Default-Anwendungsprogramm + + + + &Choose... + &Auswählen... + + + + TextLabel + Textfeld + + + + None + Keins + + + + Patterns + Dateimuster + + + + *.txt *.xml + *.txt *.xml + + + + MIME type + MIME-Typ + + + + Icon + Symbol + + + + Description + Beschreibung + + + diff --git a/lxqt-config-file-associations/translations/lxqt-config-file-associations_it.ts b/lxqt-config-file-associations/translations/lxqt-config-file-associations_it.ts new file mode 100644 index 0000000..efc59c1 --- /dev/null +++ b/lxqt-config-file-associations/translations/lxqt-config-file-associations_it.ts @@ -0,0 +1,123 @@ + + + + + ApplicationChooser + + + ApplicationChooser + Applicazioni predefinite + + + + Pick an application for: + Scegli un applicazione per: + + + + 1 + 1 + + + + Applications that handle JPEG + Applicazioni che possono gestire JPEG + + + + + + + New Subitem + + + + + + Other applications + Altre applicazioni + + + + Applications that handle %1 + Applicazioni che possono gestire %1 + + + + No applications found + Nessuna applicazione trovata + + + + MimetypeViewer + + + + None + Nessuno + + + + &Change... + &Cambia... + + + + &Choose... + &Scegli... + + + + mimetypeviewer + + + File Associations + Associazioni file + + + + Default application + Applicazione predefinita + + + + &Choose... + &Scegli... + + + + TextLabel + + + + + None + + + + + Patterns + Tipi di file + + + + *.txt *.xml + + + + + MIME type + Tipo MIME + + + + Icon + Icona + + + + Description + Descrizione + + + diff --git a/lxqt-config-file-associations/translations/lxqt-config-file-associations_ja.desktop b/lxqt-config-file-associations/translations/lxqt-config-file-associations_ja.desktop new file mode 100644 index 0000000..8213df7 --- /dev/null +++ b/lxqt-config-file-associations/translations/lxqt-config-file-associations_ja.desktop @@ -0,0 +1,4 @@ +# Translations +Comment[ja]=既知のファイル種類に対するアプリケーション関連付けの設定 +GenericName[ja]=ファイル関連付けの設定 +Name[ja]=ファイル関連付け diff --git a/lxqt-config-file-associations/translations/lxqt-config-file-associations_ja.ts b/lxqt-config-file-associations/translations/lxqt-config-file-associations_ja.ts new file mode 100644 index 0000000..2e2935b --- /dev/null +++ b/lxqt-config-file-associations/translations/lxqt-config-file-associations_ja.ts @@ -0,0 +1,123 @@ + + + + + ApplicationChooser + + + ApplicationChooser + アプリケーションの関連付け + + + + Pick an application for: + このファイルを開くアプリケーション: + + + + 1 + 1 + + + + Applications that handle JPEG + JPEGを扱うアプリケーション + + + + + + + New Subitem + 新しいサブアイテム + + + + + Other applications + その他のアプリケーション + + + + Applications that handle %1 + %1 を扱うアプリケーション + + + + No applications found + アプリケーションが見つかりませんでした + + + + MimetypeViewer + + + + None + なし + + + + &Change... + 変更(&C) + + + + &Choose... + 選択(&C) + + + + mimetypeviewer + + + File Associations + ファイルの関連付け + + + + Default application + デフォルトのアプリケーション + + + + &Choose... + 選択(&C) + + + + TextLabel + テキストラベル + + + + None + なし + + + + Patterns + パターン + + + + *.txt *.xml + *.txt *.xml + + + + MIME type + MIMEタイプ + + + + Icon + アイコン + + + + Description + 説明 + + + diff --git a/lxqt-config-file-associations/translations/lxqt-config-file-associations_pt.desktop b/lxqt-config-file-associations/translations/lxqt-config-file-associations_pt.desktop new file mode 100644 index 0000000..49ffd2a --- /dev/null +++ b/lxqt-config-file-associations/translations/lxqt-config-file-associations_pt.desktop @@ -0,0 +1,4 @@ +# Translations +Name[pt]=Associação de ficheiros +GenericName[pt]=Definições de associação de ficheiros +Comment[pt]=Configurar associação de ficheiros para os tipos de ficheiro conhecidos diff --git a/lxqt-config-file-associations/translations/lxqt-config-file-associations_pt.ts b/lxqt-config-file-associations/translations/lxqt-config-file-associations_pt.ts new file mode 100644 index 0000000..33e260e --- /dev/null +++ b/lxqt-config-file-associations/translations/lxqt-config-file-associations_pt.ts @@ -0,0 +1,123 @@ + + + + + ApplicationChooser + + + ApplicationChooser + Seletor de aplicações + + + + Pick an application for: + Escolha uma aplicação para: + + + + 1 + 1 + + + + Applications that handle JPEG + Aplicações para manipular JPEG + + + + + + + New Subitem + Novo subitem + + + + + Other applications + Outras aplicações + + + + Applications that handle %1 + Aplicações para manipular %1 + + + + No applications found + Nenhuma aplicação encontrada + + + + MimetypeViewer + + + + None + Nenhum + + + + &Change... + &Mudar... + + + + &Choose... + Es&colher... + + + + mimetypeviewer + + + File Associations + Associação de ficheiros + + + + Default application + Aplicaçao pré-definida + + + + &Choose... + Es&colher... + + + + TextLabel + Etiqueta + + + + None + Nenhuma + + + + Patterns + Padrões + + + + *.txt *.xml + *.txt *.xml + + + + MIME type + Tipo MIME + + + + Icon + Ícone + + + + Description + Descrição + + + diff --git a/lxqt-config-file-associations/translations/lxqt-config-file-associations_ru.desktop b/lxqt-config-file-associations/translations/lxqt-config-file-associations_ru.desktop new file mode 100644 index 0000000..2024701 --- /dev/null +++ b/lxqt-config-file-associations/translations/lxqt-config-file-associations_ru.desktop @@ -0,0 +1,4 @@ +# Translations +Comment[ru]=Настроить приложения ассоциированные с известным типом файлв +GenericName[ru]=Настройки ассоциации файлов +Name[ru]=Ассоциация файлов \ No newline at end of file diff --git a/lxqt-config-file-associations/translations/lxqt-config-file-associations_ru.ts b/lxqt-config-file-associations/translations/lxqt-config-file-associations_ru.ts new file mode 100644 index 0000000..616ea7f --- /dev/null +++ b/lxqt-config-file-associations/translations/lxqt-config-file-associations_ru.ts @@ -0,0 +1,123 @@ + + + + + ApplicationChooser + + + ApplicationChooser + Выбор приложения + + + + Pick an application for: + Выбрать приложение для: + + + + 1 + + + + + Applications that handle JPEG + Приложения, которые поддерживают JPEG + + + + + + + New Subitem + + + + + + Other applications + Другие приложения + + + + Applications that handle %1 + Приложение, которое поддерживает %1 + + + + No applications found + Не найдены приложения + + + + MimetypeViewer + + + + None + Нет + + + + &Change... + &Изменить... + + + + &Choose... + &Выбрать... + + + + mimetypeviewer + + + File Associations + Ассоциация файлов + + + + Default application + Приложение по умолчанию + + + + &Choose... + &Выбрать... + + + + TextLabel + + + + + None + Нет + + + + Patterns + Шаблоны + + + + *.txt *.xml + + + + + MIME type + MIME-тип + + + + Icon + Значок + + + + Description + Описание + + + diff --git a/lxqt-config-file-associations/translations/lxqt-config-file-associations_ru_RU.desktop b/lxqt-config-file-associations/translations/lxqt-config-file-associations_ru_RU.desktop new file mode 100644 index 0000000..d4fe06e --- /dev/null +++ b/lxqt-config-file-associations/translations/lxqt-config-file-associations_ru_RU.desktop @@ -0,0 +1,4 @@ +# Translations +Comment[ru_RU]=Настроить приложения ассоциированные с известным типом файлв +GenericName[ru_RU]=Настройки ассоциации файлов +Name[ru_RU]=Ассоциация файлов \ No newline at end of file diff --git a/lxqt-config-file-associations/translations/lxqt-config-file-associations_ru_RU.ts b/lxqt-config-file-associations/translations/lxqt-config-file-associations_ru_RU.ts new file mode 100644 index 0000000..616ea7f --- /dev/null +++ b/lxqt-config-file-associations/translations/lxqt-config-file-associations_ru_RU.ts @@ -0,0 +1,123 @@ + + + + + ApplicationChooser + + + ApplicationChooser + Выбор приложения + + + + Pick an application for: + Выбрать приложение для: + + + + 1 + + + + + Applications that handle JPEG + Приложения, которые поддерживают JPEG + + + + + + + New Subitem + + + + + + Other applications + Другие приложения + + + + Applications that handle %1 + Приложение, которое поддерживает %1 + + + + No applications found + Не найдены приложения + + + + MimetypeViewer + + + + None + Нет + + + + &Change... + &Изменить... + + + + &Choose... + &Выбрать... + + + + mimetypeviewer + + + File Associations + Ассоциация файлов + + + + Default application + Приложение по умолчанию + + + + &Choose... + &Выбрать... + + + + TextLabel + + + + + None + Нет + + + + Patterns + Шаблоны + + + + *.txt *.xml + + + + + MIME type + MIME-тип + + + + Icon + Значок + + + + Description + Описание + + + diff --git a/lxqt-config-input/CMakeLists.txt b/lxqt-config-input/CMakeLists.txt new file mode 100644 index 0000000..5066be4 --- /dev/null +++ b/lxqt-config-input/CMakeLists.txt @@ -0,0 +1,80 @@ +project(lxqt-config-input) +find_package(X11 REQUIRED) + +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-exceptions") + + +include_directories( + ${X11_INCLUDE_DIR} + ${LXQT_INCLUDE_DIRS} + ${CMAKE_CURRENT_BINARY_DIR} + "${CMAKE_SOURCE_DIR}/liblxqt-config-cursor" + "${CMAKE_BINARY_DIR}/liblxqt-config-cursor" +) + +set(lxqt-config-input_HDRS + keyboardconfig.h + mouseconfig.h + mouseconfig.h + keyboardlayoutconfig.h + selectkeyboardlayoutdialog.h +) + +set(lxqt-config-input_SRCS + lxqt-config-input.cpp + keyboardconfig.cpp + mouseconfig.cpp + keyboardlayoutconfig.cpp + selectkeyboardlayoutdialog.cpp +) + +set(lxqt-config-input_UIS + mouseconfig.ui + keyboardconfig.ui + keyboardlayoutconfig.ui + selectkeyboardlayoutdialog.ui +) + +qt5_wrap_ui(lxqt-config-input_UI_H ${lxqt-config-input_UIS}) + +# Translations ********************************** +lxqt_translate_ts(QM_FILES + UPDATE_TRANSLATIONS + ${UPDATE_TRANSLATIONS} + SOURCES + ${lxqt-config-input_HDRS} + ${lxqt-config-input_SRCS} + ${lxqt-config-input_UIS} + INSTALL_DIR + "${LXQT_TRANSLATIONS_DIR}/${PROJECT_NAME}" +) + +lxqt_app_translation_loader(QM_LOADER ${PROJECT_NAME}) +lxqt_translate_desktop(DESKTOP_FILES SOURCES ${PROJECT_NAME}.desktop.in) + +#************************************************ + +add_definitions( + -DPACKAGE_DATA_DIR="${CMAKE_INSTALL_PREFIX}/share/lxqt-config-input" +) + +add_executable(lxqt-config-input + ${lxqt-config-input_SRCS} + ${lxqt-config-input_UI_H} + ${lxqt-config-input_MOCS} + ${DESKTOP_FILES} + ${QM_FILES} + ${QM_LOADER} +) + +target_link_libraries(lxqt-config-input + KF5::WindowSystem + Qt5::Widgets + Qt5::X11Extras + ${X11_LIBRARIES} + ${LXQT_LIBRARIES} + lxqt-config-cursor +) + +install(TARGETS lxqt-config-input RUNTIME DESTINATION bin) +install(FILES ${DESKTOP_FILES} DESTINATION "${CMAKE_INSTALL_PREFIX}/share/applications") diff --git a/lxqt-config-input/data/input-keyboard.png b/lxqt-config-input/data/input-keyboard.png new file mode 100644 index 0000000..80d8774 Binary files /dev/null and b/lxqt-config-input/data/input-keyboard.png differ diff --git a/lxqt-config-input/data/input-mouse.png b/lxqt-config-input/data/input-mouse.png new file mode 100644 index 0000000..50c4cf6 Binary files /dev/null and b/lxqt-config-input/data/input-mouse.png differ diff --git a/lxqt-config-input/keyboardconfig.cpp b/lxqt-config-input/keyboardconfig.cpp new file mode 100644 index 0000000..3f77f55 --- /dev/null +++ b/lxqt-config-input/keyboardconfig.cpp @@ -0,0 +1,140 @@ +/* + Copyright (C) 2013-2014 Hong Jen Yee (PCMan) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + + +#include "keyboardconfig.h" +#include +#include +#include +#include +#include +#include +#include + +// FIXME: how to support XCB or Wayland? +#include +#include +#include + +#ifdef Q_WS_X11 +extern void qt_x11_apply_settings_in_all_apps(); +#endif + +KeyboardConfig::KeyboardConfig(LxQt::Settings* _settings, QSettings* _qtSettings, QWidget* parent): + QWidget(parent), + settings(_settings), + qtSettings(_qtSettings), + delay(500), + oldDelay(500), + interval(30), + oldInterval(30), + beep(true), + oldBeep(true) { + + ui.setupUi(this); + + /* read the config flie */ + loadSettings(); + initControls(); + + // set_range_stops(ui.keyboardDelay, 10); + connect(ui.keyboardDelay, SIGNAL(valueChanged(int)), SLOT(onKeyboardSliderChanged(int))); + // set_range_stops(ui.keyboardInterval, 10); + connect(ui.keyboardInterval, SIGNAL(valueChanged(int)), SLOT(onKeyboardSliderChanged(int))); + connect(ui.keyboardBeep, SIGNAL(toggled(bool)), SLOT(onKeyboardBeepToggled(bool))); + connect(ui.cursorFlashTime, SIGNAL(valueChanged(int)), SLOT(onCorsorFlashTimeChanged(int))); +} + +KeyboardConfig::~KeyboardConfig() { + +} + +void KeyboardConfig::initControls() { + ui.keyboardDelay->setValue(delay); + ui.keyboardInterval->setValue(interval); + ui.keyboardBeep->setChecked(beep); + + qtSettings->beginGroup(QLatin1String("Qt")); + int value = qtSettings->value(QLatin1String("cursorFlashTime"), 1000).toInt(); + ui.cursorFlashTime->setValue(value); + qtSettings->endGroup(); +} + +void KeyboardConfig::onKeyboardSliderChanged(int value) { + QSlider* slider = static_cast(sender()); + + if(slider == ui.keyboardDelay) + delay = value; + else if(slider == ui.keyboardInterval) + interval = value; + + /* apply keyboard values */ + XkbSetAutoRepeatRate(QX11Info::display(), XkbUseCoreKbd, delay, interval); + + accept(); +} + +void KeyboardConfig::onKeyboardBeepToggled(bool checked) { + XKeyboardControl values; + beep = checked; + values.bell_percent = beep ? -1 : 0; + XChangeKeyboardControl(QX11Info::display(), KBBellPercent, &values); + + accept(); +} + +void KeyboardConfig::onCorsorFlashTimeChanged(int value) +{ + qtSettings->beginGroup(QLatin1String("Qt")); + qtSettings->setValue(QLatin1String("cursorFlashTime"), value); + qtSettings->endGroup(); + qtSettings->sync(); +#ifdef Q_WS_X11 + qt_x11_apply_settings_in_all_apps(); +#endif +} + + +void KeyboardConfig::loadSettings() { + settings->beginGroup("Keyboard"); + oldDelay = delay = settings->value("delay", 500).toInt(); + oldInterval = interval = settings->value("interval", 30).toInt(); + oldBeep = beep = settings->value("beep", true).toBool(); + settings->endGroup(); +} + +void KeyboardConfig::accept() { + settings->beginGroup("Keyboard"); + settings->setValue("delay", delay); + settings->setValue("interval", interval); + settings->setValue("beep", beep); + settings->endGroup(); +} + +void KeyboardConfig::reset() { + /* restore to original settings */ + /* keyboard */ + delay = oldDelay; + interval = oldInterval; + beep = oldBeep; + XkbSetAutoRepeatRate(QX11Info::display(), XkbUseCoreKbd, delay, interval); + /* FIXME: beep? */ + + initControls(); + accept(); +} diff --git a/lxqt-config-input/keyboardconfig.h b/lxqt-config-input/keyboardconfig.h new file mode 100644 index 0000000..857193b --- /dev/null +++ b/lxqt-config-input/keyboardconfig.h @@ -0,0 +1,65 @@ +/* + Copyright (C) 2013-2014 Hong Jen Yee (PCMan) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + + +#ifndef KEYBOARDCONFIG_H +#define KEYBOARDCONFIG_H + +#include +#include "ui_keyboardconfig.h" + +namespace LxQt { + class Settings; +} +class QSettings; + +class KeyboardConfig : public QWidget { + Q_OBJECT + +public: + KeyboardConfig(LxQt::Settings* _settings, QSettings* _qtSettings, QWidget* parent = 0); + virtual ~KeyboardConfig(); + + void accept(); + +public Q_SLOTS: + void reset(); + +private: + void setLeftHandedMouse(); + void loadSettings(); + void initControls(); + +private Q_SLOTS: + void onKeyboardSliderChanged(int value); + void onKeyboardBeepToggled(bool checked); + void onCorsorFlashTimeChanged(int value); + +private: + Ui::KeyboardConfig ui; + LxQt::Settings* settings; + QSettings* qtSettings; + int delay; + int oldDelay; + int interval; + int oldInterval; + bool beep; + bool oldBeep; +}; + +#endif // KEYBOARDCONFIG_H diff --git a/lxqt-config-input/keyboardconfig.ui b/lxqt-config-input/keyboardconfig.ui new file mode 100644 index 0000000..c681023 --- /dev/null +++ b/lxqt-config-input/keyboardconfig.ui @@ -0,0 +1,201 @@ + + + KeyboardConfig + + + + 0 + 0 + 375 + 232 + + + + Form + + + + + + Cursor flash time: + + + + + + + <b>Keyboard</b> + + + + + + + Beep when there is an error of keyboard input + + + + + + + ms + + + 10000 + + + + + + + Character Repeat + + + + + + + + + 10 + + + 210 + + + 10 + + + Qt::Horizontal + + + QSlider::TicksAbove + + + + + + + Long + + + + + + + 100 + + + 1100 + + + 100 + + + 100 + + + Qt::Horizontal + + + QSlider::TicksAbove + + + + + + + Repeat delay: + + + + + + + Short + + + + + + + Repeat interval: + + + + + + + Type in the following box to test your keyboard settings + + + + + + + Short + + + + + + + Long + + + + + + + 0 + + + + + + + 0 + + + + + + + + + + + + keyboardDelay + valueChanged(int) + label_16 + setNum(int) + + + 245 + 65 + + + 405 + 70 + + + + + keyboardInterval + valueChanged(int) + label_17 + setNum(int) + + + 198 + 93 + + + 403 + 97 + + + + + diff --git a/lxqt-config-input/keyboardlayoutconfig.cpp b/lxqt-config-input/keyboardlayoutconfig.cpp new file mode 100644 index 0000000..5449b4c --- /dev/null +++ b/lxqt-config-input/keyboardlayoutconfig.cpp @@ -0,0 +1,321 @@ +/* + * + * Copyright (C) 2014 + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "keyboardlayoutconfig.h" +#include +#include +#include +#include +#include "selectkeyboardlayoutdialog.h" +#include + +KeyboardLayoutConfig::KeyboardLayoutConfig(LxQt::Settings* _settings, QWidget* parent): + QWidget(parent), + settings(_settings) { + ui.setupUi(this); + + loadLists(); + loadSettings(); + initControls(); + + connect(ui.addLayout, SIGNAL(clicked(bool)), SLOT(onAddLayout())); + connect(ui.removeLayout, SIGNAL(clicked(bool)), SLOT(onRemoveLayout())); + connect(ui.moveUp, SIGNAL(clicked(bool)), SLOT(onMoveUp())); + connect(ui.moveDown, SIGNAL(clicked(bool)), SLOT(onMoveDown())); + connect(ui.keyboardModel, SIGNAL(currentIndexChanged(int)), SLOT(accept())); + connect(ui.switchKey, SIGNAL(currentIndexChanged(int)), SLOT(accept())); +} + +KeyboardLayoutConfig::~KeyboardLayoutConfig() { +} + +void KeyboardLayoutConfig::loadSettings() { + // load current settings from the output of setxkbmap command + QProcess setxkbmap; + setxkbmap.start(QLatin1String("setxkbmap -query -verbose 5")); + setxkbmap.waitForFinished(); + if(setxkbmap.exitStatus() == QProcess::NormalExit) { + QList layouts, variants; + while(!setxkbmap.atEnd()) { + QByteArray line = setxkbmap.readLine(); + if(line.startsWith("model:")) { + keyboardModel_ = QString::fromLatin1(line.mid(6).trimmed()); + } + else if(line.startsWith("layout:")) { + layouts = line.mid(7).trimmed().split(','); + } + else if(line.startsWith("variant:")) { + variants = line.mid(8).trimmed().split(','); + } + else if(line.startsWith("options:")) { + QList options = line.mid(9).trimmed().split(','); + Q_FOREACH(QByteArray option, options) { + if(option.startsWith("grp:")) + switchKey_ = QString::fromLatin1(option); + else + currentOptions_ << QString::fromLatin1(option); + } + } + } + + const int size = layouts.size(), variantsSize = variants.size(); + for(int i = 0; i < size; ++i) { + currentLayouts_.append(QPair(layouts.at(i), variantsSize > 0 ? variants.at(i) : QString())); + } + + setxkbmap.close(); + } +} + +enum ListSection{ + NoSection, + ModelSection, + LayoutSection, + VariantSection, + OptionSection +}; + +void KeyboardLayoutConfig::loadLists() { + // load known lists from xkb data files + // FIXME: maybe we should use different files for different OSes? + QFile file(QLatin1String("/usr/share/X11/xkb/rules/base.lst")); + if(file.open(QIODevice::ReadOnly)) { + ListSection section = NoSection; + while(!file.atEnd()) { + QByteArray line = file.readLine().trimmed(); + if(section == NoSection) { + if(line.startsWith("! model")) + section = ModelSection; + else if(line.startsWith("! layout")) + section = LayoutSection; + else if(line.startsWith("! variant")) + section = VariantSection; + else if(line.startsWith("! option")) + section = OptionSection; + } + else { + if(line.isEmpty()) { + section = NoSection; + continue; + } + int sep = line.indexOf(' '); + QString name = QString::fromLatin1(line, sep); + while(line[sep] == ' ') // skip spaces + ++sep; + QString description = QString::fromUtf8(line.constData() + sep); + + switch(section) { + case ModelSection: { + ui.keyboardModel->addItem(description, name); + break; + } + case LayoutSection: + knownLayouts_[name] = KeyboardLayoutInfo(description); + break; + case VariantSection: { + // the descriptions of variants are prefixed by their language ids + sep = description.indexOf(": "); + if(sep >= 0) { + QString lang = description.left(sep); + QMap::iterator it = knownLayouts_.find(lang); + if(it != knownLayouts_.end()) { + KeyboardLayoutInfo& info = *it; + info.variants.append(LayoutVariantInfo(name, description.mid(sep + 2))); + } + } + break; + } + case OptionSection: + if(line.startsWith("grp:")) { // key used to switch to another layout + ui.switchKey->addItem(description, name); + } + break; + default:; + } + } + } + file.close(); + } +} + +void KeyboardLayoutConfig::initControls() { + QList >::iterator it; + for(it = currentLayouts_.begin(); it != currentLayouts_.end(); ++it) { + QString name = it->first; + QString variant = it->second; + addLayout(name, variant); + } + + int n = ui.keyboardModel->count(); + int row; + for(row = 0; row < n; ++row) { + if(ui.keyboardModel->itemData(row, Qt::UserRole).toString() == keyboardModel_) { + ui.keyboardModel->setCurrentIndex(row); + break; + } + } + + n = ui.switchKey->count(); + for(row = 0; row < n; ++row) { + if(ui.switchKey->itemData(row, Qt::UserRole).toString() == switchKey_) { + ui.switchKey->setCurrentIndex(row); + break; + } + } + +} + +void KeyboardLayoutConfig::addLayout(QString name, QString variant) { + qDebug() << "add" << name << variant; + const KeyboardLayoutInfo& info = knownLayouts_.value(name); + QTreeWidgetItem* item = new QTreeWidgetItem(); + item->setData(0, Qt::DisplayRole, info.description); + item->setData(0, Qt::UserRole, name); + const LayoutVariantInfo* vinfo = info.findVariant(variant); + if(vinfo) { + item->setData(1, Qt::DisplayRole, vinfo->description); + item->setData(1, Qt::UserRole, variant); + } + ui.layouts->addTopLevelItem(item); +} + +void KeyboardLayoutConfig::reset() { + ui.layouts->clear(); + initControls(); + accept(); +} + +void KeyboardLayoutConfig::accept() { + // call setxkbmap to apply the changes + QProcess setxkbmap; + // clear existing options + setxkbmap.start("setxkbmap -option"); + setxkbmap.waitForFinished(); + setxkbmap.close(); + + QString command = "setxkbmap"; + // set keyboard model + QString model; + int cur_model = ui.keyboardModel->currentIndex(); + if(cur_model >= 0) { + model = ui.keyboardModel->itemData(cur_model, Qt::UserRole).toString(); + command += " -model "; + command += model; + } + + // set keyboard layout + int n = ui.layouts->topLevelItemCount(); + QString layouts, variants; + if(n > 0) { + for(int row = 0; row < n; ++row) { + QTreeWidgetItem* item = ui.layouts->topLevelItem(row); + layouts += item->data(0, Qt::UserRole).toString(); + variants += item->data(1, Qt::UserRole).toString(); + if(row < n - 1) { // not the last row + layouts += ','; + variants += ','; + } + } + command += " -layout "; + command += layouts; + + if (variants.indexOf(',') > -1 || !variants.isEmpty()) { + command += " -variant "; + command += variants; + } + } + + Q_FOREACH(QString option, currentOptions_) { + if (!option.startsWith("grp:")) { + command += " -option "; + command += option; + } + } + + QString switchKey; + int cur_switch_key = ui.switchKey->currentIndex(); + if(cur_switch_key > 0) { // index 0 is "None" + switchKey = ui.switchKey->itemData(cur_switch_key, Qt::UserRole).toString(); + command += " -option "; + command += switchKey; + } + + qDebug() << command; + + // execute the command line + setxkbmap.start(command); + setxkbmap.waitForFinished(); + + // save to lxqt-session config file. + settings->beginGroup("Keyboard"); + settings->setValue("layout", layouts); + settings->setValue("variant", variants); + settings->setValue("model", model); + if(switchKey.isEmpty() && currentOptions_ .isEmpty()) + settings->remove("options"); + else + settings->setValue("options", switchKey.isEmpty() ? currentOptions_ : (currentOptions_ << switchKey)); + settings->endGroup(); +} + +void KeyboardLayoutConfig::onAddLayout() { + SelectKeyboardLayoutDialog dlg(knownLayouts_, this); + if(dlg.exec() == QDialog::Accepted) { + addLayout(dlg.selectedLayout(), dlg.selectedVariant()); + accept(); + } +} + +void KeyboardLayoutConfig::onRemoveLayout() { + if(ui.layouts->topLevelItemCount() > 1) { + QTreeWidgetItem* item = ui.layouts->currentItem(); + if(item) { + delete item; + accept(); + } + } +} + +void KeyboardLayoutConfig::onMoveDown() { + QTreeWidgetItem* item = ui.layouts->currentItem(); + if(!item) + return; + int pos = ui.layouts->indexOfTopLevelItem(item); + if(pos < ui.layouts->topLevelItemCount() - 1) { // not the last item + ui.layouts->takeTopLevelItem(pos); + ui.layouts->insertTopLevelItem(pos + 1, item); + ui.layouts->setCurrentItem(item); + accept(); + } +} + +void KeyboardLayoutConfig::onMoveUp() { + QTreeWidgetItem* item = ui.layouts->currentItem(); + if(!item) + return; + int pos = ui.layouts->indexOfTopLevelItem(item); + if(pos > 0) { // not the first item + ui.layouts->takeTopLevelItem(pos); + ui.layouts->insertTopLevelItem(pos - 1, item); + ui.layouts->setCurrentItem(item); + accept(); + } +} + diff --git a/lxqt-config-input/keyboardlayoutconfig.h b/lxqt-config-input/keyboardlayoutconfig.h new file mode 100644 index 0000000..36e40b5 --- /dev/null +++ b/lxqt-config-input/keyboardlayoutconfig.h @@ -0,0 +1,63 @@ +/* + * + * Copyright (C) 2014 + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef KEYBOARDLAYOUTCONFIG_H +#define KEYBOARDLAYOUTCONFIG_H + +#include +#include "keyboardlayoutinfo.h" +#include +#include "ui_keyboardlayoutconfig.h" + +namespace LxQt { + class Settings; +} + +class KeyboardLayoutConfig : public QWidget { + Q_OBJECT +public: + KeyboardLayoutConfig(LxQt::Settings* _settings, QWidget* parent = 0); + virtual ~KeyboardLayoutConfig(); + +public Q_SLOTS: + void accept(); + void reset(); + void onAddLayout(); + void onRemoveLayout(); + void onMoveUp(); + void onMoveDown(); + +private: + void loadSettings(); + void loadLists(); + void initControls(); + void addLayout(QString name, QString variant); + +private: + Ui::KeyboardLayoutConfig ui; + QString keyboardModel_; + QString switchKey_; + QStringList currentOptions_; + QList > currentLayouts_; + QMap knownLayouts_; + LxQt::Settings* settings; +}; + +#endif // KEYBOARDLAYOUTCONFIG_H diff --git a/lxqt-config-input/keyboardlayoutconfig.ui b/lxqt-config-input/keyboardlayoutconfig.ui new file mode 100644 index 0000000..d2235aa --- /dev/null +++ b/lxqt-config-input/keyboardlayoutconfig.ui @@ -0,0 +1,152 @@ + + + KeyboardLayoutConfig + + + + 0 + 0 + 428 + 322 + + + + + QFormLayout::AllNonFixedFieldsGrow + + + + + <b>Keyboard Layout</b> + + + + + + + + + + 1 + 1 + + + + true + + + QAbstractItemView::InternalMove + + + false + + + false + + + + Layout + + + + + Variant + + + + + + + + + + &Add + + + + + + + &Remove + + + + + + + up + + + + + + + down + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + Keyboard model: + + + + + + + QComboBox::AdjustToMinimumContentsLengthWithIcon + + + + + + + Keys to change layout: + + + + + + + QComboBox::AdjustToMinimumContentsLengthWithIcon + + + + None + + + + + + + + <html><head/><body><p><span style=" font-weight:600;">Note</span>: If you are using an <span style=" font-weight:600;">input method</span>, such as IBus, uim, fcitx, or gcin, the settings here <span style=" font-weight:600;">might not work</span> because they are overridden by the input methods.</p></body></html> + + + true + + + + + + + + diff --git a/lxqt-config-input/keyboardlayoutinfo.h b/lxqt-config-input/keyboardlayoutinfo.h new file mode 100644 index 0000000..da31996 --- /dev/null +++ b/lxqt-config-input/keyboardlayoutinfo.h @@ -0,0 +1,52 @@ +/* + * + * Copyright (C) 2014 + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef _KEYBOARD_LAYOUT_INFO_H_ +#define _KEYBOARD_LAYOUT_INFO_H_ + +#include +#include + +struct LayoutVariantInfo { + QString name; + QString description; + LayoutVariantInfo(QString _name, QString desc): name(_name), description(desc) { + } +}; + +struct KeyboardLayoutInfo { + QString description; + QList variants; + + KeyboardLayoutInfo(QString desc = QString()): description(desc) { + } + + const LayoutVariantInfo* findVariant(QString name) const { + if(!name.isEmpty()) { + Q_FOREACH(const LayoutVariantInfo& vinfo, variants) { + if(vinfo.name == name) + return &vinfo; + } + } + return NULL; + } +}; + +#endif diff --git a/lxqt-config-input/lxqt-config-input.cpp b/lxqt-config-input/lxqt-config-input.cpp new file mode 100644 index 0000000..3a899de --- /dev/null +++ b/lxqt-config-input/lxqt-config-input.cpp @@ -0,0 +1,58 @@ +/* + Copyright (C) 2013-2014 Hong Jen Yee (PCMan) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#include +#include +#include +#include "mouseconfig.h" +#include "keyboardconfig.h" +#include "../liblxqt-config-cursor/selectwnd.h" +#include "keyboardlayoutconfig.h" + +int main(int argc, char** argv) { + LxQt::SingleApplication app(argc, argv); + + QByteArray configName = qgetenv("LXQT_SESSION_CONFIG"); + if(configName.isEmpty()) + configName = "session"; + LxQt::Settings settings(configName); + LxQt::ConfigDialog dlg(QObject::tr("Keyboard and Mouse Settings"), &settings); + app.setActivationWindow(&dlg); + + LxQt::Settings qtSettings("lxqt"); + MouseConfig* mouseConfig = new MouseConfig(&settings, &qtSettings, &dlg); + dlg.addPage(mouseConfig, QObject::tr("Mouse"), "input-mouse"); + QObject::connect(&dlg, SIGNAL(reset()), mouseConfig, SLOT(reset())); + + SelectWnd* cursorConfig = new SelectWnd(&settings, &dlg); + cursorConfig->setCurrent(); + dlg.addPage(cursorConfig, QObject::tr("Cursor"), "preferences-desktop-theme"); + + KeyboardConfig* keyboardConfig = new KeyboardConfig(&settings, &qtSettings, &dlg); + dlg.addPage(keyboardConfig, QObject::tr("Keyboard"), "input-keyboard"); + QObject::connect(&dlg, SIGNAL(reset()), keyboardConfig, SLOT(reset())); + + KeyboardLayoutConfig* keyboardLayoutConfig = new KeyboardLayoutConfig(&settings, &dlg); + dlg.addPage(keyboardLayoutConfig, QObject::tr("Keyboard Layout"), "input-keyboard"); + QObject::connect(&dlg, SIGNAL(reset()), keyboardLayoutConfig, SLOT(reset())); + + dlg.setWindowIcon(QIcon::fromTheme("input-keyboard")); + + dlg.exec(); + return 0; +} diff --git a/lxqt-config-input/lxqt-config-input.desktop.in b/lxqt-config-input/lxqt-config-input.desktop.in new file mode 100644 index 0000000..52f19f6 --- /dev/null +++ b/lxqt-config-input/lxqt-config-input.desktop.in @@ -0,0 +1,11 @@ +[Desktop Entry] +Type=Application +Name=Keyboard and Mouse +GenericName=Input settings +Comment=Configure keyboard, mouse, and other input devices +Exec=lxqt-config-input +Icon=input-keyboard +Categories=Qt;Settings;HardwareSettings;DesktopSettings;LXQt; +OnlyShowIn=LXDE;LXQt; + +#TRANSLATIONS_DIR=translations diff --git a/lxqt-config-input/lxqt-config-input.h b/lxqt-config-input/lxqt-config-input.h new file mode 100644 index 0000000..a34befc --- /dev/null +++ b/lxqt-config-input/lxqt-config-input.h @@ -0,0 +1,6 @@ +#ifndef LXQT_CONFIG_INPUT_H +#define LXQT_CONFIG_INPUT_H + + + +#endif // LXQT_CONFIG_INPUT_H diff --git a/lxqt-config-input/mouseconfig.cpp b/lxqt-config-input/mouseconfig.cpp new file mode 100644 index 0000000..fdb3906 --- /dev/null +++ b/lxqt-config-input/mouseconfig.cpp @@ -0,0 +1,207 @@ +/* + Copyright (C) 2013-2014 Hong Jen Yee (PCMan) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + + +#include "mouseconfig.h" +#include +#include +#include +#include +#include +#include +#include +#include + +// FIXME: how to support XCB or Wayland? +#include +#include +#include + +#ifdef Q_WS_X11 +extern void qt_x11_apply_settings_in_all_apps(); +#endif + +MouseConfig::MouseConfig(LxQt::Settings* _settings, QSettings* _qtSettings, QWidget* parent): + QWidget(parent), + settings(_settings), + qtSettings(_qtSettings), + accel(20), + oldAccel(20), + threshold(10), + oldThreshold(10), + leftHanded(false), + oldLeftHanded(false), + singleClick(false), + oldSingleClick(false) { + + ui.setupUi(this); + + /* read the config flie */ + loadSettings(); + initControls(); + + // set_range_stops(ui.mouseAccel, 10); + connect(ui.mouseAccel, SIGNAL(valueChanged(int)), SLOT(onMouseAccelChanged(int))); + // set_range_stops(ui.mouseThreshold, 10); + connect(ui.mouseThreshold, SIGNAL(valueChanged(int)), SLOT(onMouseThresholdChanged(int))); + connect(ui.mouseLeftHanded, SIGNAL(toggled(bool)), SLOT(onMouseLeftHandedToggled(bool))); + + connect(ui.doubleClickInterval, SIGNAL(valueChanged(int)), SLOT(onDoubleClickIntervalChanged(int))); + connect(ui.wheelScrollLines, SIGNAL(valueChanged(int)), SLOT(onWheelScrollLinesChanged(int))); + connect(ui.singleClick, SIGNAL(toggled(bool)), SLOT(onSingleClickChanged(bool))); +} + +MouseConfig::~MouseConfig() { +} + +void MouseConfig::initControls() { + ui.mouseAccel->setValue(accel); + ui.mouseThreshold->setValue(110 - threshold); + ui.mouseLeftHanded->setChecked(leftHanded); + + ui.singleClick->setChecked(qtSettings->value(QLatin1String("single_click_activate"), false).toBool()); + + qtSettings->beginGroup(QLatin1String("Qt")); + int value = qtSettings->value(QLatin1String("doubleClickInterval"), 400).toInt(); + ui.doubleClickInterval->setValue(value); + + value = qtSettings->value(QLatin1String("wheelScrollLines"), 3).toInt(); + ui.wheelScrollLines->setValue(value); + qtSettings->endGroup(); +} + + +void MouseConfig::onMouseAccelChanged(int value) { + QSlider* slider = static_cast(sender()); + accel = value; + XChangePointerControl(QX11Info::display(), True, False, + accel, 10, 0); + accept(); +} + +void MouseConfig::onMouseThresholdChanged(int value) { + QSlider* slider = static_cast(sender()); + /* threshold = 110 - sensitivity. The lower the threshold, the higher the sensitivity */ + threshold = 110 - value; + XChangePointerControl(QX11Info::display(), False, True, + 0, 10, threshold); + accept(); +} + +/* This function is taken from Gnome's control-center 2.6.0.3 (gnome-settings-mouse.c) and was modified*/ +#define DEFAULT_PTR_MAP_SIZE 128 +void MouseConfig::setLeftHandedMouse() { + unsigned char* buttons; + int n_buttons, i; + int idx_1 = 0, idx_3 = 1; + + buttons = (unsigned char*)malloc(DEFAULT_PTR_MAP_SIZE); + n_buttons = XGetPointerMapping(QX11Info::display(), buttons, DEFAULT_PTR_MAP_SIZE); + + if(n_buttons > DEFAULT_PTR_MAP_SIZE) { + buttons = (unsigned char*)realloc(buttons, n_buttons); + n_buttons = XGetPointerMapping(QX11Info::display(), buttons, n_buttons); + } + + for(i = 0; i < n_buttons; i++) { + if(buttons[i] == 1) + idx_1 = i; + else if(buttons[i] == ((n_buttons < 3) ? 2 : 3)) + idx_3 = i; + } + + if((leftHanded && idx_1 < idx_3) || + (!leftHanded && idx_1 > idx_3)) { + buttons[idx_1] = ((n_buttons < 3) ? 2 : 3); + buttons[idx_3] = 1; + XSetPointerMapping(QX11Info::display(), buttons, n_buttons); + } + free(buttons); +} + +void MouseConfig::onMouseLeftHandedToggled(bool checked) { + leftHanded = checked; + setLeftHandedMouse(); + accept(); +} + +void MouseConfig::onDoubleClickIntervalChanged(int value) +{ + qtSettings->beginGroup(QLatin1String("Qt")); + qtSettings->setValue(QLatin1String("doubleClickInterval"), value); + qtSettings->endGroup(); + qtSettings->sync(); +#ifdef Q_WS_X11 + qt_x11_apply_settings_in_all_apps(); +#endif +} + +void MouseConfig::onWheelScrollLinesChanged(int value) +{ + qtSettings->beginGroup(QLatin1String("Qt")); + qtSettings->setValue(QLatin1String("wheelScrollLines"), value); + qtSettings->endGroup(); + qtSettings->sync(); +#ifdef Q_WS_X11 + qt_x11_apply_settings_in_all_apps(); +#endif +} + +void MouseConfig::onSingleClickChanged(bool checked) +{ + qtSettings->setValue(QLatin1String("single_click_activate"), checked); + qtSettings->sync(); +#ifdef Q_WS_X11 + qt_x11_apply_settings_in_all_apps(); +#endif +} + +void MouseConfig::loadSettings() { + oldSingleClick = singleClick = qtSettings->value("single_click_activate", false).toBool(); + + settings->beginGroup("Mouse"); + oldAccel = accel = settings->value("acc_factor", 20).toInt(); + oldThreshold = threshold = settings->value("acc_threshold", 10).toInt(); + oldLeftHanded = leftHanded = settings->value("left_handed", false).toBool(); + settings->endGroup(); +} + +void MouseConfig::accept() { + qtSettings->setValue("single_click_activate", singleClick); + + settings->beginGroup("Mouse"); + settings->setValue("acc_factor", accel); + settings->setValue("acc_threshold", threshold); + settings->setValue("left_handed", leftHanded); + settings->endGroup(); +} + +void MouseConfig::reset() { + /* restore to original settings */ + /* mouse */ + accel = oldAccel; + threshold = oldThreshold; + leftHanded = oldLeftHanded; + singleClick = oldSingleClick; + XChangePointerControl(QX11Info::display(), True, True, + accel, 10, threshold); + setLeftHandedMouse(); + + initControls(); + accept(); +} diff --git a/lxqt-config-input/mouseconfig.h b/lxqt-config-input/mouseconfig.h new file mode 100644 index 0000000..3a998f1 --- /dev/null +++ b/lxqt-config-input/mouseconfig.h @@ -0,0 +1,69 @@ +/* + Copyright (C) 2013-2014 Hong Jen Yee (PCMan) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + + +#ifndef MOUSECONFIG_H +#define MOUSECONFIG_H + +#include +#include "ui_mouseconfig.h" + +namespace LxQt { + class Settings; +} +class QSettings; + +class MouseConfig : public QWidget { + Q_OBJECT + +public: + MouseConfig(LxQt::Settings* _settings, QSettings* _qtSettings, QWidget* parent); + virtual ~MouseConfig(); + + void accept(); +public Q_SLOTS: + void reset(); + +private: + void setLeftHandedMouse(); + void loadSettings(); + void initControls(); + +private Q_SLOTS: + void onMouseAccelChanged(int value); + void onMouseThresholdChanged(int value); + void onMouseLeftHandedToggled(bool checked); + void onDoubleClickIntervalChanged(int value); + void onWheelScrollLinesChanged(int value); + void onSingleClickChanged(bool checked); + +private: + Ui::MouseConfig ui; + LxQt::Settings* settings; + QSettings* qtSettings; + int accel; + int oldAccel; + int threshold; + int oldThreshold; + bool leftHanded; + bool oldLeftHanded; + bool singleClick; + bool oldSingleClick; +}; + +#endif // MOUSECONFIG_H diff --git a/lxqt-config-input/mouseconfig.ui b/lxqt-config-input/mouseconfig.ui new file mode 100644 index 0000000..775c99d --- /dev/null +++ b/lxqt-config-input/mouseconfig.ui @@ -0,0 +1,208 @@ + + + MouseConfig + + + + 0 + 0 + 324 + 223 + + + + Form + + + + QFormLayout::AllNonFixedFieldsGrow + + + + + <b>Mouse</b> + + + + + + + Motion + + + + + + High + + + + + + + Fast + + + + + + + Sensitivity: + + + + + + + Low + + + + + + + 10 + + + 110 + + + 10 + + + Qt::Horizontal + + + QSlider::TicksAbove + + + + + + + Acceleration: + + + + + + + 10 + + + 110 + + + 10 + + + Qt::Horizontal + + + QSlider::TicksAbove + + + + + + + Slow + + + + + + + 0 + + + + + + + 0 + + + + + + + + + + Double click interval: + + + + + + + ms + + + 10000 + + + + + + + Wheel scroll lines: + + + + + + + + + + Left handed (Swap left and right mouse buttons) + + + + + + + Single click to activate items + + + + + + + + + mouseAccel + valueChanged(int) + label_41 + setNum(int) + + + 175 + 74 + + + 342 + 73 + + + + + mouseThreshold + valueChanged(int) + label_42 + setNum(int) + + + 191 + 95 + + + 347 + 95 + + + + + diff --git a/lxqt-config-input/selectkeyboardlayoutdialog.cpp b/lxqt-config-input/selectkeyboardlayoutdialog.cpp new file mode 100644 index 0000000..e6b0d8c --- /dev/null +++ b/lxqt-config-input/selectkeyboardlayoutdialog.cpp @@ -0,0 +1,76 @@ +/* + * + * Copyright (C) 2014 + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "selectkeyboardlayoutdialog.h" +#include + +SelectKeyboardLayoutDialog::SelectKeyboardLayoutDialog(QMap< QString, KeyboardLayoutInfo>& knownLayouts, QWidget* parent): + QDialog(parent), + knownLayouts_(knownLayouts) { + ui.setupUi(this); + connect(ui.layouts, SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)), SLOT(onLayoutChanged())); + + QMap::const_iterator it; + for(it = knownLayouts_.begin(); it != knownLayouts.end(); ++it) { + const QString& name = it.key(); + const KeyboardLayoutInfo& info = *it; + QListWidgetItem * item = new QListWidgetItem(info.description); + item->setData(Qt::UserRole, name); + ui.layouts->addItem(item); + } + ui.layouts->setCurrentItem(ui.layouts->item(0)); +} + +SelectKeyboardLayoutDialog::~SelectKeyboardLayoutDialog() { + +} + +void SelectKeyboardLayoutDialog::onLayoutChanged() { + QListWidgetItem* item = ui.layouts->currentItem(); + ui.variants->clear(); + + ui.variants->addItem("None"); + ui.variants->setCurrentItem(ui.variants->item(0)); + if(item) { // add variants of this layout to the list view + QString name = item->data(Qt::UserRole).toString(); + const KeyboardLayoutInfo& info = knownLayouts_[name]; + Q_FOREACH(const LayoutVariantInfo& vinfo, info.variants) { + QListWidgetItem * vitem = new QListWidgetItem(vinfo.description); + // qDebug() << "vitem" << vinfo.name << vinfo.description; + vitem->setData(Qt::UserRole, vinfo.name); + ui.variants->addItem(vitem); + } + } +} + +QString SelectKeyboardLayoutDialog::selectedLayout() { + QListWidgetItem* layoutItem = ui.layouts->currentItem(); + if(layoutItem) { + return layoutItem->data(Qt::UserRole).toString(); + } + return QString(); +} + +QString SelectKeyboardLayoutDialog::selectedVariant() { + QListWidgetItem* variantItem = ui.variants->currentItem(); + if(variantItem) + return variantItem->data(Qt::UserRole).toString(); + return QString(); +} diff --git a/lxqt-config-input/selectkeyboardlayoutdialog.h b/lxqt-config-input/selectkeyboardlayoutdialog.h new file mode 100644 index 0000000..43bb12c --- /dev/null +++ b/lxqt-config-input/selectkeyboardlayoutdialog.h @@ -0,0 +1,45 @@ +/* + * + * Copyright (C) 2014 + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef SELECTKEYBOARDLAYOUTDIALOG_H +#define SELECTKEYBOARDLAYOUTDIALOG_H + +#include +#include "ui_selectkeyboardlayoutdialog.h" +#include "keyboardlayoutinfo.h" + +class SelectKeyboardLayoutDialog : public QDialog { + Q_OBJECT +public: + SelectKeyboardLayoutDialog(QMap< QString, KeyboardLayoutInfo >& knownLayouts, QWidget* parent = 0); + virtual ~SelectKeyboardLayoutDialog(); + + QString selectedLayout(); + QString selectedVariant(); + +private Q_SLOTS: + void onLayoutChanged(); + +private: + Ui::SelectKeyboardLayoutDialog ui; + QMap& knownLayouts_; +}; + +#endif // SELECTKEYBOARDLAYOUTDIALOG_H diff --git a/lxqt-config-input/selectkeyboardlayoutdialog.ui b/lxqt-config-input/selectkeyboardlayoutdialog.ui new file mode 100644 index 0000000..36bb688 --- /dev/null +++ b/lxqt-config-input/selectkeyboardlayoutdialog.ui @@ -0,0 +1,88 @@ + + + SelectKeyboardLayoutDialog + + + + 0 + 0 + 480 + 384 + + + + Select a keyboard layout + + + + + + Keyboard layout + + + + + + + Variant + + + + + + + true + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + SelectKeyboardLayoutDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + SelectKeyboardLayoutDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/lxqt-config-input/translations/lxinput-qt_template-zh_TW.ts b/lxqt-config-input/translations/lxinput-qt_template-zh_TW.ts new file mode 100644 index 0000000..8b5600d --- /dev/null +++ b/lxqt-config-input/translations/lxinput-qt_template-zh_TW.ts @@ -0,0 +1,82 @@ + + + + MainDialog + + Input Device Preferences + 輸入裝置偏好設定 + + + Motion + 移動 + + + High + + + + Fast + + + + Sensitivity: + 敏感度: + + + Low + + + + Acceleration: + 加速度: + + + Slow + + + + 0 + + + + Left handed (Swap left and right mouse buttons) + 慣用左手 (將滑鼠左右鍵倒轉) + + + Mouse + 滑鼠 + + + Character Repeat + 字元重覆 + + + Long + + + + Repeat delay: + 重複延遲: + + + Short + + + + Repeat interval: + 重複間隔: + + + Type in the following box to test your keyboard settings + + + + Beep when there is an error of keyboard input + + + + Keyboard + 鍵盤 + + + diff --git a/lxqt-config-input/translations/lxqt-config-input.ts b/lxqt-config-input/translations/lxqt-config-input.ts new file mode 100644 index 0000000..bda8e29 --- /dev/null +++ b/lxqt-config-input/translations/lxqt-config-input.ts @@ -0,0 +1,253 @@ + + + + + KeyboardConfig + + + Form + + + + + Cursor flash time: + + + + + <b>Keyboard</b> + + + + + Beep when there is an error of keyboard input + + + + + ms + + + + + Character Repeat + + + + + + Long + + + + + Repeat delay: + + + + + + Short + + + + + Repeat interval: + + + + + Type in the following box to test your keyboard settings + + + + + + 0 + + + + + KeyboardLayoutConfig + + + <b>Keyboard Layout</b> + + + + + Layout + + + + + Variant + + + + + &Add + + + + + &Remove + + + + + up + + + + + down + + + + + Keyboard model: + + + + + Keys to change layout: + + + + + None + + + + + <html><head/><body><p><span style=" font-weight:600;">Note</span>: If you are using an <span style=" font-weight:600;">input method</span>, such as IBus, uim, fcitx, or gcin, the settings here <span style=" font-weight:600;">might not work</span> because they are overridden by the input methods.</p></body></html> + + + + + MouseConfig + + + Form + + + + + <b>Mouse</b> + + + + + Motion + + + + + High + + + + + Fast + + + + + Sensitivity: + + + + + Low + + + + + Acceleration: + + + + + Slow + + + + + + 0 + + + + + Double click interval: + + + + + ms + + + + + Wheel scroll lines: + + + + + Left handed (Swap left and right mouse buttons) + + + + + Single click to activate items + + + + + QObject + + + Keyboard and Mouse Settings + + + + + Mouse + + + + + Cursor + + + + + Keyboard + + + + + Keyboard Layout + + + + + SelectKeyboardLayoutDialog + + + Select a keyboard layout + + + + + Keyboard layout + + + + + Variant + + + + diff --git a/lxqt-config-input/translations/lxqt-config-input_af.ts b/lxqt-config-input/translations/lxqt-config-input_af.ts new file mode 100644 index 0000000..ec68908 --- /dev/null +++ b/lxqt-config-input/translations/lxqt-config-input_af.ts @@ -0,0 +1,253 @@ + + + + + KeyboardConfig + + + Form + + + + + Cursor flash time: + + + + + <b>Keyboard</b> + + + + + Beep when there is an error of keyboard input + + + + + ms + + + + + Character Repeat + + + + + + Long + + + + + Repeat delay: + + + + + + Short + + + + + Repeat interval: + + + + + Type in the following box to test your keyboard settings + + + + + + 0 + + + + + KeyboardLayoutConfig + + + <b>Keyboard Layout</b> + + + + + Layout + + + + + Variant + + + + + &Add + + + + + &Remove + + + + + up + + + + + down + + + + + Keyboard model: + + + + + Keys to change layout: + + + + + None + + + + + <html><head/><body><p><span style=" font-weight:600;">Note</span>: If you are using an <span style=" font-weight:600;">input method</span>, such as IBus, uim, fcitx, or gcin, the settings here <span style=" font-weight:600;">might not work</span> because they are overridden by the input methods.</p></body></html> + + + + + MouseConfig + + + Form + + + + + <b>Mouse</b> + + + + + Motion + + + + + High + + + + + Fast + + + + + Sensitivity: + + + + + Low + + + + + Acceleration: + + + + + Slow + + + + + + 0 + + + + + Double click interval: + + + + + ms + + + + + Wheel scroll lines: + + + + + Left handed (Swap left and right mouse buttons) + + + + + Single click to activate items + + + + + QObject + + + Keyboard and Mouse Settings + + + + + Mouse + + + + + Cursor + + + + + Keyboard + + + + + Keyboard Layout + + + + + SelectKeyboardLayoutDialog + + + Select a keyboard layout + + + + + Keyboard layout + + + + + Variant + + + + diff --git a/lxqt-config-input/translations/lxqt-config-input_ar.ts b/lxqt-config-input/translations/lxqt-config-input_ar.ts new file mode 100644 index 0000000..16e3cf7 --- /dev/null +++ b/lxqt-config-input/translations/lxqt-config-input_ar.ts @@ -0,0 +1,253 @@ + + + + + KeyboardConfig + + + Form + + + + + Cursor flash time: + + + + + <b>Keyboard</b> + + + + + Beep when there is an error of keyboard input + + + + + ms + + + + + Character Repeat + + + + + + Long + + + + + Repeat delay: + + + + + + Short + + + + + Repeat interval: + + + + + Type in the following box to test your keyboard settings + + + + + + 0 + + + + + KeyboardLayoutConfig + + + <b>Keyboard Layout</b> + + + + + Layout + + + + + Variant + + + + + &Add + + + + + &Remove + + + + + up + + + + + down + + + + + Keyboard model: + + + + + Keys to change layout: + + + + + None + + + + + <html><head/><body><p><span style=" font-weight:600;">Note</span>: If you are using an <span style=" font-weight:600;">input method</span>, such as IBus, uim, fcitx, or gcin, the settings here <span style=" font-weight:600;">might not work</span> because they are overridden by the input methods.</p></body></html> + + + + + MouseConfig + + + Form + + + + + <b>Mouse</b> + + + + + Motion + + + + + High + + + + + Fast + + + + + Sensitivity: + + + + + Low + + + + + Acceleration: + + + + + Slow + + + + + + 0 + + + + + Double click interval: + + + + + ms + + + + + Wheel scroll lines: + + + + + Left handed (Swap left and right mouse buttons) + + + + + Single click to activate items + + + + + QObject + + + Keyboard and Mouse Settings + + + + + Mouse + + + + + Cursor + + + + + Keyboard + + + + + Keyboard Layout + + + + + SelectKeyboardLayoutDialog + + + Select a keyboard layout + + + + + Keyboard layout + + + + + Variant + + + + diff --git a/lxqt-config-input/translations/lxqt-config-input_bg.ts b/lxqt-config-input/translations/lxqt-config-input_bg.ts new file mode 100644 index 0000000..a2d0bd3 --- /dev/null +++ b/lxqt-config-input/translations/lxqt-config-input_bg.ts @@ -0,0 +1,332 @@ + + + + + KeyboardConfig + + + Form + + + + + Cursor flash time: + + + + + <b>Keyboard</b> + + + + + Beep when there is an error of keyboard input + Звуков сигнал, когато има грешка при набирането + + + + ms + + + + + Character Repeat + Повторение на знаци + + + + + Long + Дълго + + + + Repeat delay: + Задържане на повторението: + + + + + Short + Кратко + + + + Repeat interval: + Интервал на повторение: + + + + Type in the following box to test your keyboard settings + Наберете в следната кутия, за да тествате клавиатурните настройки + + + + + 0 + 0 + + + + KeyboardLayoutConfig + + + <b>Keyboard Layout</b> + + + + + Layout + + + + + Variant + + + + + &Add + + + + + &Remove + + + + + up + + + + + down + + + + + Keyboard model: + + + + + Keys to change layout: + + + + + None + + + + + <html><head/><body><p><span style=" font-weight:600;">Note</span>: If you are using an <span style=" font-weight:600;">input method</span>, such as IBus, uim, fcitx, or gcin, the settings here <span style=" font-weight:600;">might not work</span> because they are overridden by the input methods.</p></body></html> + + + + + MainDialog + + Input Device Preferences + Настройки на входните устройства + + + Motion + Движение + + + High + Високо + + + Fast + Бързо + + + Sensitivity: + Чувствителност: + + + Low + Ниско + + + Acceleration: + Ускорение: + + + Slow + Бавно + + + 0 + 0 + + + Left handed (Swap left and right mouse buttons) + Лява ръка (смяна на ляв и десен бутони на мишката) + + + Mouse + Мишка + + + Character Repeat + Повторение на знаци + + + Long + Дълго + + + Repeat delay: + Задържане на повторението: + + + Short + Кратко + + + Repeat interval: + Интервал на повторение: + + + Type in the following box to test your keyboard settings + Наберете в следната кутия, за да тествате клавиатурните настройки + + + Beep when there is an error of keyboard input + Звуков сигнал, когато има грешка при набирането + + + Keyboard + Клавиатура + + + + MouseConfig + + + Form + + + + + <b>Mouse</b> + + + + + Motion + Движение + + + + High + Високо + + + + Fast + Бързо + + + + Sensitivity: + Чувствителност: + + + + Low + Ниско + + + + Acceleration: + Ускорение: + + + + Slow + Бавно + + + + + 0 + 0 + + + + Double click interval: + + + + + ms + + + + + Wheel scroll lines: + + + + + Left handed (Swap left and right mouse buttons) + Лява ръка (смяна на ляв и десен бутони на мишката) + + + + Single click to activate items + + + + + QObject + + + Keyboard and Mouse Settings + + + + + Mouse + Мишка + + + + Cursor + + + + + Keyboard + Клавиатура + + + + Keyboard Layout + + + + + SelectKeyboardLayoutDialog + + + Select a keyboard layout + + + + + Keyboard layout + + + + + Variant + + + + diff --git a/lxqt-config-input/translations/lxqt-config-input_bn.ts b/lxqt-config-input/translations/lxqt-config-input_bn.ts new file mode 100644 index 0000000..09617e7 --- /dev/null +++ b/lxqt-config-input/translations/lxqt-config-input_bn.ts @@ -0,0 +1,253 @@ + + + + + KeyboardConfig + + + Form + + + + + Cursor flash time: + + + + + <b>Keyboard</b> + + + + + Beep when there is an error of keyboard input + + + + + ms + + + + + Character Repeat + + + + + + Long + + + + + Repeat delay: + + + + + + Short + + + + + Repeat interval: + + + + + Type in the following box to test your keyboard settings + + + + + + 0 + + + + + KeyboardLayoutConfig + + + <b>Keyboard Layout</b> + + + + + Layout + + + + + Variant + + + + + &Add + + + + + &Remove + + + + + up + + + + + down + + + + + Keyboard model: + + + + + Keys to change layout: + + + + + None + + + + + <html><head/><body><p><span style=" font-weight:600;">Note</span>: If you are using an <span style=" font-weight:600;">input method</span>, such as IBus, uim, fcitx, or gcin, the settings here <span style=" font-weight:600;">might not work</span> because they are overridden by the input methods.</p></body></html> + + + + + MouseConfig + + + Form + + + + + <b>Mouse</b> + + + + + Motion + + + + + High + + + + + Fast + + + + + Sensitivity: + + + + + Low + + + + + Acceleration: + + + + + Slow + + + + + + 0 + + + + + Double click interval: + + + + + ms + + + + + Wheel scroll lines: + + + + + Left handed (Swap left and right mouse buttons) + + + + + Single click to activate items + + + + + QObject + + + Keyboard and Mouse Settings + + + + + Mouse + + + + + Cursor + + + + + Keyboard + + + + + Keyboard Layout + + + + + SelectKeyboardLayoutDialog + + + Select a keyboard layout + + + + + Keyboard layout + + + + + Variant + + + + diff --git a/lxqt-config-input/translations/lxqt-config-input_bn_IN.ts b/lxqt-config-input/translations/lxqt-config-input_bn_IN.ts new file mode 100644 index 0000000..b2571d8 --- /dev/null +++ b/lxqt-config-input/translations/lxqt-config-input_bn_IN.ts @@ -0,0 +1,253 @@ + + + + + KeyboardConfig + + + Form + + + + + Cursor flash time: + + + + + <b>Keyboard</b> + + + + + Beep when there is an error of keyboard input + + + + + ms + + + + + Character Repeat + + + + + + Long + + + + + Repeat delay: + + + + + + Short + + + + + Repeat interval: + + + + + Type in the following box to test your keyboard settings + + + + + + 0 + + + + + KeyboardLayoutConfig + + + <b>Keyboard Layout</b> + + + + + Layout + + + + + Variant + + + + + &Add + + + + + &Remove + + + + + up + + + + + down + + + + + Keyboard model: + + + + + Keys to change layout: + + + + + None + + + + + <html><head/><body><p><span style=" font-weight:600;">Note</span>: If you are using an <span style=" font-weight:600;">input method</span>, such as IBus, uim, fcitx, or gcin, the settings here <span style=" font-weight:600;">might not work</span> because they are overridden by the input methods.</p></body></html> + + + + + MouseConfig + + + Form + + + + + <b>Mouse</b> + + + + + Motion + + + + + High + + + + + Fast + + + + + Sensitivity: + + + + + Low + + + + + Acceleration: + + + + + Slow + + + + + + 0 + + + + + Double click interval: + + + + + ms + + + + + Wheel scroll lines: + + + + + Left handed (Swap left and right mouse buttons) + + + + + Single click to activate items + + + + + QObject + + + Keyboard and Mouse Settings + + + + + Mouse + + + + + Cursor + + + + + Keyboard + + + + + Keyboard Layout + + + + + SelectKeyboardLayoutDialog + + + Select a keyboard layout + + + + + Keyboard layout + + + + + Variant + + + + diff --git a/lxqt-config-input/translations/lxqt-config-input_ca.ts b/lxqt-config-input/translations/lxqt-config-input_ca.ts new file mode 100644 index 0000000..ac0d9ac --- /dev/null +++ b/lxqt-config-input/translations/lxqt-config-input_ca.ts @@ -0,0 +1,253 @@ + + + + + KeyboardConfig + + + Form + + + + + Cursor flash time: + + + + + <b>Keyboard</b> + + + + + Beep when there is an error of keyboard input + + + + + ms + + + + + Character Repeat + + + + + + Long + + + + + Repeat delay: + + + + + + Short + + + + + Repeat interval: + + + + + Type in the following box to test your keyboard settings + + + + + + 0 + + + + + KeyboardLayoutConfig + + + <b>Keyboard Layout</b> + + + + + Layout + + + + + Variant + + + + + &Add + + + + + &Remove + + + + + up + + + + + down + + + + + Keyboard model: + + + + + Keys to change layout: + + + + + None + + + + + <html><head/><body><p><span style=" font-weight:600;">Note</span>: If you are using an <span style=" font-weight:600;">input method</span>, such as IBus, uim, fcitx, or gcin, the settings here <span style=" font-weight:600;">might not work</span> because they are overridden by the input methods.</p></body></html> + + + + + MouseConfig + + + Form + + + + + <b>Mouse</b> + + + + + Motion + + + + + High + + + + + Fast + + + + + Sensitivity: + + + + + Low + + + + + Acceleration: + + + + + Slow + + + + + + 0 + + + + + Double click interval: + + + + + ms + + + + + Wheel scroll lines: + + + + + Left handed (Swap left and right mouse buttons) + + + + + Single click to activate items + + + + + QObject + + + Keyboard and Mouse Settings + + + + + Mouse + + + + + Cursor + + + + + Keyboard + + + + + Keyboard Layout + + + + + SelectKeyboardLayoutDialog + + + Select a keyboard layout + + + + + Keyboard layout + + + + + Variant + + + + diff --git a/lxqt-config-input/translations/lxqt-config-input_cs.ts b/lxqt-config-input/translations/lxqt-config-input_cs.ts new file mode 100644 index 0000000..50e5590 --- /dev/null +++ b/lxqt-config-input/translations/lxqt-config-input_cs.ts @@ -0,0 +1,253 @@ + + + + + KeyboardConfig + + + Form + + + + + Cursor flash time: + + + + + <b>Keyboard</b> + + + + + Beep when there is an error of keyboard input + + + + + ms + + + + + Character Repeat + + + + + + Long + + + + + Repeat delay: + + + + + + Short + + + + + Repeat interval: + + + + + Type in the following box to test your keyboard settings + + + + + + 0 + + + + + KeyboardLayoutConfig + + + <b>Keyboard Layout</b> + + + + + Layout + + + + + Variant + + + + + &Add + + + + + &Remove + + + + + up + + + + + down + + + + + Keyboard model: + + + + + Keys to change layout: + + + + + None + + + + + <html><head/><body><p><span style=" font-weight:600;">Note</span>: If you are using an <span style=" font-weight:600;">input method</span>, such as IBus, uim, fcitx, or gcin, the settings here <span style=" font-weight:600;">might not work</span> because they are overridden by the input methods.</p></body></html> + + + + + MouseConfig + + + Form + + + + + <b>Mouse</b> + + + + + Motion + + + + + High + + + + + Fast + + + + + Sensitivity: + + + + + Low + + + + + Acceleration: + + + + + Slow + + + + + + 0 + + + + + Double click interval: + + + + + ms + + + + + Wheel scroll lines: + + + + + Left handed (Swap left and right mouse buttons) + + + + + Single click to activate items + + + + + QObject + + + Keyboard and Mouse Settings + + + + + Mouse + + + + + Cursor + + + + + Keyboard + + + + + Keyboard Layout + + + + + SelectKeyboardLayoutDialog + + + Select a keyboard layout + + + + + Keyboard layout + + + + + Variant + + + + diff --git a/lxqt-config-input/translations/lxqt-config-input_da.ts b/lxqt-config-input/translations/lxqt-config-input_da.ts new file mode 100644 index 0000000..24023a7 --- /dev/null +++ b/lxqt-config-input/translations/lxqt-config-input_da.ts @@ -0,0 +1,312 @@ + + + + + KeyboardConfig + + + Form + + + + + Cursor flash time: + + + + + <b>Keyboard</b> + + + + + Beep when there is an error of keyboard input + + + + + ms + + + + + Character Repeat + + + + + + Long + Lang + + + + Repeat delay: + Interval mellem gentagelser: + + + + + Short + Kort + + + + Repeat interval: + Gentagelsesinterval: + + + + Type in the following box to test your keyboard settings + + + + + + 0 + + + + + KeyboardLayoutConfig + + + <b>Keyboard Layout</b> + + + + + Layout + + + + + Variant + + + + + &Add + + + + + &Remove + + + + + up + + + + + down + + + + + Keyboard model: + + + + + Keys to change layout: + + + + + None + + + + + <html><head/><body><p><span style=" font-weight:600;">Note</span>: If you are using an <span style=" font-weight:600;">input method</span>, such as IBus, uim, fcitx, or gcin, the settings here <span style=" font-weight:600;">might not work</span> because they are overridden by the input methods.</p></body></html> + + + + + MainDialog + + Input Device Preferences + Enhedspræference + + + Motion + Bevægelse + + + High + Høj + + + Fast + Hurtig + + + Sensitivity: + Følsomhed: + + + Low + Lav + + + Acceleration: + Enhedspræference + + + Slow + Langsom + + + Left handed (Swap left and right mouse buttons) + Venstrehåndet (Byt rundt på venstre og højre museknap) + + + Mouse + Mus + + + Long + Lang + + + Repeat delay: + Interval mellem gentagelser: + + + Short + Kort + + + Repeat interval: + Gentagelsesinterval: + + + + MouseConfig + + + Form + + + + + <b>Mouse</b> + + + + + Motion + Bevægelse + + + + High + Høj + + + + Fast + Hurtig + + + + Sensitivity: + Følsomhed: + + + + Low + Lav + + + + Acceleration: + Enhedspræference + + + + Slow + Langsom + + + + + 0 + + + + + Double click interval: + + + + + ms + + + + + Wheel scroll lines: + + + + + Left handed (Swap left and right mouse buttons) + Venstrehåndet (Byt rundt på venstre og højre museknap) + + + + Single click to activate items + + + + + QObject + + + Keyboard and Mouse Settings + + + + + Mouse + Mus + + + + Cursor + + + + + Keyboard + + + + + Keyboard Layout + + + + + SelectKeyboardLayoutDialog + + + Select a keyboard layout + + + + + Keyboard layout + + + + + Variant + + + + diff --git a/lxqt-config-input/translations/lxqt-config-input_de.desktop b/lxqt-config-input/translations/lxqt-config-input_de.desktop new file mode 100644 index 0000000..da426fc --- /dev/null +++ b/lxqt-config-input/translations/lxqt-config-input_de.desktop @@ -0,0 +1,4 @@ +# Translations +Name[de]=Tastatur und Maus +GenericName[de]=Eingabegerätekonfiguration +Comment[de]=Tastatur, Maus und andere Eingabegeräte konfigurieren diff --git a/lxqt-config-input/translations/lxqt-config-input_de.ts b/lxqt-config-input/translations/lxqt-config-input_de.ts new file mode 100644 index 0000000..4f0f21c --- /dev/null +++ b/lxqt-config-input/translations/lxqt-config-input_de.ts @@ -0,0 +1,253 @@ + + + + + KeyboardConfig + + + Form + Dialogfenster + + + + Cursor flash time: + Cursorblinkrate: + + + + <b>Keyboard</b> + <b>Tastatur</b> + + + + Beep when there is an error of keyboard input + Signalton bei Fehleingaben + + + + ms + ms + + + + Character Repeat + Zeichenwiederholung + + + + + Long + Lang + + + + Repeat delay: + Verzögerung: + + + + + Short + Kurz + + + + Repeat interval: + Geschwindigkeit: + + + + Type in the following box to test your keyboard settings + Testbereich für Tastatureinstellungen + + + + + 0 + 0 + + + + KeyboardLayoutConfig + + + <b>Keyboard Layout</b> + <b>Tastenbelegung</b> + + + + Layout + Belegung + + + + Variant + Variante + + + + &Add + H&inzufügen + + + + &Remove + &Entfernen + + + + up + Nach oben + + + + down + Nach unten + + + + Keyboard model: + Tastatur-Modell: + + + + Keys to change layout: + Tastenkombination zum Ändern der Belegung: + + + + None + Keine + + + + <html><head/><body><p><span style=" font-weight:600;">Note</span>: If you are using an <span style=" font-weight:600;">input method</span>, such as IBus, uim, fcitx, or gcin, the settings here <span style=" font-weight:600;">might not work</span> because they are overridden by the input methods.</p></body></html> + <html><head/><body><p><span style=" font-weight:600;">Anmerkung</span>: Falls Sie eine <span style=" font-weight:600;">Eingabemethode</span> wie IBus, uim, fcitx oder gcin verwenden, werden die Einstellungen hier <span style=" font-weight:600;">möglicherweise nicht funktionieren</span>, weil sie von den Eingabemethoden aufgehoben werden.</p></body></html> + + + + MouseConfig + + + Form + Dialogfenster + + + + <b>Mouse</b> + <b>Maus</b> + + + + Motion + Bewegung + + + + High + Hoch + + + + Fast + Schnell + + + + Sensitivity: + Empfindlichkeit: + + + + Low + Niedrig + + + + Acceleration: + Beschleunigung: + + + + Slow + Langsam + + + + + 0 + 0 + + + + Double click interval: + Doppelklickgeschwindigkeit: + + + + ms + ms + + + + Wheel scroll lines: + Mausrad erzeugt Bildlauf um ... Zeilen: + + + + Left handed (Swap left and right mouse buttons) + Linkshändige Bedienung (linke und rechte Maustaste vertauschen) + + + + Single click to activate items + Einfacher Klick aktiviert Elemente + + + + QObject + + + Keyboard and Mouse Settings + Einstellungen von Tastatur und Maus + + + + Mouse + Maus + + + + Cursor + Cursor + + + + Keyboard + Tastatur + + + + Keyboard Layout + Tastenbelegung + + + + SelectKeyboardLayoutDialog + + + Select a keyboard layout + Auswählen der Tastenbelegung + + + + Keyboard layout + Tastenbelegung + + + + Variant + Variante + + + diff --git a/lxqt-config-input/translations/lxqt-config-input_es.ts b/lxqt-config-input/translations/lxqt-config-input_es.ts new file mode 100644 index 0000000..4451382 --- /dev/null +++ b/lxqt-config-input/translations/lxqt-config-input_es.ts @@ -0,0 +1,332 @@ + + + + + KeyboardConfig + + + Form + + + + + Cursor flash time: + + + + + <b>Keyboard</b> + + + + + Beep when there is an error of keyboard input + Pitar cuando ocurra un error de entrada del teclado + + + + ms + + + + + Character Repeat + Repetición de caracteres + + + + + Long + Largo + + + + Repeat delay: + Retardo de repetición: + + + + + Short + Corto + + + + Repeat interval: + Intervalo de repetición: + + + + Type in the following box to test your keyboard settings + Escriba en el siguiente cuadro para probar la configuración + + + + + 0 + 0 + + + + KeyboardLayoutConfig + + + <b>Keyboard Layout</b> + + + + + Layout + + + + + Variant + + + + + &Add + + + + + &Remove + + + + + up + + + + + down + + + + + Keyboard model: + + + + + Keys to change layout: + + + + + None + + + + + <html><head/><body><p><span style=" font-weight:600;">Note</span>: If you are using an <span style=" font-weight:600;">input method</span>, such as IBus, uim, fcitx, or gcin, the settings here <span style=" font-weight:600;">might not work</span> because they are overridden by the input methods.</p></body></html> + + + + + MainDialog + + Input Device Preferences + Preferencias del dispositivo de entrada + + + Motion + Movimiento + + + High + Alta + + + Fast + Rápido + + + Sensitivity: + Sensibilidad: + + + Low + Baja + + + Acceleration: + Aceleración: + + + Slow + Lento + + + 0 + 0 + + + Left handed (Swap left and right mouse buttons) + Zurdo (invertir botones izquierdo y derecho del ratón) + + + Mouse + Ratón + + + Character Repeat + Repetición de caracteres + + + Long + Largo + + + Repeat delay: + Retardo de repetición: + + + Short + Corto + + + Repeat interval: + Intervalo de repetición: + + + Type in the following box to test your keyboard settings + Escriba en el siguiente cuadro para probar la configuración + + + Beep when there is an error of keyboard input + Pitar cuando ocurra un error de entrada del teclado + + + Keyboard + Teclado + + + + MouseConfig + + + Form + + + + + <b>Mouse</b> + + + + + Motion + Movimiento + + + + High + Alta + + + + Fast + Rápido + + + + Sensitivity: + Sensibilidad: + + + + Low + Baja + + + + Acceleration: + Aceleración: + + + + Slow + Lento + + + + + 0 + 0 + + + + Double click interval: + + + + + ms + + + + + Wheel scroll lines: + + + + + Left handed (Swap left and right mouse buttons) + Zurdo (invertir botones izquierdo y derecho del ratón) + + + + Single click to activate items + + + + + QObject + + + Keyboard and Mouse Settings + + + + + Mouse + Ratón + + + + Cursor + + + + + Keyboard + Teclado + + + + Keyboard Layout + + + + + SelectKeyboardLayoutDialog + + + Select a keyboard layout + + + + + Keyboard layout + + + + + Variant + + + + diff --git a/lxqt-config-input/translations/lxqt-config-input_eu.ts b/lxqt-config-input/translations/lxqt-config-input_eu.ts new file mode 100644 index 0000000..5576c3f --- /dev/null +++ b/lxqt-config-input/translations/lxqt-config-input_eu.ts @@ -0,0 +1,324 @@ + + + + + KeyboardConfig + + + Form + + + + + Cursor flash time: + + + + + <b>Keyboard</b> + + + + + Beep when there is an error of keyboard input + + + + + ms + + + + + Character Repeat + Karaktere-errepikapena + + + + + Long + Luzea + + + + Repeat delay: + Errepikatze atzerapena: + + + + + Short + Laburra + + + + Repeat interval: + Errepikatze tartea: + + + + Type in the following box to test your keyboard settings + Idatzi ondorengo testu-koadroan zure teklatuaren ezarpenak probatzeko + + + + + 0 + 0 + + + + KeyboardLayoutConfig + + + <b>Keyboard Layout</b> + + + + + Layout + + + + + Variant + + + + + &Add + + + + + &Remove + + + + + up + + + + + down + + + + + Keyboard model: + + + + + Keys to change layout: + + + + + None + + + + + <html><head/><body><p><span style=" font-weight:600;">Note</span>: If you are using an <span style=" font-weight:600;">input method</span>, such as IBus, uim, fcitx, or gcin, the settings here <span style=" font-weight:600;">might not work</span> because they are overridden by the input methods.</p></body></html> + + + + + MainDialog + + Input Device Preferences + Sarrerako gailuaren hobespenak + + + Motion + Mugimendua + + + High + Altua + + + Fast + Azkarra + + + Sensitivity: + Sentikortasuna: + + + Low + Baxua + + + Acceleration: + Azelerazioa: + + + Slow + Mantsoa + + + 0 + 0 + + + Mouse + Sagua + + + Character Repeat + Karaktere-errepikapena + + + Long + Luzea + + + Repeat delay: + Errepikatze atzerapena: + + + Short + Laburra + + + Repeat interval: + Errepikatze tartea: + + + Type in the following box to test your keyboard settings + Idatzi ondorengo testu-koadroan zure teklatuaren ezarpenak probatzeko + + + Keyboard + Teklatua + + + + MouseConfig + + + Form + + + + + <b>Mouse</b> + + + + + Motion + Mugimendua + + + + High + Altua + + + + Fast + Azkarra + + + + Sensitivity: + Sentikortasuna: + + + + Low + Baxua + + + + Acceleration: + Azelerazioa: + + + + Slow + Mantsoa + + + + + 0 + 0 + + + + Double click interval: + + + + + ms + + + + + Wheel scroll lines: + + + + + Left handed (Swap left and right mouse buttons) + + + + + Single click to activate items + + + + + QObject + + + Keyboard and Mouse Settings + + + + + Mouse + Sagua + + + + Cursor + + + + + Keyboard + Teklatua + + + + Keyboard Layout + + + + + SelectKeyboardLayoutDialog + + + Select a keyboard layout + + + + + Keyboard layout + + + + + Variant + + + + diff --git a/lxqt-config-input/translations/lxqt-config-input_fi.ts b/lxqt-config-input/translations/lxqt-config-input_fi.ts new file mode 100644 index 0000000..315f447 --- /dev/null +++ b/lxqt-config-input/translations/lxqt-config-input_fi.ts @@ -0,0 +1,332 @@ + + + + + KeyboardConfig + + + Form + + + + + Cursor flash time: + + + + + <b>Keyboard</b> + + + + + Beep when there is an error of keyboard input + Piippaa kun näppäimistön näppäilyssä tapahtuu virhe + + + + ms + + + + + Character Repeat + Merkin toisto + + + + + Long + Pitkä + + + + Repeat delay: + Toiston viive: + + + + + Short + Lyhyt + + + + Repeat interval: + Toistoväli: + + + + Type in the following box to test your keyboard settings + Voit kokeilla näppäimistön asetuksia alla olevaan laatikkoon + + + + + 0 + 0 + + + + KeyboardLayoutConfig + + + <b>Keyboard Layout</b> + + + + + Layout + + + + + Variant + + + + + &Add + + + + + &Remove + + + + + up + + + + + down + + + + + Keyboard model: + + + + + Keys to change layout: + + + + + None + + + + + <html><head/><body><p><span style=" font-weight:600;">Note</span>: If you are using an <span style=" font-weight:600;">input method</span>, such as IBus, uim, fcitx, or gcin, the settings here <span style=" font-weight:600;">might not work</span> because they are overridden by the input methods.</p></body></html> + + + + + MainDialog + + Input Device Preferences + Syötelaitteiden asetukset + + + Motion + Liike + + + High + Suuri + + + Fast + Nopea + + + Sensitivity: + Herkkyys: + + + Low + Vähäinen + + + Acceleration: + Kiihdytys: + + + Slow + Hidas + + + 0 + 0 + + + Left handed (Swap left and right mouse buttons) + Vasenkätinen (vaihda oikean ja vasemman hiiren napin paikkoja) + + + Mouse + Hiiri + + + Character Repeat + Merkin toisto + + + Long + Pitkä + + + Repeat delay: + Toiston viive: + + + Short + Lyhyt + + + Repeat interval: + Toistoväli: + + + Type in the following box to test your keyboard settings + Voit kokeilla näppäimistön asetuksia alla olevaan laatikkoon + + + Beep when there is an error of keyboard input + Piippaa kun näppäimistön näppäilyssä tapahtuu virhe + + + Keyboard + Näppäimistö + + + + MouseConfig + + + Form + + + + + <b>Mouse</b> + + + + + Motion + Liike + + + + High + Suuri + + + + Fast + Nopea + + + + Sensitivity: + Herkkyys: + + + + Low + Vähäinen + + + + Acceleration: + Kiihdytys: + + + + Slow + Hidas + + + + + 0 + 0 + + + + Double click interval: + + + + + ms + + + + + Wheel scroll lines: + + + + + Left handed (Swap left and right mouse buttons) + Vasenkätinen (vaihda oikean ja vasemman hiiren napin paikkoja) + + + + Single click to activate items + + + + + QObject + + + Keyboard and Mouse Settings + + + + + Mouse + Hiiri + + + + Cursor + + + + + Keyboard + Näppäimistö + + + + Keyboard Layout + + + + + SelectKeyboardLayoutDialog + + + Select a keyboard layout + + + + + Keyboard layout + + + + + Variant + + + + diff --git a/lxqt-config-input/translations/lxqt-config-input_fr.ts b/lxqt-config-input/translations/lxqt-config-input_fr.ts new file mode 100644 index 0000000..c408867 --- /dev/null +++ b/lxqt-config-input/translations/lxqt-config-input_fr.ts @@ -0,0 +1,332 @@ + + + + + KeyboardConfig + + + Form + + + + + Cursor flash time: + + + + + <b>Keyboard</b> + + + + + Beep when there is an error of keyboard input + Émettre un son lors d'une erreur d'entrée sur le clavier + + + + ms + + + + + Character Repeat + Répétition de caractère + + + + + Long + Long + + + + Repeat delay: + Délai de répétition : + + + + + Short + Court + + + + Repeat interval: + Intervalle de répétition : + + + + Type in the following box to test your keyboard settings + Tapez dans le champ ci-dessous pour tester vos paramètres clavier + + + + + 0 + 0 + + + + KeyboardLayoutConfig + + + <b>Keyboard Layout</b> + + + + + Layout + + + + + Variant + + + + + &Add + + + + + &Remove + + + + + up + + + + + down + + + + + Keyboard model: + + + + + Keys to change layout: + + + + + None + + + + + <html><head/><body><p><span style=" font-weight:600;">Note</span>: If you are using an <span style=" font-weight:600;">input method</span>, such as IBus, uim, fcitx, or gcin, the settings here <span style=" font-weight:600;">might not work</span> because they are overridden by the input methods.</p></body></html> + + + + + MainDialog + + Input Device Preferences + Préférences des périphériques d'entrée + + + Motion + Mouvement + + + High + Forte + + + Fast + Rapide + + + Sensitivity: + Sensibilité : + + + Low + Faible + + + Acceleration: + Accélération : + + + Slow + Lente + + + 0 + 0 + + + Left handed (Swap left and right mouse buttons) + Gaucher (inverse les boutons droit et gauche de la souris) + + + Mouse + Souris + + + Character Repeat + Répétition de caractère + + + Long + Long + + + Repeat delay: + Délai de répétition : + + + Short + Court + + + Repeat interval: + Intervalle de répétition : + + + Type in the following box to test your keyboard settings + Tapez dans le champ ci-dessous pour tester vos paramètres clavier + + + Beep when there is an error of keyboard input + Émettre un son lors d'une erreur d'entrée sur le clavier + + + Keyboard + Clavier + + + + MouseConfig + + + Form + + + + + <b>Mouse</b> + + + + + Motion + Mouvement + + + + High + Forte + + + + Fast + Rapide + + + + Sensitivity: + Sensibilité : + + + + Low + Faible + + + + Acceleration: + Accélération : + + + + Slow + Lente + + + + + 0 + 0 + + + + Double click interval: + + + + + ms + + + + + Wheel scroll lines: + + + + + Left handed (Swap left and right mouse buttons) + Gaucher (inverse les boutons droit et gauche de la souris) + + + + Single click to activate items + + + + + QObject + + + Keyboard and Mouse Settings + + + + + Mouse + Souris + + + + Cursor + + + + + Keyboard + Clavier + + + + Keyboard Layout + + + + + SelectKeyboardLayoutDialog + + + Select a keyboard layout + + + + + Keyboard layout + + + + + Variant + + + + diff --git a/lxqt-config-input/translations/lxqt-config-input_gl.ts b/lxqt-config-input/translations/lxqt-config-input_gl.ts new file mode 100644 index 0000000..b4d6ba8 --- /dev/null +++ b/lxqt-config-input/translations/lxqt-config-input_gl.ts @@ -0,0 +1,332 @@ + + + + + KeyboardConfig + + + Form + + + + + Cursor flash time: + + + + + <b>Keyboard</b> + + + + + Beep when there is an error of keyboard input + Pitar cando se produza un erro de entrada de teclado + + + + ms + + + + + Character Repeat + Repetición de caracteres + + + + + Long + Longa + + + + Repeat delay: + Atraso da repetición: + + + + + Short + Curta + + + + Repeat interval: + Intervalo de repetición: + + + + Type in the following box to test your keyboard settings + Escriba na seguinte caixa para probar os axustes do teclado + + + + + 0 + 0 + + + + KeyboardLayoutConfig + + + <b>Keyboard Layout</b> + + + + + Layout + + + + + Variant + + + + + &Add + + + + + &Remove + + + + + up + + + + + down + + + + + Keyboard model: + + + + + Keys to change layout: + + + + + None + + + + + <html><head/><body><p><span style=" font-weight:600;">Note</span>: If you are using an <span style=" font-weight:600;">input method</span>, such as IBus, uim, fcitx, or gcin, the settings here <span style=" font-weight:600;">might not work</span> because they are overridden by the input methods.</p></body></html> + + + + + MainDialog + + Input Device Preferences + Preferencias do dispositivos de entrada + + + Motion + Movemento + + + High + Alto + + + Fast + Rápido + + + Sensitivity: + Sensibilidade: + + + Low + Baixa + + + Acceleration: + Aceleración: + + + Slow + Lenta + + + 0 + 0 + + + Left handed (Swap left and right mouse buttons) + Zurdo (Intercambiar botóns dereito e esquerdo do rato) + + + Mouse + Rato + + + Character Repeat + Repetición de caracteres + + + Long + Longa + + + Repeat delay: + Atraso da repetición: + + + Short + Curta + + + Repeat interval: + Intervalo de repetición: + + + Type in the following box to test your keyboard settings + Escriba na seguinte caixa para probar os axustes do teclado + + + Beep when there is an error of keyboard input + Pitar cando se produza un erro de entrada de teclado + + + Keyboard + Teclado + + + + MouseConfig + + + Form + + + + + <b>Mouse</b> + + + + + Motion + Movemento + + + + High + Alto + + + + Fast + Rápido + + + + Sensitivity: + Sensibilidade: + + + + Low + Baixa + + + + Acceleration: + Aceleración: + + + + Slow + Lenta + + + + + 0 + 0 + + + + Double click interval: + + + + + ms + + + + + Wheel scroll lines: + + + + + Left handed (Swap left and right mouse buttons) + Zurdo (Intercambiar botóns dereito e esquerdo do rato) + + + + Single click to activate items + + + + + QObject + + + Keyboard and Mouse Settings + + + + + Mouse + Rato + + + + Cursor + + + + + Keyboard + Teclado + + + + Keyboard Layout + + + + + SelectKeyboardLayoutDialog + + + Select a keyboard layout + + + + + Keyboard layout + + + + + Variant + + + + diff --git a/lxqt-config-input/translations/lxqt-config-input_hr.ts b/lxqt-config-input/translations/lxqt-config-input_hr.ts new file mode 100644 index 0000000..b78fc03 --- /dev/null +++ b/lxqt-config-input/translations/lxqt-config-input_hr.ts @@ -0,0 +1,328 @@ + + + + + KeyboardConfig + + + Form + + + + + Cursor flash time: + + + + + <b>Keyboard</b> + + + + + Beep when there is an error of keyboard input + + + + + ms + + + + + Character Repeat + Ponavljanje znaka + + + + + Long + Dugačko + + + + Repeat delay: + Odgoda ponavljanja: + + + + + Short + Kratko + + + + Repeat interval: + Interval ponavljanja: + + + + Type in the following box to test your keyboard settings + Tipkajte u slijedeće polje da biste testirali postavke tipkovnice + + + + + 0 + 0 + + + + KeyboardLayoutConfig + + + <b>Keyboard Layout</b> + + + + + Layout + + + + + Variant + + + + + &Add + + + + + &Remove + + + + + up + + + + + down + + + + + Keyboard model: + + + + + Keys to change layout: + + + + + None + + + + + <html><head/><body><p><span style=" font-weight:600;">Note</span>: If you are using an <span style=" font-weight:600;">input method</span>, such as IBus, uim, fcitx, or gcin, the settings here <span style=" font-weight:600;">might not work</span> because they are overridden by the input methods.</p></body></html> + + + + + MainDialog + + Input Device Preferences + Osobitosti ulaznog uređaja + + + Motion + Pokret: + + + High + Visok + + + Fast + Brzo + + + Sensitivity: + Osijetljivost: + + + Low + Nisko + + + Acceleration: + Ubrzanje: + + + Slow + Sporo + + + 0 + 0 + + + Left handed (Swap left and right mouse buttons) + Ljevoruki (premješta lijevo i desno dugme miša) + + + Mouse + Miš + + + Character Repeat + Ponavljanje znaka + + + Long + Dugačko + + + Repeat delay: + Odgoda ponavljanja: + + + Short + Kratko + + + Repeat interval: + Interval ponavljanja: + + + Type in the following box to test your keyboard settings + Tipkajte u slijedeće polje da biste testirali postavke tipkovnice + + + Keyboard + Tipkovnica + + + + MouseConfig + + + Form + + + + + <b>Mouse</b> + + + + + Motion + Pokret: + + + + High + Visok + + + + Fast + Brzo + + + + Sensitivity: + Osijetljivost: + + + + Low + Nisko + + + + Acceleration: + Ubrzanje: + + + + Slow + Sporo + + + + + 0 + 0 + + + + Double click interval: + + + + + ms + + + + + Wheel scroll lines: + + + + + Left handed (Swap left and right mouse buttons) + Ljevoruki (premješta lijevo i desno dugme miša) + + + + Single click to activate items + + + + + QObject + + + Keyboard and Mouse Settings + + + + + Mouse + Miš + + + + Cursor + + + + + Keyboard + Tipkovnica + + + + Keyboard Layout + + + + + SelectKeyboardLayoutDialog + + + Select a keyboard layout + + + + + Keyboard layout + + + + + Variant + + + + diff --git a/lxqt-config-input/translations/lxqt-config-input_id.ts b/lxqt-config-input/translations/lxqt-config-input_id.ts new file mode 100644 index 0000000..b5ee78b --- /dev/null +++ b/lxqt-config-input/translations/lxqt-config-input_id.ts @@ -0,0 +1,332 @@ + + + + + KeyboardConfig + + + Form + + + + + Cursor flash time: + + + + + <b>Keyboard</b> + + + + + Beep when there is an error of keyboard input + Bip ketika ada galat masukan papan tik + + + + ms + + + + + Character Repeat + Pengulangan Karakter + + + + + Long + Lama + + + + Repeat delay: + Tundaan pengulangan: + + + + + Short + Singkat + + + + Repeat interval: + Interval pengulangan: + + + + Type in the following box to test your keyboard settings + Ketik dalam kotak berikut untuk menguji pengaturan papan tik Anda + + + + + 0 + 0 + + + + KeyboardLayoutConfig + + + <b>Keyboard Layout</b> + + + + + Layout + + + + + Variant + + + + + &Add + + + + + &Remove + + + + + up + + + + + down + + + + + Keyboard model: + + + + + Keys to change layout: + + + + + None + + + + + <html><head/><body><p><span style=" font-weight:600;">Note</span>: If you are using an <span style=" font-weight:600;">input method</span>, such as IBus, uim, fcitx, or gcin, the settings here <span style=" font-weight:600;">might not work</span> because they are overridden by the input methods.</p></body></html> + + + + + MainDialog + + Input Device Preferences + Preferensi Perangkat Masukan + + + Motion + Gerakan + + + High + Tinggi + + + Fast + Cepat + + + Sensitivity: + Sensitivitas: + + + Low + Rendah + + + Acceleration: + Akselerasi: + + + Slow + Lambat + + + 0 + 0 + + + Left handed (Swap left and right mouse buttons) + Kidal (Tukar tombol tetikus kiri dan kanan) + + + Mouse + Tetikus + + + Character Repeat + Pengulangan Karakter + + + Long + Lama + + + Repeat delay: + Tundaan pengulangan: + + + Short + Singkat + + + Repeat interval: + Interval pengulangan: + + + Type in the following box to test your keyboard settings + Ketik dalam kotak berikut untuk menguji pengaturan papan tik Anda + + + Beep when there is an error of keyboard input + Bip ketika ada galat masukan papan tik + + + Keyboard + Papan tik + + + + MouseConfig + + + Form + + + + + <b>Mouse</b> + + + + + Motion + Gerakan + + + + High + Tinggi + + + + Fast + Cepat + + + + Sensitivity: + Sensitivitas: + + + + Low + Rendah + + + + Acceleration: + Akselerasi: + + + + Slow + Lambat + + + + + 0 + 0 + + + + Double click interval: + + + + + ms + + + + + Wheel scroll lines: + + + + + Left handed (Swap left and right mouse buttons) + Kidal (Tukar tombol tetikus kiri dan kanan) + + + + Single click to activate items + + + + + QObject + + + Keyboard and Mouse Settings + + + + + Mouse + Tetikus + + + + Cursor + + + + + Keyboard + Papan tik + + + + Keyboard Layout + + + + + SelectKeyboardLayoutDialog + + + Select a keyboard layout + + + + + Keyboard layout + + + + + Variant + + + + diff --git a/lxqt-config-input/translations/lxqt-config-input_is.ts b/lxqt-config-input/translations/lxqt-config-input_is.ts new file mode 100644 index 0000000..18808fa --- /dev/null +++ b/lxqt-config-input/translations/lxqt-config-input_is.ts @@ -0,0 +1,253 @@ + + + + + KeyboardConfig + + + Form + + + + + Cursor flash time: + + + + + <b>Keyboard</b> + + + + + Beep when there is an error of keyboard input + + + + + ms + + + + + Character Repeat + + + + + + Long + + + + + Repeat delay: + + + + + + Short + + + + + Repeat interval: + + + + + Type in the following box to test your keyboard settings + + + + + + 0 + + + + + KeyboardLayoutConfig + + + <b>Keyboard Layout</b> + + + + + Layout + + + + + Variant + + + + + &Add + + + + + &Remove + + + + + up + + + + + down + + + + + Keyboard model: + + + + + Keys to change layout: + + + + + None + + + + + <html><head/><body><p><span style=" font-weight:600;">Note</span>: If you are using an <span style=" font-weight:600;">input method</span>, such as IBus, uim, fcitx, or gcin, the settings here <span style=" font-weight:600;">might not work</span> because they are overridden by the input methods.</p></body></html> + + + + + MouseConfig + + + Form + + + + + <b>Mouse</b> + + + + + Motion + + + + + High + + + + + Fast + + + + + Sensitivity: + + + + + Low + + + + + Acceleration: + + + + + Slow + + + + + + 0 + + + + + Double click interval: + + + + + ms + + + + + Wheel scroll lines: + + + + + Left handed (Swap left and right mouse buttons) + + + + + Single click to activate items + + + + + QObject + + + Keyboard and Mouse Settings + + + + + Mouse + + + + + Cursor + + + + + Keyboard + + + + + Keyboard Layout + + + + + SelectKeyboardLayoutDialog + + + Select a keyboard layout + + + + + Keyboard layout + + + + + Variant + + + + diff --git a/lxqt-config-input/translations/lxqt-config-input_it.ts b/lxqt-config-input/translations/lxqt-config-input_it.ts new file mode 100644 index 0000000..2fde950 --- /dev/null +++ b/lxqt-config-input/translations/lxqt-config-input_it.ts @@ -0,0 +1,332 @@ + + + + + KeyboardConfig + + + Form + + + + + Cursor flash time: + + + + + <b>Keyboard</b> + + + + + Beep when there is an error of keyboard input + Emetti un beep per gli errori di input da tastiera + + + + ms + + + + + Character Repeat + Ripetizione caratteri + + + + + Long + Lungo + + + + Repeat delay: + Attesa ripetizione: + + + + + Short + Corto + + + + Repeat interval: + Intervallo ripetizione: + + + + Type in the following box to test your keyboard settings + Scrivere nella casella sottostante per provare le impostazioni della tastiera + + + + + 0 + 0 + + + + KeyboardLayoutConfig + + + <b>Keyboard Layout</b> + + + + + Layout + + + + + Variant + + + + + &Add + + + + + &Remove + + + + + up + + + + + down + + + + + Keyboard model: + + + + + Keys to change layout: + + + + + None + + + + + <html><head/><body><p><span style=" font-weight:600;">Note</span>: If you are using an <span style=" font-weight:600;">input method</span>, such as IBus, uim, fcitx, or gcin, the settings here <span style=" font-weight:600;">might not work</span> because they are overridden by the input methods.</p></body></html> + + + + + MainDialog + + Input Device Preferences + Preferenze dei dispositivi di ingresso + + + Motion + Movimento + + + High + Alta + + + Fast + Veloce + + + Sensitivity: + Sensibilità: + + + Low + Bassa + + + Acceleration: + Accelerazione: + + + Slow + Lenta + + + 0 + 0 + + + Left handed (Swap left and right mouse buttons) + Mancino (inverte tasto destro e sinistro del mouse) + + + Mouse + Mouse + + + Character Repeat + Ripetizione caratteri + + + Long + Lungo + + + Repeat delay: + Attesa ripetizione: + + + Short + Corto + + + Repeat interval: + Intervallo ripetizione: + + + Type in the following box to test your keyboard settings + Scrivere nella casella sottostante per provare le impostazioni della tastiera + + + Beep when there is an error of keyboard input + Emetti un beep per gli errori di input da tastiera + + + Keyboard + Tastiera + + + + MouseConfig + + + Form + + + + + <b>Mouse</b> + + + + + Motion + Movimento + + + + High + Alta + + + + Fast + Veloce + + + + Sensitivity: + Sensibilità: + + + + Low + Bassa + + + + Acceleration: + Accelerazione: + + + + Slow + Lenta + + + + + 0 + 0 + + + + Double click interval: + + + + + ms + + + + + Wheel scroll lines: + + + + + Left handed (Swap left and right mouse buttons) + Mancino (inverte tasto destro e sinistro del mouse) + + + + Single click to activate items + + + + + QObject + + + Keyboard and Mouse Settings + + + + + Mouse + Mouse + + + + Cursor + + + + + Keyboard + Tastiera + + + + Keyboard Layout + + + + + SelectKeyboardLayoutDialog + + + Select a keyboard layout + + + + + Keyboard layout + + + + + Variant + + + + diff --git a/lxqt-config-input/translations/lxqt-config-input_ja.desktop b/lxqt-config-input/translations/lxqt-config-input_ja.desktop new file mode 100644 index 0000000..201a9b7 --- /dev/null +++ b/lxqt-config-input/translations/lxqt-config-input_ja.desktop @@ -0,0 +1,5 @@ +# Translations +Name[ja]=キーボードとマウス +GenericName[ja]=入力の設定 +Comment[ja]=キーボードやマウス、その他の入力デバイスの設定 + diff --git a/lxqt-config-input/translations/lxqt-config-input_ja.ts b/lxqt-config-input/translations/lxqt-config-input_ja.ts new file mode 100644 index 0000000..481051d --- /dev/null +++ b/lxqt-config-input/translations/lxqt-config-input_ja.ts @@ -0,0 +1,253 @@ + + + + + KeyboardConfig + + + Form + フォーム + + + + Cursor flash time: + カーソルの点滅時間 + + + + <b>Keyboard</b> + <b>キーボード</b> + + + + Beep when there is an error of keyboard input + キーボード入力にエラーがあるときはビープ音を出す + + + + ms + ms + + + + Character Repeat + 文字リピート + + + + + Long + 長い + + + + Repeat delay: + リピートするまでの遅延: + + + + + Short + 短い + + + + Repeat interval: + リピートの間隔: + + + + Type in the following box to test your keyboard settings + 下のボックスにタイプして、キーボード設定のテストをしてください + + + + + 0 + 0 + + + + KeyboardLayoutConfig + + + <b>Keyboard Layout</b> + <b>キーボードレイアウト</b> + + + + Layout + レイアウト + + + + Variant + バリアント + + + + &Add + 追加(&A) + + + + &Remove + 削除(&R) + + + + up + 上へ + + + + down + 下へ + + + + Keyboard model: + キーボードの型式: + + + + Keys to change layout: + レイアウトを変更するためのキー + + + + None + なし + + + + <html><head/><body><p><span style=" font-weight:600;">Note</span>: If you are using an <span style=" font-weight:600;">input method</span>, such as IBus, uim, fcitx, or gcin, the settings here <span style=" font-weight:600;">might not work</span> because they are overridden by the input methods.</p></body></html> + <html><head/><body><p><span style=" font-weight:600;">注意</span>: <span style=" font-weight:600;">入力メソッド</span>(例: IBus や uim、fcitx、gcin)を使用している場合には, この設定は<span style=" font-weight:600;">機能しないことがあります</span>。入力メソッドが設定を上書きしてしまうためです。</p></body></html> + + + + MouseConfig + + + Form + フォーム + + + + <b>Mouse</b> + <b>マウス</b> + + + + Motion + 動作 + + + + High + 高い + + + + Fast + 速い + + + + Sensitivity: + 感度: + + + + Low + 低い + + + + Acceleration: + 加速: + + + + Slow + 遅い + + + + + 0 + 0 + + + + Double click interval: + ダブルクリックの間隔: + + + + ms + ms + + + + Wheel scroll lines: + ホイールでスクロールする行数: + + + + Left handed (Swap left and right mouse buttons) + 左利き (マウスボタンの左右を入れ替える) + + + + Single click to activate items + シングルクリックでアイテムを有効にする + + + + QObject + + + Keyboard and Mouse Settings + キーボードとマウスの設定 + + + + Mouse + マウス + + + + Cursor + カーソル + + + + Keyboard + キーボード + + + + Keyboard Layout + キーボードレイアウト + + + + SelectKeyboardLayoutDialog + + + Select a keyboard layout + キーボードレイアウトを選択 + + + + Keyboard layout + キーボードレイアウト + + + + Variant + バリアント + + + diff --git a/lxqt-config-input/translations/lxqt-config-input_nl.ts b/lxqt-config-input/translations/lxqt-config-input_nl.ts new file mode 100644 index 0000000..e2fe793 --- /dev/null +++ b/lxqt-config-input/translations/lxqt-config-input_nl.ts @@ -0,0 +1,332 @@ + + + + + KeyboardConfig + + + Form + + + + + Cursor flash time: + + + + + <b>Keyboard</b> + + + + + Beep when there is an error of keyboard input + Piep wanneer er een toetsenbordinvoerfout optreedt + + + + ms + + + + + Character Repeat + Tekenherhaling + + + + + Long + Lang + + + + Repeat delay: + Herhalingsvertraging: + + + + + Short + Kort + + + + Repeat interval: + Herhalingstussenpoze: + + + + Type in the following box to test your keyboard settings + Tik iets in het volgende vak om uw toetsenbordinstellingen uit te proberen + + + + + 0 + 0 + + + + KeyboardLayoutConfig + + + <b>Keyboard Layout</b> + + + + + Layout + + + + + Variant + + + + + &Add + + + + + &Remove + + + + + up + + + + + down + + + + + Keyboard model: + + + + + Keys to change layout: + + + + + None + + + + + <html><head/><body><p><span style=" font-weight:600;">Note</span>: If you are using an <span style=" font-weight:600;">input method</span>, such as IBus, uim, fcitx, or gcin, the settings here <span style=" font-weight:600;">might not work</span> because they are overridden by the input methods.</p></body></html> + + + + + MainDialog + + Input Device Preferences + Voorkeuren van invoerapparaat + + + Motion + Beweging + + + High + Hoog + + + Fast + Snel + + + Sensitivity: + Gevoeligheid: + + + Low + Laag + + + Acceleration: + Versnelling: + + + Slow + Langzaam + + + 0 + 0 + + + Left handed (Swap left and right mouse buttons) + Linkshandig (wissel linkse en rechtse muisknoppen om) + + + Mouse + Muis + + + Character Repeat + Tekenherhaling + + + Long + Lang + + + Repeat delay: + Herhalingsvertraging: + + + Short + Kort + + + Repeat interval: + Herhalingstussenpoze: + + + Type in the following box to test your keyboard settings + Tik iets in het volgende vak om uw toetsenbordinstellingen uit te proberen + + + Beep when there is an error of keyboard input + Piep wanneer er een toetsenbordinvoerfout optreedt + + + Keyboard + Toetsenbord + + + + MouseConfig + + + Form + + + + + <b>Mouse</b> + + + + + Motion + Beweging + + + + High + Hoog + + + + Fast + Snel + + + + Sensitivity: + Gevoeligheid: + + + + Low + Laag + + + + Acceleration: + Versnelling: + + + + Slow + Langzaam + + + + + 0 + 0 + + + + Double click interval: + + + + + ms + + + + + Wheel scroll lines: + + + + + Left handed (Swap left and right mouse buttons) + Linkshandig (wissel linkse en rechtse muisknoppen om) + + + + Single click to activate items + + + + + QObject + + + Keyboard and Mouse Settings + + + + + Mouse + Muis + + + + Cursor + + + + + Keyboard + Toetsenbord + + + + Keyboard Layout + + + + + SelectKeyboardLayoutDialog + + + Select a keyboard layout + + + + + Keyboard layout + + + + + Variant + + + + diff --git a/lxqt-config-input/translations/lxqt-config-input_pa.ts b/lxqt-config-input/translations/lxqt-config-input_pa.ts new file mode 100644 index 0000000..46e7075 --- /dev/null +++ b/lxqt-config-input/translations/lxqt-config-input_pa.ts @@ -0,0 +1,253 @@ + + + + + KeyboardConfig + + + Form + + + + + Cursor flash time: + + + + + <b>Keyboard</b> + + + + + Beep when there is an error of keyboard input + + + + + ms + + + + + Character Repeat + + + + + + Long + + + + + Repeat delay: + + + + + + Short + + + + + Repeat interval: + + + + + Type in the following box to test your keyboard settings + + + + + + 0 + + + + + KeyboardLayoutConfig + + + <b>Keyboard Layout</b> + + + + + Layout + + + + + Variant + + + + + &Add + + + + + &Remove + + + + + up + + + + + down + + + + + Keyboard model: + + + + + Keys to change layout: + + + + + None + + + + + <html><head/><body><p><span style=" font-weight:600;">Note</span>: If you are using an <span style=" font-weight:600;">input method</span>, such as IBus, uim, fcitx, or gcin, the settings here <span style=" font-weight:600;">might not work</span> because they are overridden by the input methods.</p></body></html> + + + + + MouseConfig + + + Form + + + + + <b>Mouse</b> + + + + + Motion + + + + + High + + + + + Fast + + + + + Sensitivity: + + + + + Low + + + + + Acceleration: + + + + + Slow + + + + + + 0 + + + + + Double click interval: + + + + + ms + + + + + Wheel scroll lines: + + + + + Left handed (Swap left and right mouse buttons) + + + + + Single click to activate items + + + + + QObject + + + Keyboard and Mouse Settings + + + + + Mouse + + + + + Cursor + + + + + Keyboard + + + + + Keyboard Layout + + + + + SelectKeyboardLayoutDialog + + + Select a keyboard layout + + + + + Keyboard layout + + + + + Variant + + + + diff --git a/lxqt-config-input/translations/lxqt-config-input_pl.ts b/lxqt-config-input/translations/lxqt-config-input_pl.ts new file mode 100644 index 0000000..792985e --- /dev/null +++ b/lxqt-config-input/translations/lxqt-config-input_pl.ts @@ -0,0 +1,332 @@ + + + + + KeyboardConfig + + + Form + + + + + Cursor flash time: + + + + + <b>Keyboard</b> + + + + + Beep when there is an error of keyboard input + Brzęczyk, gdy wystąpi błąd podczas wprowadzania z klawiatury + + + + ms + + + + + Character Repeat + Powtórzenia znaków + + + + + Long + Długie + + + + Repeat delay: + Opóźnienie powtórki: + + + + + Short + Krótkie + + + + Repeat interval: + Częstotliwość powtarzania: + + + + Type in the following box to test your keyboard settings + Zacznij pisać w okienku, aby przetestować ustawienia swojej klawiatury + + + + + 0 + 0 + + + + KeyboardLayoutConfig + + + <b>Keyboard Layout</b> + + + + + Layout + + + + + Variant + + + + + &Add + + + + + &Remove + + + + + up + + + + + down + + + + + Keyboard model: + + + + + Keys to change layout: + + + + + None + + + + + <html><head/><body><p><span style=" font-weight:600;">Note</span>: If you are using an <span style=" font-weight:600;">input method</span>, such as IBus, uim, fcitx, or gcin, the settings here <span style=" font-weight:600;">might not work</span> because they are overridden by the input methods.</p></body></html> + + + + + MainDialog + + Input Device Preferences + Preferencje urządzeń wejściowych + + + Motion + Ruch + + + High + Wysoka + + + Fast + Szybkie + + + Sensitivity: + Czułość: + + + Low + Niska + + + Acceleration: + Przyspieszenie: + + + Slow + Wolne + + + 0 + 0 + + + Left handed (Swap left and right mouse buttons) + Leworęczna (Zamiana lewego i prawego przycisku myszy) + + + Mouse + Mysz + + + Character Repeat + Powtórzenia znaków + + + Long + Długie + + + Repeat delay: + Opóźnienie powtórki: + + + Short + Krótkie + + + Repeat interval: + Częstotliwość powtarzania: + + + Type in the following box to test your keyboard settings + Zacznij pisać w okienku, aby przetestować ustawienia swojej klawiatury + + + Beep when there is an error of keyboard input + Brzęczyk, gdy wystąpi błąd podczas wprowadzania z klawiatury + + + Keyboard + Klawiatura + + + + MouseConfig + + + Form + + + + + <b>Mouse</b> + + + + + Motion + Ruch + + + + High + Wysoka + + + + Fast + Szybkie + + + + Sensitivity: + Czułość: + + + + Low + Niska + + + + Acceleration: + Przyspieszenie: + + + + Slow + Wolne + + + + + 0 + 0 + + + + Double click interval: + + + + + ms + + + + + Wheel scroll lines: + + + + + Left handed (Swap left and right mouse buttons) + Leworęczna (Zamiana lewego i prawego przycisku myszy) + + + + Single click to activate items + + + + + QObject + + + Keyboard and Mouse Settings + + + + + Mouse + Mysz + + + + Cursor + + + + + Keyboard + Klawiatura + + + + Keyboard Layout + + + + + SelectKeyboardLayoutDialog + + + Select a keyboard layout + + + + + Keyboard layout + + + + + Variant + + + + diff --git a/lxqt-config-input/translations/lxqt-config-input_pt.desktop b/lxqt-config-input/translations/lxqt-config-input_pt.desktop new file mode 100644 index 0000000..565b74f --- /dev/null +++ b/lxqt-config-input/translations/lxqt-config-input_pt.desktop @@ -0,0 +1,4 @@ +# Translations +Name[pt]=Teclado e rato +GenericName[pt]=Definições de introdução +Comment[pt]=Configuração do rato, teclado e outros dispositivos de introdução diff --git a/lxqt-config-input/translations/lxqt-config-input_pt.ts b/lxqt-config-input/translations/lxqt-config-input_pt.ts new file mode 100644 index 0000000..14b85dd --- /dev/null +++ b/lxqt-config-input/translations/lxqt-config-input_pt.ts @@ -0,0 +1,332 @@ + + + + + KeyboardConfig + + + Form + + + + + Cursor flash time: + + + + + <b>Keyboard</b> + + + + + Beep when there is an error of keyboard input + Reproduzir um som se ocorrer um erro de teclado + + + + ms + + + + + Character Repeat + Repetição de caracteres + + + + + Long + Longa + + + + Repeat delay: + Atraso de repetição: + + + + + Short + Curto + + + + Repeat interval: + Intervalo de repetição: + + + + Type in the following box to test your keyboard settings + Escreva algo na caixa de teste abaixo para testar o teclado + + + + + 0 + 0 + + + + KeyboardLayoutConfig + + + <b>Keyboard Layout</b> + + + + + Layout + + + + + Variant + + + + + &Add + + + + + &Remove + + + + + up + + + + + down + + + + + Keyboard model: + + + + + Keys to change layout: + + + + + None + + + + + <html><head/><body><p><span style=" font-weight:600;">Note</span>: If you are using an <span style=" font-weight:600;">input method</span>, such as IBus, uim, fcitx, or gcin, the settings here <span style=" font-weight:600;">might not work</span> because they are overridden by the input methods.</p></body></html> + + + + + MainDialog + + Input Device Preferences + Preferências de dispositivos + + + Motion + Movimento + + + High + Muito rápido + + + Fast + Rápido + + + Sensitivity: + Sensibilidade: + + + Low + Baixa + + + Acceleration: + Aceleração: + + + Slow + Lenta + + + 0 + 0 + + + Left handed (Swap left and right mouse buttons) + Canhoto (inverter botões do rato) + + + Mouse + Rato + + + Character Repeat + Repetição de caracteres + + + Long + Longa + + + Repeat delay: + Atraso de repetição: + + + Short + Curto + + + Repeat interval: + Intervalo de repetição: + + + Type in the following box to test your keyboard settings + Escreva algo na caixa de teste abaixo para testar o teclado + + + Beep when there is an error of keyboard input + Reproduzir um som se ocorrer um erro de teclado + + + Keyboard + Teclado + + + + MouseConfig + + + Form + + + + + <b>Mouse</b> + + + + + Motion + Movimento + + + + High + Muito rápido + + + + Fast + Rápido + + + + Sensitivity: + Sensibilidade: + + + + Low + Baixa + + + + Acceleration: + Aceleração: + + + + Slow + Lenta + + + + + 0 + 0 + + + + Double click interval: + + + + + ms + + + + + Wheel scroll lines: + + + + + Left handed (Swap left and right mouse buttons) + Canhoto (inverter botões do rato) + + + + Single click to activate items + + + + + QObject + + + Keyboard and Mouse Settings + + + + + Mouse + Rato + + + + Cursor + + + + + Keyboard + Teclado + + + + Keyboard Layout + + + + + SelectKeyboardLayoutDialog + + + Select a keyboard layout + + + + + Keyboard layout + + + + + Variant + + + + diff --git a/lxqt-config-input/translations/lxqt-config-input_ru.desktop b/lxqt-config-input/translations/lxqt-config-input_ru.desktop new file mode 100644 index 0000000..6736259 --- /dev/null +++ b/lxqt-config-input/translations/lxqt-config-input_ru.desktop @@ -0,0 +1,4 @@ +# Translations +Comment[ru]=Настроить клавиатуру, мышь и доругие устройства ввода +Name[ru]=Клавиатура и мышь +GenericName[ru]=Настройки ввода \ No newline at end of file diff --git a/lxqt-config-input/translations/lxqt-config-input_ru.ts b/lxqt-config-input/translations/lxqt-config-input_ru.ts new file mode 100644 index 0000000..f1ed4b9 --- /dev/null +++ b/lxqt-config-input/translations/lxqt-config-input_ru.ts @@ -0,0 +1,253 @@ + + + + + KeyboardConfig + + + Form + + + + + Cursor flash time: + Частота мерцания курсора: + + + + <b>Keyboard</b> + <b>Клавиатура</b> + + + + Beep when there is an error of keyboard input + Пищать об ошибке ввода с клавиатуры + + + + ms + мс + + + + Character Repeat + Повтор символа + + + + + Long + Длинная + + + + Repeat delay: + Задержка повтора: + + + + + Short + Короткая + + + + Repeat interval: + Пауза между повтором: + + + + Type in the following box to test your keyboard settings + Поле для проверки настроек клавиатуры + + + + + 0 + + + + + KeyboardLayoutConfig + + + <b>Keyboard Layout</b> + <b>Раскладка клавиатуры</b> + + + + Layout + Раскладка + + + + Variant + Вариант + + + + &Add + &Добавить + + + + &Remove + &Удалить + + + + up + выше + + + + down + ниже + + + + Keyboard model: + Модель клавиатуры: + + + + Keys to change layout: + Клавиши смены раскладки: + + + + None + Нет + + + + <html><head/><body><p><span style=" font-weight:600;">Note</span>: If you are using an <span style=" font-weight:600;">input method</span>, such as IBus, uim, fcitx, or gcin, the settings here <span style=" font-weight:600;">might not work</span> because they are overridden by the input methods.</p></body></html> + <html><head/><body><p><span style=" font-weight:600;">Внимание</span>: Если вы используете <span style=" font-weight:600;">метод ввода</span>, такой как IBus, uim, fcitx, или gcin, настройки здесь <span style=" font-weight:600;">могут не работать</span> поскольку они переопределятся этим методом ввода.</p></body></html> + + + + MouseConfig + + + Form + + + + + <b>Mouse</b> + <b>Мышь</b> + + + + Motion + Движение + + + + High + Высокая + + + + Fast + Быстро + + + + Sensitivity: + Чувствительность: + + + + Low + Низкая + + + + Acceleration: + Ускорение: + + + + Slow + Медленно + + + + + 0 + + + + + Double click interval: + Интервал двойного щелчка: + + + + ms + мс + + + + Wheel scroll lines: + Колёсико перематывает строк: + + + + Left handed (Swap left and right mouse buttons) + Для левшей (поменять функции левой и правой кнопок мыши) + + + + Single click to activate items + Один клик для активации элементов + + + + QObject + + + Keyboard and Mouse Settings + Настройки клавиатуры и мыши + + + + Mouse + Мышь + + + + Cursor + Курсор + + + + Keyboard + Клавиатура + + + + Keyboard Layout + Раскладка клавиатура + + + + SelectKeyboardLayoutDialog + + + Select a keyboard layout + Выбрать раскладку клавиатуры + + + + Keyboard layout + Раскладка клавиатуры + + + + Variant + Вариант + + + diff --git a/lxqt-config-input/translations/lxqt-config-input_ru_RU.desktop b/lxqt-config-input/translations/lxqt-config-input_ru_RU.desktop new file mode 100644 index 0000000..d6c1de1 --- /dev/null +++ b/lxqt-config-input/translations/lxqt-config-input_ru_RU.desktop @@ -0,0 +1,4 @@ +# Translations +Comment[ru_RU]=Настроить клавиатуру, мышь и доругие устройства ввода +Name[ru_RU]=Клавиатура и мышь +GenericName[ru_RU]=Настройки ввода \ No newline at end of file diff --git a/lxqt-config-input/translations/lxqt-config-input_ru_RU.ts b/lxqt-config-input/translations/lxqt-config-input_ru_RU.ts new file mode 100644 index 0000000..e2aee1a --- /dev/null +++ b/lxqt-config-input/translations/lxqt-config-input_ru_RU.ts @@ -0,0 +1,253 @@ + + + + + KeyboardConfig + + + Form + + + + + Cursor flash time: + Частота мерцания курсора: + + + + <b>Keyboard</b> + <b>Клавиатура</b> + + + + Beep when there is an error of keyboard input + Пищать об ошибке ввода с клавиатуры + + + + ms + мс + + + + Character Repeat + Повтор символа + + + + + Long + Длинная + + + + Repeat delay: + Задержка повтора: + + + + + Short + Короткая + + + + Repeat interval: + Пауза между повтором: + + + + Type in the following box to test your keyboard settings + Поле для проверки настроек клавиатуры + + + + + 0 + + + + + KeyboardLayoutConfig + + + <b>Keyboard Layout</b> + <b>Раскладка клавиатуры</b> + + + + Layout + Раскладка + + + + Variant + Вариант + + + + &Add + &Добавить + + + + &Remove + &Удалить + + + + up + выше + + + + down + ниже + + + + Keyboard model: + Модель клавиатуры: + + + + Keys to change layout: + Клавиши смены раскладки: + + + + None + Нет + + + + <html><head/><body><p><span style=" font-weight:600;">Note</span>: If you are using an <span style=" font-weight:600;">input method</span>, such as IBus, uim, fcitx, or gcin, the settings here <span style=" font-weight:600;">might not work</span> because they are overridden by the input methods.</p></body></html> + <html><head/><body><p><span style=" font-weight:600;">Внимание</span>: Если вы используете <span style=" font-weight:600;">метод ввода</span>, такой как IBus, uim, fcitx, или gcin, настройки здесь <span style=" font-weight:600;">могут не работать</span> поскольку они переопределятся этим методом ввода.</p></body></html> + + + + MouseConfig + + + Form + + + + + <b>Mouse</b> + <b>Мышь</b> + + + + Motion + Движение + + + + High + Высокая + + + + Fast + Быстро + + + + Sensitivity: + Чувствительность: + + + + Low + Низкая + + + + Acceleration: + Ускорение: + + + + Slow + Медленно + + + + + 0 + + + + + Double click interval: + Интервал двойного щелчка: + + + + ms + мс + + + + Wheel scroll lines: + Колёсико перематывает строк: + + + + Left handed (Swap left and right mouse buttons) + Для левшей (поменять функции левой и правой кнопок мыши) + + + + Single click to activate items + Один клик для активации элементов + + + + QObject + + + Keyboard and Mouse Settings + Настройки клавиатуры и мыши + + + + Mouse + Мышь + + + + Cursor + Курсор + + + + Keyboard + Клавиатура + + + + Keyboard Layout + Раскладка клавиатура + + + + SelectKeyboardLayoutDialog + + + Select a keyboard layout + Выбрать раскладку клавиатуры + + + + Keyboard layout + Раскладка клавиатуры + + + + Variant + Вариант + + + diff --git a/lxqt-config-input/translations/lxqt-config-input_sv.ts b/lxqt-config-input/translations/lxqt-config-input_sv.ts new file mode 100644 index 0000000..40e66e7 --- /dev/null +++ b/lxqt-config-input/translations/lxqt-config-input_sv.ts @@ -0,0 +1,332 @@ + + + + + KeyboardConfig + + + Form + + + + + Cursor flash time: + + + + + <b>Keyboard</b> + + + + + Beep when there is an error of keyboard input + Avge ett pip när ett fel uppstår vid tangentbordsinmatning + + + + ms + + + + + Character Repeat + Teckenupprepning + + + + + Long + Lång + + + + Repeat delay: + Tid innan upprepning: + + + + + Short + Kort + + + + Repeat interval: + Tid mellan upprepningar: + + + + Type in the following box to test your keyboard settings + För att pröva dina inställningar kan du skriva i följande ruta + + + + + 0 + 0 + + + + KeyboardLayoutConfig + + + <b>Keyboard Layout</b> + + + + + Layout + + + + + Variant + + + + + &Add + + + + + &Remove + + + + + up + + + + + down + + + + + Keyboard model: + + + + + Keys to change layout: + + + + + None + + + + + <html><head/><body><p><span style=" font-weight:600;">Note</span>: If you are using an <span style=" font-weight:600;">input method</span>, such as IBus, uim, fcitx, or gcin, the settings here <span style=" font-weight:600;">might not work</span> because they are overridden by the input methods.</p></body></html> + + + + + MainDialog + + Input Device Preferences + Egenskaper för inmatningsenhet + + + Motion + Rörelse + + + High + Hög + + + Fast + Snabb + + + Sensitivity: + Känslighet: + + + Low + Låg + + + Acceleration: + Acceleration: + + + Slow + Långsam + + + 0 + 0 + + + Left handed (Swap left and right mouse buttons) + Vänsterhänt (byt funktioner för vänster och höger musknapp) + + + Mouse + Mus + + + Character Repeat + Teckenupprepning + + + Long + Lång + + + Repeat delay: + Tid innan upprepning: + + + Short + Kort + + + Repeat interval: + Tid mellan upprepningar: + + + Type in the following box to test your keyboard settings + För att pröva dina inställningar kan du skriva i följande ruta + + + Beep when there is an error of keyboard input + Avge ett pip när ett fel uppstår vid tangentbordsinmatning + + + Keyboard + Tangentbord + + + + MouseConfig + + + Form + + + + + <b>Mouse</b> + + + + + Motion + Rörelse + + + + High + Hög + + + + Fast + Snabb + + + + Sensitivity: + Känslighet: + + + + Low + Låg + + + + Acceleration: + Acceleration: + + + + Slow + Långsam + + + + + 0 + 0 + + + + Double click interval: + + + + + ms + + + + + Wheel scroll lines: + + + + + Left handed (Swap left and right mouse buttons) + Vänsterhänt (byt funktioner för vänster och höger musknapp) + + + + Single click to activate items + + + + + QObject + + + Keyboard and Mouse Settings + + + + + Mouse + Mus + + + + Cursor + + + + + Keyboard + Tangentbord + + + + Keyboard Layout + + + + + SelectKeyboardLayoutDialog + + + Select a keyboard layout + + + + + Keyboard layout + + + + + Variant + + + + diff --git a/lxqt-config-input/translations/lxqt-config-input_uk.ts b/lxqt-config-input/translations/lxqt-config-input_uk.ts new file mode 100644 index 0000000..c806938 --- /dev/null +++ b/lxqt-config-input/translations/lxqt-config-input_uk.ts @@ -0,0 +1,253 @@ + + + + + KeyboardConfig + + + Form + + + + + Cursor flash time: + + + + + <b>Keyboard</b> + + + + + Beep when there is an error of keyboard input + + + + + ms + + + + + Character Repeat + + + + + + Long + + + + + Repeat delay: + + + + + + Short + + + + + Repeat interval: + + + + + Type in the following box to test your keyboard settings + + + + + + 0 + + + + + KeyboardLayoutConfig + + + <b>Keyboard Layout</b> + + + + + Layout + + + + + Variant + + + + + &Add + + + + + &Remove + + + + + up + + + + + down + + + + + Keyboard model: + + + + + Keys to change layout: + + + + + None + + + + + <html><head/><body><p><span style=" font-weight:600;">Note</span>: If you are using an <span style=" font-weight:600;">input method</span>, such as IBus, uim, fcitx, or gcin, the settings here <span style=" font-weight:600;">might not work</span> because they are overridden by the input methods.</p></body></html> + + + + + MouseConfig + + + Form + + + + + <b>Mouse</b> + + + + + Motion + + + + + High + + + + + Fast + + + + + Sensitivity: + + + + + Low + + + + + Acceleration: + + + + + Slow + + + + + + 0 + + + + + Double click interval: + + + + + ms + + + + + Wheel scroll lines: + + + + + Left handed (Swap left and right mouse buttons) + + + + + Single click to activate items + + + + + QObject + + + Keyboard and Mouse Settings + + + + + Mouse + + + + + Cursor + + + + + Keyboard + + + + + Keyboard Layout + + + + + SelectKeyboardLayoutDialog + + + Select a keyboard layout + + + + + Keyboard layout + + + + + Variant + + + + diff --git a/lxqt-config-input/translations/lxqt-config-input_zh_CN.ts b/lxqt-config-input/translations/lxqt-config-input_zh_CN.ts new file mode 100644 index 0000000..70097c9 --- /dev/null +++ b/lxqt-config-input/translations/lxqt-config-input_zh_CN.ts @@ -0,0 +1,332 @@ + + + + + KeyboardConfig + + + Form + + + + + Cursor flash time: + + + + + <b>Keyboard</b> + + + + + Beep when there is an error of keyboard input + 键盘输入出错时蜂鸣 + + + + ms + + + + + Character Repeat + 字符重复 + + + + + Long + + + + + Repeat delay: + 重复延迟: + + + + + Short + + + + + Repeat interval: + 重复间隔: + + + + Type in the following box to test your keyboard settings + 在下面的框中输入字符,以测试键盘设置 + + + + + 0 + 0 + + + + KeyboardLayoutConfig + + + <b>Keyboard Layout</b> + + + + + Layout + + + + + Variant + + + + + &Add + + + + + &Remove + + + + + up + + + + + down + + + + + Keyboard model: + + + + + Keys to change layout: + + + + + None + + + + + <html><head/><body><p><span style=" font-weight:600;">Note</span>: If you are using an <span style=" font-weight:600;">input method</span>, such as IBus, uim, fcitx, or gcin, the settings here <span style=" font-weight:600;">might not work</span> because they are overridden by the input methods.</p></body></html> + + + + + MainDialog + + Input Device Preferences + 输入设备首选项 + + + Motion + 运动 + + + High + + + + Fast + 快速 + + + Sensitivity: + 敏感度: + + + Low + + + + Acceleration: + 加速 : + + + Slow + + + + 0 + 0 + + + Left handed (Swap left and right mouse buttons) + 惯用左手(交换左右鼠标按键) + + + Mouse + 鼠标 + + + Character Repeat + 字符重复 + + + Long + + + + Repeat delay: + 重复延迟: + + + Short + + + + Repeat interval: + 重复间隔: + + + Type in the following box to test your keyboard settings + 在下面的框中输入字符,以测试键盘设置 + + + Beep when there is an error of keyboard input + 键盘输入出错时蜂鸣 + + + Keyboard + 键盘 + + + + MouseConfig + + + Form + + + + + <b>Mouse</b> + + + + + Motion + 运动 + + + + High + + + + + Fast + 快速 + + + + Sensitivity: + 敏感度: + + + + Low + + + + + Acceleration: + 加速 : + + + + Slow + + + + + + 0 + 0 + + + + Double click interval: + + + + + ms + + + + + Wheel scroll lines: + + + + + Left handed (Swap left and right mouse buttons) + 惯用左手(交换左右鼠标按键) + + + + Single click to activate items + + + + + QObject + + + Keyboard and Mouse Settings + + + + + Mouse + 鼠标 + + + + Cursor + + + + + Keyboard + 键盘 + + + + Keyboard Layout + + + + + SelectKeyboardLayoutDialog + + + Select a keyboard layout + + + + + Keyboard layout + + + + + Variant + + + + diff --git a/lxqt-config-input/translations/lxqt-config-input_zh_HK.ts b/lxqt-config-input/translations/lxqt-config-input_zh_HK.ts new file mode 100644 index 0000000..939b260 --- /dev/null +++ b/lxqt-config-input/translations/lxqt-config-input_zh_HK.ts @@ -0,0 +1,253 @@ + + + + + KeyboardConfig + + + Form + + + + + Cursor flash time: + + + + + <b>Keyboard</b> + + + + + Beep when there is an error of keyboard input + + + + + ms + + + + + Character Repeat + + + + + + Long + + + + + Repeat delay: + + + + + + Short + + + + + Repeat interval: + + + + + Type in the following box to test your keyboard settings + + + + + + 0 + + + + + KeyboardLayoutConfig + + + <b>Keyboard Layout</b> + + + + + Layout + + + + + Variant + + + + + &Add + + + + + &Remove + + + + + up + + + + + down + + + + + Keyboard model: + + + + + Keys to change layout: + + + + + None + + + + + <html><head/><body><p><span style=" font-weight:600;">Note</span>: If you are using an <span style=" font-weight:600;">input method</span>, such as IBus, uim, fcitx, or gcin, the settings here <span style=" font-weight:600;">might not work</span> because they are overridden by the input methods.</p></body></html> + + + + + MouseConfig + + + Form + + + + + <b>Mouse</b> + + + + + Motion + + + + + High + + + + + Fast + + + + + Sensitivity: + + + + + Low + + + + + Acceleration: + + + + + Slow + + + + + + 0 + + + + + Double click interval: + + + + + ms + + + + + Wheel scroll lines: + + + + + Left handed (Swap left and right mouse buttons) + + + + + Single click to activate items + + + + + QObject + + + Keyboard and Mouse Settings + + + + + Mouse + + + + + Cursor + + + + + Keyboard + + + + + Keyboard Layout + + + + + SelectKeyboardLayoutDialog + + + Select a keyboard layout + + + + + Keyboard layout + + + + + Variant + + + + diff --git a/lxqt-config-input/translations/lxqt-config-input_zh_TW.ts b/lxqt-config-input/translations/lxqt-config-input_zh_TW.ts new file mode 100644 index 0000000..e1e193b --- /dev/null +++ b/lxqt-config-input/translations/lxqt-config-input_zh_TW.ts @@ -0,0 +1,332 @@ + + + + + KeyboardConfig + + + Form + + + + + Cursor flash time: + + + + + <b>Keyboard</b> + + + + + Beep when there is an error of keyboard input + 鍵盤輸入錯誤時發出嗶聲 + + + + ms + + + + + Character Repeat + 字元重複 + + + + + Long + + + + + Repeat delay: + 重複延遲: + + + + + Short + + + + + Repeat interval: + 重複間隔時間: + + + + Type in the following box to test your keyboard settings + 在下列方框裡輸入文字測試你的鍵盤設定 + + + + + 0 + 0 + + + + KeyboardLayoutConfig + + + <b>Keyboard Layout</b> + + + + + Layout + + + + + Variant + + + + + &Add + + + + + &Remove + + + + + up + + + + + down + + + + + Keyboard model: + + + + + Keys to change layout: + + + + + None + + + + + <html><head/><body><p><span style=" font-weight:600;">Note</span>: If you are using an <span style=" font-weight:600;">input method</span>, such as IBus, uim, fcitx, or gcin, the settings here <span style=" font-weight:600;">might not work</span> because they are overridden by the input methods.</p></body></html> + + + + + MainDialog + + Input Device Preferences + 輸入裝置偏好設定 + + + Motion + 移動 + + + High + + + + Fast + + + + Sensitivity: + 敏感度: + + + Low + + + + Acceleration: + 加速: + + + Slow + + + + 0 + 0 + + + Left handed (Swap left and right mouse buttons) + 左撇子 (對換滑鼠左右鍵) + + + Mouse + 滑鼠 + + + Character Repeat + 字元重複 + + + Long + + + + Repeat delay: + 重複延遲: + + + Short + + + + Repeat interval: + 重複間隔時間: + + + Type in the following box to test your keyboard settings + 在下列方框裡輸入文字測試你的鍵盤設定 + + + Beep when there is an error of keyboard input + 鍵盤輸入錯誤時發出嗶聲 + + + Keyboard + 鍵盤 + + + + MouseConfig + + + Form + + + + + <b>Mouse</b> + + + + + Motion + 移動 + + + + High + + + + + Fast + + + + + Sensitivity: + 敏感度: + + + + Low + + + + + Acceleration: + 加速: + + + + Slow + + + + + + 0 + 0 + + + + Double click interval: + + + + + ms + + + + + Wheel scroll lines: + + + + + Left handed (Swap left and right mouse buttons) + 左撇子 (對換滑鼠左右鍵) + + + + Single click to activate items + + + + + QObject + + + Keyboard and Mouse Settings + + + + + Mouse + 滑鼠 + + + + Cursor + + + + + Keyboard + 鍵盤 + + + + Keyboard Layout + + + + + SelectKeyboardLayoutDialog + + + Select a keyboard layout + + + + + Keyboard layout + + + + + Variant + + + + diff --git a/lxqt-config-monitor/CMakeLists.txt b/lxqt-config-monitor/CMakeLists.txt new file mode 100644 index 0000000..66ef516 --- /dev/null +++ b/lxqt-config-monitor/CMakeLists.txt @@ -0,0 +1,72 @@ +project(lxqt-config-monitor) + +include_directories ( + "${CMAKE_CURRENT_BINARY_DIR}" + ${LXQT_INCLUDE_DIRS} +) + +set(H_FILES + main.h + monitorsettingsdialog.h + monitor.h + monitorwidget.h + xrandr.h + monitorpicture.h +) + +set(CPP_FILES + main.cpp + monitorsettingsdialog.cpp + xrandr.cpp + monitor.cpp + monitorwidget.cpp + timeoutdialog.cpp + monitorpicture.cpp +) + +set(UI_FILES + mainwindow.ui + monitorwidget.ui + timeoutdialog.ui + monitorpicture.ui +) + +qt5_wrap_ui(UI_HEADERS ${UI_FILES}) + +# Translations ********************************** +lxqt_translate_ts(QM_FILES + UPDATE_TRANSLATIONS + ${UPDATE_TRANSLATIONS} + SOURCES + ${H_FILES} + ${CPP_FILES} + ${UI_FILES} + INSTALL_DIR + "${LXQT_TRANSLATIONS_DIR}/${PROJECT_NAME}" +) + +lxqt_app_translation_loader(QM_LOADER ${PROJECT_NAME}) +lxqt_translate_desktop(DESKTOP_FILES SOURCES ${PROJECT_NAME}.desktop.in) + +#************************************************ + +add_executable(${PROJECT_NAME} + ${CPP_FILES} + ${UI_FILES} + ${RESOURCES} + ${QRC_SOURCES} + ${QM_FILES} + ${MOC_SOURCES} + ${DESKTOP_FILES} + ${QM_LOADER} +) + +target_link_libraries(${PROJECT_NAME} + KF5::WindowSystem + Qt5::Widgets + Qt5::X11Extras + ${LXQT_LIBRARIES} +) + +install(TARGETS ${PROJECT_NAME} RUNTIME DESTINATION bin) +install(FILES ${DESKTOP_FILES} DESTINATION "${CMAKE_INSTALL_PREFIX}/share/applications") diff --git a/lxqt-config-monitor/LICENSE b/lxqt-config-monitor/LICENSE new file mode 100644 index 0000000..d7f1051 --- /dev/null +++ b/lxqt-config-monitor/LICENSE @@ -0,0 +1,339 @@ +GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + {description} + Copyright (C) {year} {fullname} + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + {signature of Ty Coon}, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/lxqt-config-monitor/README.md b/lxqt-config-monitor/README.md new file mode 100644 index 0000000..d6afe26 --- /dev/null +++ b/lxqt-config-monitor/README.md @@ -0,0 +1,4 @@ +lxqt-config-monitor +=================== + +This tool lets you change monitor settings. It is based on lxrandr-qt. diff --git a/lxqt-config-monitor/info-for-developers.txt b/lxqt-config-monitor/info-for-developers.txt new file mode 100644 index 0000000..4a24eba --- /dev/null +++ b/lxqt-config-monitor/info-for-developers.txt @@ -0,0 +1,34 @@ +Info for developers +============== + +lxqt-config-monitor has 3 important modules: + +- Monitor (monitor.h and monitor.cpp) +- MonitorSettingsDialog (monitorsettingsdialog.h and monitorsettingsdialog.cpp) +- XRandR (xrandr.h and xrandr.cpp) + +MonitorSettingsDialog module contains all code related to GUI. + +XRandR module contains code related to get or set settings from XRandR X11 driver. XRandR doesn't need MonitorSettingsDialog to work. + +Monitor module is a glue between MonitorSettingsDialog and XRandR. + +Indeep, XRandR module can be replaced and other modules won't need changes. Example, Wayland or Mir can use other tool for monitor settings. Other module can be added to work with that tool. + + +Module XRandR +============ + +Contains an implementation of class Backend. This class has got two methods in order to get or set configs. + +This is only a simple implementation. It reads info from a pipe to a xrandr command. + +Module Monitor +============ + +Contains 4 classes: + +- Backend: Ii is an abstract class. It have to be implemented by monitor drivers. In X11 this driver is XRandR +- MonitorInfo: This class contains all information about one monitor. It is obtained from Backend::getMonitorsInfo method. +- MonitorSettings: This class is used by Backend::setMonitorsSettings method. This class contains settings for one monitor. +- Monitor: This class is used by MonitorSettingsDialog in order to store monitor settings. diff --git a/lxqt-config-monitor/lxqt-config-monitor.desktop.in b/lxqt-config-monitor/lxqt-config-monitor.desktop.in new file mode 100644 index 0000000..4d8c80b --- /dev/null +++ b/lxqt-config-monitor/lxqt-config-monitor.desktop.in @@ -0,0 +1,11 @@ +[Desktop Entry] +Type=Application +Name=Monitor settings +GenericName=Monitor settings +Comment=Configure monitors +Exec=lxqt-config-monitor +Icon=preferences-desktop-display +Categories=Settings;DesktopSettings;Qt;LXQt;;HardwareSettings; +OnlyShowIn=LXQt; + +#TRANSLATIONS_DIR=translations diff --git a/lxqt-config-monitor/magnetic_attraction.html b/lxqt-config-monitor/magnetic_attraction.html new file mode 100644 index 0000000..1fc4fd3 --- /dev/null +++ b/lxqt-config-monitor/magnetic_attraction.html @@ -0,0 +1,42 @@ + + +Magnetic attraction algorithm + + + +

Magnetic attraction algorithm

+

The algorithm used to move monitors to the nearest one in "position dialog" is explained here.

+

Segment equation is used. Let's explain segment equation in order to understand the proccess:

+

If you have two points, p0, p1 ∈ ℝ 2, the equation of straigh line between p0 and p1 is:

+ +r = v · t + p0 + +

where v = p1 - p0, and t ∈ [0,1].

+

Algorithm calculates equation of the segment between monitor centers. Then, it gets intersection points with edges of monitors:

+ + + + Layer 1 + + + + c_0 + c_1 + t_2 + t_1 + + + + +

If v = c1 - c0, c0 and c1 are monitors centers, the equation between them is r = v · t + c0.

+

where t1 is the parameter of the mentioned equation to get the intersection point with the c1 monitor.

+

where t2 the parameter with the c0 monitor.

+

t1, t2 ∈ [0,1].

+ +

If t2<t1, the monitors are separated, otherwise the monitors are overlapped.

+

With the previous information we get:

+

r1 = v· t1 + c0

+

r2 = v· t2 + c0

+

Iff t2<t1, c0 monitor must be moved, and its displacement is provided by r = r1-r2

+ + \ No newline at end of file diff --git a/lxqt-config-monitor/main.cpp b/lxqt-config-monitor/main.cpp new file mode 100644 index 0000000..7ca8e15 --- /dev/null +++ b/lxqt-config-monitor/main.cpp @@ -0,0 +1,35 @@ +/* + Copyright (C) 2014 P.L. Lucas + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + + +#include "main.h" +#include +#include "monitorsettingsdialog.h" +#include "xrandr.h" + +int main(int argc, char** argv) { + LxQt::SingleApplication app(argc, argv); + + XRandRBackend *xrandr = new XRandRBackend(); + MonitorSettingsDialog dlg(xrandr); + app.setActivationWindow(&dlg); + dlg.setWindowIcon(QIcon::fromTheme("preferences-desktop-display")); + dlg.show(); + + return app.exec(); +} diff --git a/lxqt-config-monitor/main.h b/lxqt-config-monitor/main.h new file mode 100644 index 0000000..afc99d8 --- /dev/null +++ b/lxqt-config-monitor/main.h @@ -0,0 +1,24 @@ +/* + Copyright (C) 2014 P.L. Lucas + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + + +#ifndef _MAIN_H_ +#define _MAIN_H_ + + +#endif // _MAIN_H_ diff --git a/lxqt-config-monitor/mainwindow.ui b/lxqt-config-monitor/mainwindow.ui new file mode 100644 index 0000000..32977cc --- /dev/null +++ b/lxqt-config-monitor/mainwindow.ui @@ -0,0 +1,237 @@ + + + MonitorSettingsDialog + + + + 0 + 0 + 549 + 392 + + + + Monitor Settings + + + + + + + + + + + 1 + + + + Quick Options + + + + + + Show the same screen on both laptop LCD and external monitor + + + + + + + Extended view + + + + + + + Turn off laptop LCD and use external monitor only + + + + + + + Turn off external monitor and use laptop LCD only + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + Settings + + + + + + + + + 0 + 1 + + + + Qt::ScrollBarAlwaysOff + + + + + + + + 1 + 1 + + + + + + + + + + + + Unify all monitors + + + + + + + Monitor Position + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Primary monitor: + + + + + + + + + + + + + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Apply|QDialogButtonBox::Close|QDialogButtonBox::Save + + + + + + + + + buttonBox + rejected() + MonitorSettingsDialog + reject() + + + 338 + 439 + + + 286 + 257 + + + + + unify + toggled(bool) + primaryLabel + setDisabled(bool) + + + 115 + 386 + + + 413 + 388 + + + + + unify + toggled(bool) + primaryCombo + setDisabled(bool) + + + 60 + 386 + + + 491 + 388 + + + + + monitorList + currentRowChanged(int) + stackedWidget + setCurrentIndex(int) + + + 126 + 181 + + + 392 + 186 + + + + + diff --git a/lxqt-config-monitor/monitor.cpp b/lxqt-config-monitor/monitor.cpp new file mode 100644 index 0000000..3802ad2 --- /dev/null +++ b/lxqt-config-monitor/monitor.cpp @@ -0,0 +1,74 @@ +/* + Copyright (C) 2014 P.L. Lucas + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#include "monitor.h" +#include + +bool MonitorInfo::LVDS_Ok = false; + +QSize sizeFromString(QString str) { + int width = 0; + int height = 0; + int x = str.indexOf('x'); + if(x > 0) { + width = str.left(x).toInt(); + height = str.mid(x + 1).toInt(); + } + return QSize(width, height); +} + +bool MonitorSettingsBackend::isUnified(const QList< MonitorInfo* > monitors) { + Q_FOREACH(MonitorInfo * monitor, monitors) { + if(monitor->position != MonitorSettings::None) + return false; + } + return true; +} + +MonitorSettings::MonitorSettings(QObject* parent): QObject(parent) { + position = None; + primaryOk = false; + enabledOk = false; +} + +MonitorInfo::MonitorInfo(QObject* parent): MonitorSettings(parent) { +} + +QString MonitorInfo::humanReadableName() { + if(name.startsWith("LVDS")) + return tr("Laptop LCD Monitor"); + else if(name.startsWith("VGA") || name.startsWith("Analog")) + return LVDS_Ok ? tr("External VGA Monitor") : tr("VGA Monitor"); + else if(name.startsWith("DVI") || name.startsWith("TMDS") || name.startsWith("Digital") || name.startsWith("LVDS")) + return LVDS_Ok ? tr("External DVI Monitor") : tr("DVI Monitor"); + else if(name.startsWith("TV") || name.startsWith("S-Video")) + return tr("TV"); + else if(name == "default") + return tr("Default Monitor"); + return name; +} + +QSize MonitorSettings::currentSize() { + return sizeFromString(currentMode); +} + + +QRect MonitorSettings::geometry() { + return QRect(QPoint(xPos, yPos), currentSize()); +} + diff --git a/lxqt-config-monitor/monitor.h b/lxqt-config-monitor/monitor.h new file mode 100644 index 0000000..01d313c --- /dev/null +++ b/lxqt-config-monitor/monitor.h @@ -0,0 +1,82 @@ +/* + Copyright (C) 2014 P.L. Lucas + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + + +#ifndef _MONITOR_H_ +#define _MONITOR_H_ + +#include +#include +#include +#include + +//Settings to pass to backend +class MonitorSettings: public QObject { + Q_OBJECT +public: + MonitorSettings(QObject* parent = 0); + QString name; + QString currentMode; + QString currentRate; + QString gamma; + QString brightness; + QString backlight; + QString backlightMin; + QString backlightMax; + int xPos; + int yPos; + bool enabledOk; + enum Position {None = 0, Manual}; + Position position; + bool primaryOk; + + QSize currentSize(); + QRect geometry(); +}; + + +// Monitor information from backend +class MonitorInfo: public MonitorSettings { + Q_OBJECT +public: + MonitorInfo(QObject* parent = 0); + QStringList modes; // Modes of this monitor in order + QHash modeLines; // Rates suported by each mode + QString preferredMode; + QString preferredRate; + QString edid; // EDID data, not used yet, can be used to detect vendor name of the monitor + QString vendor; + + static bool LVDS_Ok; // Is true if LVDS (Laptop monitor) is connected. + QString humanReadableName(); +}; + + +class MonitorSettingsBackend: public QObject { + Q_OBJECT +public: + virtual QList getMonitorsInfo() = 0; + virtual bool setMonitorsSettings(const QList monitors) = 0; + virtual QString getCommand(const QList monitors) = 0; + virtual bool isUnified(const QList monitors); +}; + +/**Gets size from string rate. String rate format is "widthxheight". Example: 800x600*/ +QSize sizeFromString(QString str); + +#endif // _MONITOR_H_ \ No newline at end of file diff --git a/lxqt-config-monitor/monitorpicture.cpp b/lxqt-config-monitor/monitorpicture.cpp new file mode 100644 index 0000000..84b0a31 --- /dev/null +++ b/lxqt-config-monitor/monitorpicture.cpp @@ -0,0 +1,231 @@ +#include "monitorpicture.h" + +#include +#include +#include +#include +#include + + +MonitorPictureDialog::MonitorPictureDialog(QWidget * parent, Qt::WindowFlags f): QDialog(parent,f) { + ui.setupUi(this); +} + + +void MonitorPictureDialog::setScene(QList monitors) { + int monitorsWidth = 100.0; + int monitorsHeight = 100.0; + QGraphicsScene *scene = new QGraphicsScene(); + Q_FOREACH(MonitorWidget * monitor, monitors) { + MonitorPicture *monitorPicture = new MonitorPicture(NULL, monitor, this); + pictures.append(monitorPicture); + scene->addItem(monitorPicture); + monitorsWidth+=monitorPicture->rect().width(); + monitorsHeight+=monitorPicture->rect().height(); + } + ui.graphicsView->scale(200.0/(float)monitorsWidth,200.0/(float)monitorsHeight); + ui.graphicsView->setScene(scene); +} + +void MonitorPictureDialog::updateScene() { + ui.graphicsView->scene()->update(); +} + +void MonitorPictureDialog::updateMonitorWidgets(QString primaryMonitor) { + int x0, y0; + x0 = y0 =0; + Q_FOREACH(MonitorPicture * picture, pictures) { + if( picture->monitorWidget->monitorInfo->name == primaryMonitor || primaryMonitor=="") { + x0 = picture->monitorWidget->ui.xPosSpinBox->value() + picture->pos().x(); + y0 = picture->monitorWidget->ui.yPosSpinBox->value() + picture->pos().y(); + break; + } + } + Q_FOREACH(MonitorPicture * picture, pictures) { + int x = -x0 + picture->monitorWidget->ui.xPosSpinBox->value(); + int y = -y0 + picture->monitorWidget->ui.yPosSpinBox->value(); + picture->monitorWidget->ui.xPosSpinBox->setValue(x + picture->pos().x()); + picture->monitorWidget->ui.yPosSpinBox->setValue(y + picture->pos().y()); + } +} + + +MonitorPicture::MonitorPicture(QGraphicsItem * parent, MonitorWidget *monitorWidget, MonitorPictureDialog *monitorPictureDialog):QGraphicsRectItem(parent) +{ + this->monitorWidget = monitorWidget; + this->monitorPictureDialog = monitorPictureDialog; + QSize currentSize = sizeFromString(monitorWidget->ui.resolutionCombo->currentText()); + int x = monitorWidget->ui.xPosSpinBox->value(); + int y = monitorWidget->ui.yPosSpinBox->value(); + setAcceptedMouseButtons(Qt::LeftButton); + setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemSendsGeometryChanges); + setRect(x, y, currentSize.width(), currentSize.height()); + originX = x; + originY = y; + setPen(QPen(Qt::black, 20)); + textItem = new QGraphicsTextItem(monitorWidget->monitorInfo->name, this); + textItem->setX(x); + textItem->setY(y); + textItem->setParentItem(this); + + adjustNameSize(); +} + + +void MonitorPicture::adjustNameSize() { + qreal fontWidth = QFontMetrics(textItem->font()).width(monitorWidget->monitorInfo->name+" "); + textItem->setScale((qreal)this->rect().width()/fontWidth); +} + + +QVariant MonitorPicture::itemChange(GraphicsItemChange change, const QVariant & value) +{ + //qDebug() << "[MonitorPicture::itemChange]: "; + //if ( change == ItemPositionChange && scene()) { + // value is the new position. + //QPointF newPos = value.toPointF(); + //qDebug() << "[MonitorPictureDialog::updateMonitorWidgets]: " << newPos.x() << "x" << newPos.y(); + //} + return QGraphicsItem::itemChange(change, value); +} + + +void MonitorPicture::setMonitorPosition(int x, int y) +{ + setPos(x,y); +} + + +void MonitorPicture::mouseReleaseEvent(QGraphicsSceneMouseEvent * event) +{ + QGraphicsRectItem::mouseReleaseEvent(event); + monitorPictureDialog->moveMonitorPictureToNearest(this); +} + + +////////////////////////////////////////////////////////////////////////////////// +// Move picture to nearest picture procedure. +// Read magnetic_attraction.html for more info about the algorithm used. +////////////////////////////////////////////////////////////////////////////////// + +struct Parameters { + float t1, t2; + QVector2D cutPoint; +}; + +static Parameters segmentsCut(QVector2D p0, QVector2D p1, QVector2D s0, QVector2D s1) +{ + Parameters result; + QVector2D v0 = p1 - p0; + QVector2D v1 = s1 - s0; + QVector2D P = s0 - p0; + float det = v0.y()*v1.x() - v0.x()*v1.y(); + if( det == 0.0 ) { + result.t1 = result.t2 = -1.0; + } + result.t1 = 1/det * ( -v1.y()*P.x() + v1.x()*P.y() ); + result.t2 = 1/det * ( -v0.y()*P.x() + v0.x()*P.y() ); + result.cutPoint = v0*result.t1 + p0; + return result; +} + +static QVector2D computeCenter(MonitorPicture* monitorPicture) +{ + float x0 = monitorPicture->x() + monitorPicture->originX; + float y0 = monitorPicture->y() + monitorPicture->originY; + float x1 = x0 + monitorPicture->rect().width(); + float y1 = y0 + monitorPicture->rect().height(); + QVector2D p0(x0,y0); + QVector2D p1(x1,y1); + QVector2D center = p0 + (p1-p0)*0.5; + return center; +} + +struct Result_moveMonitorPictureToNearest +{ + bool ok; + QVector2D vector; +}; + +static Result_moveMonitorPictureToNearest compareTwoMonitors(MonitorPicture* monitorPicture1, MonitorPicture* monitorPicture2) +{ + Result_moveMonitorPictureToNearest result; + QVector2D center1 = computeCenter(monitorPicture1); + QVector2D center2 = computeCenter(monitorPicture2); + float x0 = monitorPicture2->x() + monitorPicture2->originX; + float y0 = monitorPicture2->y() + monitorPicture2->originY; + float x1 = x0 + monitorPicture2->rect().width(); + float y1 = y0 + monitorPicture2->rect().height(); + QVector2D p0(x0,y0); + QVector2D p1(x1,y1); + QVector2D P1, P2; + float t1=-1.0, t2=-1.0; + Parameters params = segmentsCut(center1, center2, QVector2D(x0,y0), QVector2D(x1,y0)); + if(params.t1>=0.0 && params.t1<=1.0 && params.t2>=0.0 && params.t2<=1.0) { + if(t1<0) {t1 = params.t1; P1 = params.cutPoint;} + } + params = segmentsCut(center1, center2, QVector2D(x0,y0), QVector2D(x0,y1)); + if(params.t1>=0.0 && params.t1<=1.0 && params.t2>=0.0 && params.t2<=1.0) { + if(t1<0) {t1 = params.t1; P1 = params.cutPoint;} + } + params = segmentsCut(center1, center2, QVector2D(x1,y1), QVector2D(x1,y0)); + if(params.t1>=0.0 && params.t1<=1.0 && params.t2>=0.0 && params.t2<=1.0) { + if(t1<0) {t1 = params.t1; P1 = params.cutPoint;} + } + params = segmentsCut(center1, center2, QVector2D(x1,y1), QVector2D(x0,y1)); + if(params.t1>=0.0 && params.t1<=1.0 && params.t2>=0.0 && params.t2<=1.0) { + if(t1<0) {t1 = params.t1; P1 = params.cutPoint;} + } + x0 = monitorPicture1->x() + monitorPicture1->originX; + y0 = monitorPicture1->y() + monitorPicture1->originY; + x1 = x0 + monitorPicture1->rect().width(); + y1 = y0 + monitorPicture1->rect().height(); + p0 = QVector2D(x0,y0); + p1 = QVector2D(x1,y1); + params = segmentsCut(center1, center2, QVector2D(x0,y0), QVector2D(x1,y0)); + if(params.t1>=0.0 && params.t1<=1.0 && params.t2>=0.0 && params.t2<=1.0) { + if(t2<0) {t2 = params.t1; P2 = params.cutPoint;} + } + params = segmentsCut(center1, center2, QVector2D(x0,y0), QVector2D(x0,y1)); + if(params.t1>=0.0 && params.t1<=1.0 && params.t2>=0.0 && params.t2<=1.0) { + if(t2<0) {t2 = params.t1; P2 = params.cutPoint;} + } + params = segmentsCut(center1, center2, QVector2D(x1,y1), QVector2D(x1,y0)); + if(params.t1>=0.0 && params.t1<=1.0 && params.t2>=0.0 && params.t2<=1.0) { + if(t2<0) {t2 = params.t1; P2 = params.cutPoint;} + } + params = segmentsCut(center1, center2, QVector2D(x1,y1), QVector2D(x0,y1)); + if(params.t1>=0.0 && params.t1<=1.0 && params.t2>=0.0 && params.t2<=1.0) { + if(t2<0) {t2 = params.t1; P2 = params.cutPoint;} + } + + if(t1>t2) { //Monitor outside + result.vector = P1-P2; + result.ok = false; + } else { + result.ok = true; + } + + return result; +} + +void MonitorPictureDialog::moveMonitorPictureToNearest(MonitorPicture* monitorPicture) +{ + if(!ui.magneticCheckBox->isChecked()) + return; + QVector2D vector(0,0); + foreach(MonitorPicture* picture, pictures) { + if(picture==monitorPicture) continue; + Result_moveMonitorPictureToNearest result = compareTwoMonitors(monitorPicture, picture); + if(result.ok) { + return; + } else { + if(result.vector.length()x(); + int y = monitorPicture->y(); + monitorPicture->setX( x + vector.x() ); + monitorPicture->setY( y + vector.y() ); +} diff --git a/lxqt-config-monitor/monitorpicture.h b/lxqt-config-monitor/monitorpicture.h new file mode 100644 index 0000000..775237c --- /dev/null +++ b/lxqt-config-monitor/monitorpicture.h @@ -0,0 +1,66 @@ +/* + Copyright (C) 2014 P.L. Lucas + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + + +#ifndef _MONITORPICTURE_H_ +#define _MONITORPICTURE_H_ + +#include +#include +#include +#include +#include "monitor.h" +#include "ui_monitorpicture.h" +#include "monitorwidget.h" + +class MonitorPicture; + +class MonitorPictureDialog: public QDialog { + Q_OBJECT +public: + MonitorPictureDialog(QWidget * parent = 0, Qt::WindowFlags f = 0); + void setScene(QList monitors); + void updateMonitorWidgets(QString primaryMonitor); + void moveMonitorPictureToNearest(MonitorPicture* monitorPicture); + void updateScene(); +private: + Ui::MonitorPictureDialog ui; + QList pictures; +}; + + +class MonitorPicture: public QGraphicsRectItem { + +public: + MonitorPicture(QGraphicsItem * parent, MonitorWidget *monitorWidget, MonitorPictureDialog *monitorPictureDialog); + void setMonitorPosition(int x, int y); + void adjustNameSize(); + + MonitorWidget *monitorWidget; + int originX, originY; +private: + QGraphicsTextItem *textItem; + MonitorPictureDialog *monitorPictureDialog; + +protected: + QVariant itemChange(GraphicsItemChange change, const QVariant & value); + void mouseReleaseEvent(QGraphicsSceneMouseEvent * event); +}; + + +#endif // _MONITORPICTURE_H_ diff --git a/lxqt-config-monitor/monitorpicture.ui b/lxqt-config-monitor/monitorpicture.ui new file mode 100644 index 0000000..29d9853 --- /dev/null +++ b/lxqt-config-monitor/monitorpicture.ui @@ -0,0 +1,81 @@ + + + MonitorPictureDialog + + + + 0 + 0 + 462 + 362 + + + + Dialog + + + + + + + + + + + + + Magnetic attraction + + + true + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + MonitorPictureDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + MonitorPictureDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/lxqt-config-monitor/monitorsettingsdialog.cpp b/lxqt-config-monitor/monitorsettingsdialog.cpp new file mode 100644 index 0000000..feca0ab --- /dev/null +++ b/lxqt-config-monitor/monitorsettingsdialog.cpp @@ -0,0 +1,303 @@ +/* + Copyright (C) 2014 P.L. Lucas + Copyright (C) 2013 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + + +#include "monitorsettingsdialog.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "monitorwidget.h" +#include "timeoutdialog.h" +#include "xrandr.h" +#include "monitorpicture.h" + +MonitorSettingsDialog::MonitorSettingsDialog(MonitorSettingsBackend* backend): + QDialog(NULL, 0), + LVDS(NULL) { + timeoutDialog = NULL; + timer = NULL; + this->backend = backend; + backend->setParent(this); + setupUi(); +} + + +MonitorSettingsDialog::~MonitorSettingsDialog() { +} + + +void MonitorSettingsDialog::deleteTimeoutData() { + timeoutDialog = NULL; + Q_FOREACH(MonitorInfo * monitorInfo, timeoutSettings) { + delete monitorInfo; + } + timeoutSettings.clear(); +} + +void MonitorSettingsDialog::onCancelSettings() { + // restore the old settings + QList settings; + Q_FOREACH(MonitorInfo * monitorInfo, timeoutSettings) { + settings.append((MonitorSettings*)monitorInfo); + } + backend->setMonitorsSettings(settings); + deleteTimeoutData(); +} + +QList MonitorSettingsDialog::getMonitorsSettings() { + // Build list of monitor and their settings + QList settings; + Q_FOREACH(MonitorWidget * monitor, monitors) { + MonitorSettings* s = monitor->getSettings(); + settings.append(s); + if(ui.primaryCombo->currentText() == monitor->monitorInfo->name) + s->primaryOk = true; + } + if(ui.unify->isChecked()) { + Q_FOREACH(MonitorSettings * s, settings) { + s->position = MonitorSettings::None; + } + } + return settings; +} + +void MonitorSettingsDialog::setMonitorsConfig() { + deleteTimeoutData(); + timeoutSettings = backend->getMonitorsInfo(); + // Show timeout dialog + timeoutDialog = new TimeoutDialog(this); + connect(timeoutDialog, SIGNAL(rejected()), this, SLOT(onCancelSettings())); + connect(timeoutDialog, SIGNAL(finished(int)), timeoutDialog, SLOT(deleteLater())); + // Build list of monitor and their settings + QList settings = getMonitorsSettings(); + backend->setMonitorsSettings(settings); + Q_FOREACH(MonitorSettings * s, settings) { + delete s; + } + timeoutDialog->show(); +} + +// turn on both laptop LCD and the external monitor +void MonitorSettingsDialog::onUseBoth() { + if(monitors.length() == 0) + return; + ui.unify->setChecked(true); + MonitorWidget* monitor = monitors[0]; + bool ok; + QString mode; + for(int i = 0; i < monitor->monitorInfo->modes.length(); i++) { + mode = monitor->monitorInfo->modes[i]; + ok = true; + Q_FOREACH(MonitorWidget * monitor2, monitors) { + ok = ok && monitor2->monitorInfo->modes.contains(mode); + } + if(ok) + break; + } + qDebug() << "Mode selected" << mode << ok; + Q_FOREACH(MonitorWidget * monitor2, monitors) { + int index = monitor2->monitorInfo->modes.indexOf(mode) + 1; + if(monitor2->ui.resolutionCombo->count() > index) + monitor2->ui.resolutionCombo->setCurrentIndex(index); + else + monitor2->chooseMaxResolution(); + monitor2->enableMonitor(true); + qDebug() << "Mode selected index" << index << "Mode" << monitor->ui.resolutionCombo->currentText(); + } + setMonitorsConfig(); +} + +// external monitor only +void MonitorSettingsDialog::onExternalOnly() { + Q_FOREACH(MonitorWidget * monitor, monitors) { + monitor->chooseMaxResolution(); + monitor->enableMonitor(monitor != LVDS); + } + setMonitorsConfig(); +} + +// laptop panel - LVDS only +void MonitorSettingsDialog::onLaptopOnly() { + Q_FOREACH(MonitorWidget * monitor, monitors) { + monitor->chooseMaxResolution(); + monitor->enableMonitor(monitor == LVDS); + } + setMonitorsConfig(); +} + +void MonitorSettingsDialog::onExtended() { + ui.unify->setChecked(false); + int virtualWidth = 0; + Q_FOREACH(MonitorWidget * monitor, monitors) { + monitor->chooseMaxResolution(); + monitor->enableMonitor(true); + monitor->disablePositionOption(false); + QSize size = sizeFromString(monitor->ui.resolutionCombo->currentText()); + monitor->ui.xPosSpinBox->setValue(virtualWidth); + monitor->ui.yPosSpinBox->setValue(0); + virtualWidth+=size.width(); + } + setMonitorsConfig(); +} + +void MonitorSettingsDialog::setupUi() { + ui.setupUi(this); + connect(ui.useBoth, SIGNAL(clicked(bool)), SLOT(onUseBoth())); + connect(ui.externalOnly, SIGNAL(clicked(bool)), SLOT(onExternalOnly())); + connect(ui.laptopOnly, SIGNAL(clicked(bool)), SLOT(onLaptopOnly())); + connect(ui.extended, SIGNAL(clicked(bool)), SLOT(onExtended())); + connect(ui.buttonBox, SIGNAL(clicked(QAbstractButton*)), SLOT(onDialogButtonClicked(QAbstractButton*))); + connect(ui.positionPushButton, SIGNAL(clicked()), SLOT(onPositionButtonClicked())); + + // Get monitors information + QList monitorsInfo = backend->getMonitorsInfo(); + + // Search if LVSD monitor is connected + Q_FOREACH(MonitorInfo * monitorInfo, monitorsInfo) { + if(! LVDS && (monitorInfo->name.startsWith("LVDS") || monitorInfo->name.startsWith("PANEL"))) { + MonitorInfo::LVDS_Ok = true; + break; + } + } + + int i = 0; + connect(ui.unify, SIGNAL(toggled(bool)), this, SLOT(disablePositionOption(bool))); + Q_FOREACH(MonitorInfo * monitorInfo, monitorsInfo) { + ui.primaryCombo->addItem(monitorInfo->name); + if(monitorInfo->primaryOk) + ui.primaryCombo->setCurrentIndex(ui.primaryCombo->findText(monitorInfo->name)); + + qDebug() << "Monitor" << monitorInfo->name; + MonitorWidget* monitor = new MonitorWidget(monitorInfo, monitorsInfo, this); + QString title = QString("Monitor %1: %2 (%3) %4") + .arg(i + 1) + .arg(monitor->monitorInfo->name) + .arg(monitor->monitorInfo->humanReadableName()) + .arg(monitor->monitorInfo->vendor); + qDebug() << "Monitor" << title; + monitor->setTitle(title); + + connect(ui.unify, SIGNAL(toggled(bool)), monitor, SLOT(disablePositionOption(bool))); + monitors.append(monitor); + if(! LVDS && (monitorInfo->name.startsWith("LVDS") || monitorInfo->name.startsWith("PANEL"))) { + LVDS = monitor; + } + ui.stackedWidget->addWidget(monitor); + ui.monitorList->addItem(monitor->monitorInfo->name); + ++i; + } + ui.monitorList->setCurrentRow(0); + // set the max width of the list widget to the maximal width of its rows + the width of a vertical scrollbar. + ui.monitorList->setMaximumWidth(ui.monitorList->sizeHintForColumn(0) + style()->pixelMetric(QStyle::PM_ScrollBarExtent) + 40); + + // are the monitors unified? + if(monitorsInfo.length() > 1) + ui.unify->setChecked(backend->isUnified(monitorsInfo)); + else {// disable the option if we only have one monitor + ui.unify->setEnabled(false); + ui.positionPushButton->setEnabled(false); + } + + // If this is a laptop and there is an external monitor, offer quick options + if(monitors.length() == 2) { + ui.tabWidget->setCurrentIndex(0); + // If there is only two monitors,offer quick options + if(! LVDS) { + LVDS = monitors[0]; + } + } + else { + ui.tabWidget->removeTab(0); + } + + adjustSize(); +} + +void MonitorSettingsDialog::accept() { + setMonitorsConfig(); + QDialog::accept(); +} + +void MonitorSettingsDialog::disablePositionOption(bool disable) { + ui.positionPushButton->setEnabled(!disable); +} + +void MonitorSettingsDialog::onPositionButtonClicked() { + MonitorPictureDialog *dialog = new MonitorPictureDialog(this); + dialog->setScene(monitors); + dialog->exec(); + dialog->updateMonitorWidgets(ui.primaryCombo->currentText()); + delete dialog; +} + +void MonitorSettingsDialog::onDialogButtonClicked(QAbstractButton* button) { + if(ui.buttonBox->standardButton(button) == QDialogButtonBox::Apply) { + setMonitorsConfig(); + } + else if(ui.buttonBox->standardButton(button) == QDialogButtonBox::Save) { + // Save config and exit + QMessageBox msgBox; + msgBox.setText(tr("Do you want to save changes?")); + msgBox.setInformativeText(tr("Please, check the settings before saving.")); + msgBox.setStandardButtons(QMessageBox::Save | QMessageBox::Cancel); + msgBox.setDefaultButton(QMessageBox::Cancel); + int ret = msgBox.exec(); + if( ret == QMessageBox::Cancel ) + return; + QList settings = getMonitorsSettings(); + QString cmd = backend->getCommand(settings); + Q_FOREACH(MonitorSettings * s, settings) { + delete s; + } + QString desktop = QString("[Desktop Entry]\n" + "Type=Application\n" + "Name=LXQt-config-monitor autostart\n" + "Comment=Autostart monitor settings for LXQt-config-monitor\n" + "Exec=%1\n" + "OnlyShowIn=LXQt\n").arg(cmd); + // Check if ~/.config/autostart/ exists + bool ok = true; + QFileInfo fileInfo(QDir::homePath() + "/.config/autostart/"); + if( ! fileInfo.exists() ) + ok = QDir::root().mkpath(QDir::homePath() + "/.config/autostart/"); + QFile file(QDir::homePath() + "/.config/autostart/lxqt-config-monitor-autostart.desktop"); + if(ok) + ok = file.open(QIODevice::WriteOnly | QIODevice::Text); + if(!ok) { + QMessageBox::critical(this, tr("Error"), tr("Config can not be saved")); + return; + } + QTextStream out(&file); + out << desktop; + out.flush(); + file.close(); + //QDialog::accept(); + } +} + diff --git a/lxqt-config-monitor/monitorsettingsdialog.h b/lxqt-config-monitor/monitorsettingsdialog.h new file mode 100644 index 0000000..baf0ecc --- /dev/null +++ b/lxqt-config-monitor/monitorsettingsdialog.h @@ -0,0 +1,72 @@ +/* + Copyright (C) 2014 P.L. Lucas + Copyright (C) 2013 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + + +#ifndef MONITORSETTINGSDIALOG_H +#define MONITORSETTINGSDIALOG_H + +#include +#include "ui_mainwindow.h" +#include "monitor.h" +#include "monitorwidget.h" + +class TimeoutDialog; +class QTimer; + +class MonitorSettingsDialog: public QDialog { + Q_OBJECT + +public: + MonitorSettingsDialog(MonitorSettingsBackend* backend); + virtual ~MonitorSettingsDialog(); + virtual void accept(); + +private: + void setMonitorsConfig(); + void setupUi(); + QList getMonitorsSettings(); + + void deleteTimeoutData(); // Used to delete data from TimeoutDialog + +private Q_SLOTS: + // Timeout dialog signals + void onCancelSettings(); + + // quick options + void onUseBoth(); + void onExternalOnly(); + void onLaptopOnly(); + void onExtended(); + + void onDialogButtonClicked(QAbstractButton* button); + void onPositionButtonClicked(); + void disablePositionOption(bool disable); + +private: + Ui::MonitorSettingsDialog ui; + QList monitors; + MonitorWidget* LVDS; + MonitorSettingsBackend* backend; + // TimeoutDialog data + TimeoutDialog* timeoutDialog; + QTimer* timer; + QList timeoutSettings; +}; + +#endif // MONITORSETTINGSDIALOG_H diff --git a/lxqt-config-monitor/monitorwidget.cpp b/lxqt-config-monitor/monitorwidget.cpp new file mode 100644 index 0000000..8d4ad52 --- /dev/null +++ b/lxqt-config-monitor/monitorwidget.cpp @@ -0,0 +1,147 @@ +/* + Copyright (C) 2014 P.L. Lucas + Copyright (C) 2014 Hong Jen Yee (PCMan) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#include "monitorwidget.h" +#include "monitor.h" +#include + +MonitorWidget::MonitorWidget(MonitorInfo* monitor, const QList monitorsInfo, QWidget* parent): + QGroupBox(parent) { + ui.enabled = NULL; + monitorInfo = monitor; + monitor->setParent(this); // take the ownership + + ui.setupUi(this); + + if(monitorsInfo.length() == 1) { + disablePositionOption(true); + + // turn off screen is not allowed since there should be at least one monitor available. + ui.enabled->setEnabled(false); + } + + ui.xPosSpinBox->setValue(monitor->xPos); + ui.yPosSpinBox->setValue(monitor->yPos); + + if(monitor->enabledOk) + ui.enabled->setChecked(true); + + connect(ui.resolutionCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(onResolutionChanged(int))); + ui.resolutionCombo->addItem(tr("Auto")); + Q_FOREACH(QString _mode_line, monitor->modes) { + ui.resolutionCombo->addItem(_mode_line); + } + + + if(!monitor->currentMode.isEmpty()) + ui.resolutionCombo->setCurrentIndex(ui.resolutionCombo->findText(monitor->currentMode)); + else + ui.resolutionCombo->setCurrentIndex(0); + if(!monitor->currentRate.isEmpty()) + ui.rateCombo->setCurrentIndex(ui.rateCombo->findText(monitor->currentRate)); + else + ui.rateCombo->setCurrentIndex(0); + + int brightness; + if( !monitorInfo->brightness.isEmpty() ) + brightness = monitorInfo->brightness.toFloat()*100; + else + brightness = 100; + ui.brightnessSlider->setValue(brightness); + + // Set gamma values + ui.redSpinBox->setSingleStep(0.01); + ui.greenSpinBox->setSingleStep(0.01); + ui.blueSpinBox->setSingleStep(0.01); + if(!monitor->gamma.isEmpty()) { + QStringList gammaValues = monitor->gamma.split(":"); + ui.redSpinBox->setValue(gammaValues[0].toFloat()); + ui.greenSpinBox->setValue(gammaValues[1].toFloat()); + ui.blueSpinBox->setValue(gammaValues[2].toFloat()); + } + + //Set backlight values + if( !monitor->backlight.isEmpty() ) { + ui.backlightSlider->setMinimum(monitor->backlightMin.toInt()); + ui.backlightSlider->setMaximum(monitor->backlightMax.toInt()); + ui.backlightSlider->setSingleStep(1); + ui.backlightSlider->setValue(monitor->backlight.toInt()); + } else { + ui.backlightSlider->setEnabled(false); + ui.backlightLabel->setEnabled(false); + } +} + +void MonitorWidget::onResolutionChanged(int index) { + QComboBox* combo =ui.resolutionCombo; + QHash modeLines = monitorInfo->modeLines; + QComboBox* rateCombo = ui.rateCombo; + QString mode = combo->currentText(); + rateCombo->clear(); + rateCombo->addItem(tr("Auto")); + if(modeLines.contains(mode)) { + QStringList mode_lines = modeLines[mode]; + Q_FOREACH(QString rate, mode_lines) { + rateCombo->addItem(rate); + } + rateCombo->setCurrentIndex(0); + } +} + + +void MonitorWidget::disablePositionOption(bool disable) { + bool enable = !disable; + ui.xPosSpinBox->setEnabled(enable); + ui.yPosSpinBox->setEnabled(enable); + ui.xPosLabel->setEnabled(enable); + ui.yPosLabel->setEnabled(enable); + ui.positionLabel->setEnabled(enable); +} + +MonitorSettings* MonitorWidget::getSettings() { + MonitorSettings* s = new MonitorSettings(); + s->name = monitorInfo->name; + s->enabledOk = ui.enabled->isChecked(); + s->currentMode = ui.resolutionCombo->currentText(); + s->currentRate = ui.rateCombo->currentText(); + if( ! ui.xPosSpinBox->isEnabled() ) { // If no unify monitor is selected, then position is disabled. + s->position = MonitorSettings::None; + } else { + s->position = MonitorSettings::Manual; + } + s->xPos=ui.xPosSpinBox->value(); + s->yPos=ui.yPosSpinBox->value(); + s->brightness = QString("%1").arg((float)(ui.brightnessSlider->value())/100.0); + s->gamma = QString("%1:%2:%3").arg(ui.redSpinBox->value()).arg(ui.greenSpinBox->value()).arg(ui.blueSpinBox->value()); + if(ui.backlightSlider->isEnabled()) { + s->backlight = QString("%1").arg(ui.backlightSlider->value()); + s->backlightMax = QString("%1").arg(ui.backlightSlider->maximum()); + s->backlightMin = QString("%1").arg(ui.backlightSlider->minimum()); + } + return s; +} + +void MonitorWidget::chooseMaxResolution() { + if(ui.resolutionCombo->count() > 1) + ui.resolutionCombo->setCurrentIndex(1); +} + +void MonitorWidget::enableMonitor(bool enable) { + ui.enabled->setChecked(enable); +} diff --git a/lxqt-config-monitor/monitorwidget.h b/lxqt-config-monitor/monitorwidget.h new file mode 100644 index 0000000..12a09e6 --- /dev/null +++ b/lxqt-config-monitor/monitorwidget.h @@ -0,0 +1,53 @@ +/* + Copyright (C) 2014 P.L. Lucas + Copyright (C) 2014 Hong Jen Yee (PCMan) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + + +#ifndef _MONITORWIDGET_H_ +#define _MONITORWIDGET_H_ + +#include +#include +#include +#include +#include "ui_monitorwidget.h" + +class MonitorInfo; +class MonitorSettings; + +// Monitor info +class MonitorWidget : public QGroupBox { + Q_OBJECT + +public: + MonitorWidget(MonitorInfo* monitor, const QList< MonitorInfo* > monitorsInfo, QWidget* parent = 0); + MonitorSettings* getSettings(); + void chooseMaxResolution(); + void enableMonitor(bool enable); + + MonitorInfo* monitorInfo; + + Ui::MonitorWidget ui; +public Q_SLOTS: + void disablePositionOption(bool disabled); + +private Q_SLOTS: + void onResolutionChanged(int); +}; + +#endif // _MONITORWIDGET_H_ diff --git a/lxqt-config-monitor/monitorwidget.ui b/lxqt-config-monitor/monitorwidget.ui new file mode 100644 index 0000000..000cb9c --- /dev/null +++ b/lxqt-config-monitor/monitorwidget.ui @@ -0,0 +1,208 @@ + + + MonitorWidget + + + + 0 + 0 + 345 + 286 + + + + + + + + QFormLayout::AllNonFixedFieldsGrow + + + + + Turn on + + + + + + + Resolution: + + + + + + + + + + Rate: + + + + + + + + + + + + + 0 + 0 + + + + Hz + + + + + + + + + Position: + + + + + + + QFormLayout::AllNonFixedFieldsGrow + + + + + x: + + + + + + + -10000000 + + + 10000000 + + + + + + + y: + + + + + + + -10000000 + + + 10000000 + + + + + + + + + Brightness: + + + + + + + 100 + + + 100 + + + Qt::Horizontal + + + + + + + Gamma: + + + + + + + + + 10.000000000000000 + + + 1.000000000000000 + + + + + + + : + + + + + + + 10.000000000000000 + + + 1.000000000000000 + + + + + + + : + + + + + + + 10.000000000000000 + + + 1.000000000000000 + + + 1.000000000000000 + + + + + + + + + Backlight: + + + + + + + Qt::Horizontal + + + + + + + + diff --git a/lxqt-config-monitor/timeoutdialog.cpp b/lxqt-config-monitor/timeoutdialog.cpp new file mode 100644 index 0000000..7ba9844 --- /dev/null +++ b/lxqt-config-monitor/timeoutdialog.cpp @@ -0,0 +1,54 @@ +/* + * + * Copyright (C) 2014 PCMan + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "timeoutdialog.h" +#include + +TimeoutDialog::TimeoutDialog(QWidget* parent, Qt::WindowFlags f) { + ui.setupUi(this); + + QIcon icon = style()->standardIcon(QStyle::SP_MessageBoxQuestion); + int size = style()->pixelMetric(QStyle::PM_MessageBoxIconSize); + ui.icon->setPixmap(icon.pixmap(QSize(size, size))); + + timer = new QTimer(this); + connect(timer, SIGNAL(timeout()), this, SLOT(onTimeout())); + adjustSize(); +} + +TimeoutDialog::~TimeoutDialog() { +} + +void TimeoutDialog::showEvent(QShowEvent* e) { + timer->start(1000); + QDialog::showEvent(e); +} + +void TimeoutDialog::onTimeout() { + int time = ui.progressBar->value() + 1; + if(time >= 10) { // If time is finished, settings are restored. + timer->stop(); + reject(); + } + else { + ui.progressBar->setValue(time); + ui.progressBar->setFormat(tr("%1 second(s) remaining").arg(10 - time)); + } +} diff --git a/lxqt-config-monitor/timeoutdialog.h b/lxqt-config-monitor/timeoutdialog.h new file mode 100644 index 0000000..08a5ad0 --- /dev/null +++ b/lxqt-config-monitor/timeoutdialog.h @@ -0,0 +1,46 @@ +/* + * + * Copyright (C) 2014 PCMan + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef TIMEOUTDIALOG_H +#define TIMEOUTDIALOG_H + +#include +#include "ui_timeoutdialog.h" + +class QTimer; + +class TimeoutDialog : public QDialog { + Q_OBJECT +public: + TimeoutDialog(QWidget* parent = 0, Qt::WindowFlags f = 0); + virtual ~TimeoutDialog(); + +protected: + virtual void showEvent(QShowEvent* e); + +private Q_SLOTS: + void onTimeout(); + +private: + Ui::TimeoutDialog ui; + QTimer* timer; +}; + +#endif // TIMEOUTDIALOG_H diff --git a/lxqt-config-monitor/timeoutdialog.ui b/lxqt-config-monitor/timeoutdialog.ui new file mode 100644 index 0000000..f220e14 --- /dev/null +++ b/lxqt-config-monitor/timeoutdialog.ui @@ -0,0 +1,100 @@ + + + TimeoutDialog + + + + 0 + 0 + 390 + 109 + + + + Settings are changed + + + true + + + + + + Are the current settings OK for you? + + + + + + + + 0 + 0 + + + + Qt::AlignCenter + + + + + + + Qt::Horizontal + + + QDialogButtonBox::No|QDialogButtonBox::Yes + + + + + + + 10 + + + 0 + + + + + + + + + + + + buttonBox + accepted() + TimeoutDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + TimeoutDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/lxqt-config-monitor/translations/lxqt-config-monitor.ts b/lxqt-config-monitor/translations/lxqt-config-monitor.ts new file mode 100644 index 0000000..55b1d44 --- /dev/null +++ b/lxqt-config-monitor/translations/lxqt-config-monitor.ts @@ -0,0 +1,220 @@ + + + + + MonitorInfo + + + Laptop LCD Monitor + + + + + External VGA Monitor + + + + + VGA Monitor + + + + + External DVI Monitor + + + + + DVI Monitor + + + + + TV + + + + + Default Monitor + + + + + MonitorPictureDialog + + + Dialog + + + + + Magnetic attraction + + + + + MonitorSettingsDialog + + + Monitor Settings + + + + + Quick Options + + + + + Show the same screen on both laptop LCD and external monitor + + + + + Extended view + + + + + Turn off laptop LCD and use external monitor only + + + + + Turn off external monitor and use laptop LCD only + + + + + Settings + + + + + Unify all monitors + + + + + Monitor Position + + + + + Primary monitor: + + + + + Do you want to save changes? + + + + + Please, check your config before to save. + + + + + Error + + + + + Config can not be saved + + + + + MonitorWidget + + + Turn on + + + + + Resolution: + + + + + Rate: + + + + + Hz + + + + + Position: + + + + + x: + + + + + y: + + + + + Brightness: + + + + + Gamma: + + + + + + : + + + + + Backlight: + + + + + + Auto + + + + + QObject + + + + Auto + + + + + TimeoutDialog + + + Settings are changed + + + + + Are the current settings OK for you? + + + + + %1 second(s) remaining + + + + diff --git a/lxqt-config-monitor/translations/lxqt-config-monitor_de.desktop b/lxqt-config-monitor/translations/lxqt-config-monitor_de.desktop new file mode 100644 index 0000000..abdbf8c --- /dev/null +++ b/lxqt-config-monitor/translations/lxqt-config-monitor_de.desktop @@ -0,0 +1,3 @@ +Name[de]=Bildschirmeinstellungen +GenericName[de]=Bildschirmeinstellungen +Comment[de]=Bildschirmauflösung und externe Monitore konfigurieren diff --git a/lxqt-config-monitor/translations/lxqt-config-monitor_de.ts b/lxqt-config-monitor/translations/lxqt-config-monitor_de.ts new file mode 100644 index 0000000..01c7641 --- /dev/null +++ b/lxqt-config-monitor/translations/lxqt-config-monitor_de.ts @@ -0,0 +1,220 @@ + + + + + MonitorInfo + + + Laptop LCD Monitor + Laptop-Bildschirm + + + + External VGA Monitor + Externer VGA-Bildschirm + + + + VGA Monitor + VGA-Bildschirm + + + + External DVI Monitor + Externer DVI-Bildschirm + + + + DVI Monitor + DVI-Bildschirm + + + + TV + Fernseher + + + + Default Monitor + Standardbildschirm + + + + MonitorPictureDialog + + + Dialog + Dialogfenster + + + + Magnetic attraction + Magnetische Anziehungskraft + + + + MonitorSettingsDialog + + + Monitor Settings + Bildschirmeinstellungen + + + + Quick Options + Schnellwahl + + + + Show the same screen on both laptop LCD and external monitor + Gleiches Bild auf Laptop und externem Bildschirm anzeigen + + + + Extended view + Erweiterter Bildschirm + + + + Turn off laptop LCD and use external monitor only + Laptop-Bildschirm ausschalten und nur den externen Monitor verwenden + + + + Turn off external monitor and use laptop LCD only + Externen Monitor ausschalten und nur den Laptop-Bildschirm verwenden + + + + Settings + Einstellungen + + + + Unify all monitors + Alle Bildschirme gleich behandeln + + + + Monitor Position + Bildschirmposition + + + + Primary monitor: + Hauptbildschirm: + + + + Do you want to save changes? + Einstellungen sichern? + + + + Please, check your config before to save. + Bitte Konfiguration vor dem Sichern überprüfen. + + + + Error + Fehler + + + + Config can not be saved + Konfiguration kann nicht gespeichert werden + + + + MonitorWidget + + + Turn on + Einschalten + + + + Resolution: + Auflösung: + + + + Rate: + Bildwiederholfrequenz: + + + + Hz + Hz + + + + Position: + Position: + + + + x: + x: + + + + y: + y: + + + + Brightness: + Helligkeit: + + + + Gamma: + Gamma: + + + + + : + : + + + + Backlight: + Hintergrundbeleuchtung: + + + + + Auto + Automatisch + + + + QObject + + + + Auto + Automatisch + + + + TimeoutDialog + + + Settings are changed + Einstellungen wurden geändert + + + + Are the current settings OK for you? + Sind die Einstellungen korrekt? + + + + %1 second(s) remaining + %1 Sekunde(n) verbleiben + + + diff --git a/lxqt-config-monitor/translations/lxqt-config-monitor_it_IT.ts b/lxqt-config-monitor/translations/lxqt-config-monitor_it_IT.ts new file mode 100644 index 0000000..11c8e2b --- /dev/null +++ b/lxqt-config-monitor/translations/lxqt-config-monitor_it_IT.ts @@ -0,0 +1,220 @@ + + + + + MonitorInfo + + + Laptop LCD Monitor + Monitor portatile LCD + + + + External VGA Monitor + Monitor esterno VGA + + + + VGA Monitor + Monitor VGA + + + + External DVI Monitor + Monitor esterno DVI + + + + DVI Monitor + Monitor DVI + + + + TV + TV + + + + Default Monitor + Monitor principale + + + + MonitorPictureDialog + + + Dialog + + + + + Magnetic attraction + Attrazione magnetica + + + + MonitorSettingsDialog + + + Monitor Settings + Impostazioni del monitor + + + + Quick Options + Opzioni veloci + + + + Show the same screen on both laptop LCD and external monitor + Unifica uscite + + + + Extended view + Vista estesa + + + + Turn off laptop LCD and use external monitor only + Spegni monitor portatile LCD e usa solo monitor esterno + + + + Turn off external monitor and use laptop LCD only + Spegni monitor esterno e usa solo monitor LCD + + + + Settings + Impostazioni + + + + Unify all monitors + Unisci tutte le uscite + + + + Monitor Position + Posizione dello schermo + + + + Primary monitor: + Monitor principale: + + + + Do you want to save changes? + Salvare i cambiamenti? + + + + Please, check your config before to save. + Per favore controlla la configurazione prima di salvare. + + + + Error + Errore + + + + Config can not be saved + La configurazione non può essere salvata + + + + MonitorWidget + + + Turn on + Accendi + + + + Resolution: + Risoluzione: + + + + Rate: + Frequenza: + + + + Hz + + + + + Position: + Posizione: + + + + x: + + + + + y: + + + + + Brightness: + Luminosità: + + + + Gamma: + + + + + + : + + + + + Backlight: + Retroilluminazione: + + + + + Auto + Auto + + + + QObject + + + + Auto + Auto + + + + TimeoutDialog + + + Settings are changed + Impostazione modificate + + + + Are the current settings OK for you? + Mantenere questa configurazione? + + + + %1 second(s) remaining + %1 secondi rimanenti + + + diff --git a/lxqt-config-monitor/translations/lxqt-config-monitor_ja.desktop b/lxqt-config-monitor/translations/lxqt-config-monitor_ja.desktop new file mode 100644 index 0000000..6c6a98c --- /dev/null +++ b/lxqt-config-monitor/translations/lxqt-config-monitor_ja.desktop @@ -0,0 +1,4 @@ +# Translations +Name[ja]=モニターの設定 +GenericName[ja]=モニターの設定 +Comment[ja]=モニターの設定 diff --git a/lxqt-config-monitor/translations/lxqt-config-monitor_ja.ts b/lxqt-config-monitor/translations/lxqt-config-monitor_ja.ts new file mode 100644 index 0000000..44965d6 --- /dev/null +++ b/lxqt-config-monitor/translations/lxqt-config-monitor_ja.ts @@ -0,0 +1,220 @@ + + + + + MonitorInfo + + + Laptop LCD Monitor + ラップトップ液晶モニター + + + + External VGA Monitor + 外部VGAモニター + + + + VGA Monitor + VGAモニター + + + + External DVI Monitor + 外部DVIモニター + + + + DVI Monitor + DVIモニター + + + + TV + TV + + + + Default Monitor + デフォルトのモニター + + + + MonitorPictureDialog + + + Dialog + ダイアログ + + + + Magnetic attraction + + + + + MonitorSettingsDialog + + + Monitor Settings + モニターの設定 + + + + Quick Options + クイックオプション + + + + Show the same screen on both laptop LCD and external monitor + ラップトップ液晶パネルと外部モニターで同じ画面を表示 + + + + Extended view + 拡張領域 + + + + Turn off laptop LCD and use external monitor only + ラップトップ液晶画面を無効にし、外部モニターのみ使う + + + + Turn off external monitor and use laptop LCD only + 外部モニターを無効にし、ラップトップ液晶画面のみ使う + + + + Settings + 設定 + + + + Unify all monitors + すべてのモニターの表示を共通にする + + + + Monitor Position + モニターの位置 + + + + Primary monitor: + プライマリーモニター: + + + + Do you want to save changes? + 変更を保存しますか? + + + + Please, check your config before to save. + 保存する前に、設定結果を確認してください + + + + Error + エラー + + + + Config can not be saved + 設定を保存することができませんでした + + + + MonitorWidget + + + Turn on + 有効にする + + + + Resolution: + 解像度: + + + + Rate: + リフレッシュレート: + + + + Hz + Hz + + + + Position: + 位置: + + + + x: + X座標: + + + + y: + Y座標: + + + + Brightness: + 明るさ: + + + + Gamma: + ガンマ: + + + + + : + : + + + + Backlight: + バックライト: + + + + + Auto + 自動 + + + + QObject + + + + Auto + 自動 + + + + TimeoutDialog + + + Settings are changed + 設定は変更されました + + + + Are the current settings OK for you? + この設定で問題ないですか? + + + + %1 second(s) remaining + 残り %1 秒 + + + diff --git a/lxqt-config-monitor/translations/lxqt-config-monitor_pt.desktop b/lxqt-config-monitor/translations/lxqt-config-monitor_pt.desktop new file mode 100644 index 0000000..d86f841 --- /dev/null +++ b/lxqt-config-monitor/translations/lxqt-config-monitor_pt.desktop @@ -0,0 +1,3 @@ +Name[pt]=Definições do monitor +GenericName[pt]=Definições do monitor +Comment[pt]=Configuração de monitores diff --git a/lxqt-config-monitor/translations/lxqt-config-monitor_pt.ts b/lxqt-config-monitor/translations/lxqt-config-monitor_pt.ts new file mode 100644 index 0000000..45e6831 --- /dev/null +++ b/lxqt-config-monitor/translations/lxqt-config-monitor_pt.ts @@ -0,0 +1,300 @@ + + + + + MonitorInfo + + + Laptop LCD Monitor + Monitor LCD de portátil + + + + External VGA Monitor + Monitor externo VGA + + + + VGA Monitor + Monitor VGA + + + + External DVI Monitor + Monitor externo DVI + + + + DVI Monitor + Monitor DVI + + + + TV + TV + + + + Default Monitor + Monitor pré-definido + + + + MonitorPictureDialog + + + Dialog + Caixa de diálogo + + + + Magnetic attraction + Atração magnética + + + + MonitorSettingsDialog + + Laptop LCD Monitor + Monitor LCD de portátil + + + External VGA Monitor + Monitor externo VGA + + + VGA Monitor + Monitor VGA + + + External DVI Monitor + Monitor externo DVI + + + DVI Monitor + Monitor DVI + + + TV + TV + + + Default Monitor + Monitor pré-definido + + + Auto + Automático + + + OK? + Aceitar? + + + Yes + Sim + + + About + Sobre + + + Left of + Esquerda de + + + Right of + Direita de + + + Above of + Acima de + + + Below of + Abaixo de + + + Show the same screen on both + Mostrar o mesmo ecrã em ambos + + + Turn off first monitor and use second monitor only + Desligar o primeiro monitor e utilizar o segundo + + + Turn off second monitor and use first monitor only + Desligar o segundo monitor e utilizar o primeiro + + + LXQt-config-monitor + +Monitor configuration tool for LXQt. + LXQt-config-monitor + +Ferramenta de configuração de monitores do LXQt. + + + + Monitor Settings + Definições do monitor + + + + Quick Options + Opções rápidas + + + + Show the same screen on both laptop LCD and external monitor + Mostrar o mesmo ecrã no portátil e no monitor externo + + + + Extended view + Vista detalhada + + + + Turn off laptop LCD and use external monitor only + Desligar ecrã do portátil e utilizar o monitor externo + + + + Turn off external monitor and use laptop LCD only + Desligar o monitor externo e utilizar o ecrã do portátil + + + + Settings + Definições + + + + Unify all monitors + Unificar todos os monitores + + + + Monitor Position + Posição do monitor + + + + Primary monitor: + Monitor principal: + + + + Do you want to save changes? + Quer guardar as alterações? + + + + Please, check your config before to save. + Verifique a configuraçao antes de guardar. + + + + Error + Erro + + + + Config can not be saved + Não é possível guardar a configuração + + + + MonitorWidget + + + Turn on + Ligar + + + + Resolution: + Resolução: + + + + Rate: + Taxa: + + + + Hz + Hz + + + + Position: + Posição: + + + + x: + x: + + + + y: + y: + + + + Brightness: + Brilho: + + + + Gamma: + Gama: + + + + + : + : + + + + Backlight: + Luz de fundo: + + + + + Auto + Automático + + + + QObject + + + + Auto + Automático + + + + TimeoutDialog + + + Settings are changed + Definições alteradas + + + + Are the current settings OK for you? + As definições estão certas para si? + + + + %1 second(s) remaining + %1 segundo(s) em falta + + + diff --git a/lxqt-config-monitor/translations/lxqt-config-monitor_ru.desktop b/lxqt-config-monitor/translations/lxqt-config-monitor_ru.desktop new file mode 100644 index 0000000..ab3984e --- /dev/null +++ b/lxqt-config-monitor/translations/lxqt-config-monitor_ru.desktop @@ -0,0 +1,4 @@ +# Translations +Comment[ru]=Настроить мониторы +Name[ru]=Настройки монитора +GenericName[ru]=Настройки монитора \ No newline at end of file diff --git a/lxqt-config-monitor/translations/lxqt-config-monitor_ru.ts b/lxqt-config-monitor/translations/lxqt-config-monitor_ru.ts new file mode 100644 index 0000000..5169d68 --- /dev/null +++ b/lxqt-config-monitor/translations/lxqt-config-monitor_ru.ts @@ -0,0 +1,244 @@ + + + + + MonitorInfo + + + Laptop LCD Monitor + ЖК-монитор лэптопа + + + + External VGA Monitor + Внешний VGA-монитор + + + + VGA Monitor + VGA-монитор + + + + External DVI Monitor + Внешний DVI-монитор + + + + DVI Monitor + DVI-монитор + + + + TV + ТВ + + + + Default Monitor + Монитор по умолчанию + + + + MonitorPictureDialog + + + Dialog + + + + + Magnetic attraction + + + + + MonitorSettingsDialog + + + Monitor Settings + Настройки монитора + + + + Quick Options + Быстрые настройки + + + + Show the same screen on both laptop LCD and external monitor + Отображать одинаковый экран на внешнем мониторе и ЖК-мониторе лэптопа + + + + Extended view + Расширенный вид + + + + Turn off laptop LCD and use external monitor only + Выключить ЖК-монитор лэптопа и использовать только внешний монитор + + + + Turn off external monitor and use laptop LCD only + Выключить внешний монитор и использовать только ЖК-монитор лэптопа + + + + Settings + Настройки + + + + Unify all monitors + Объединить все мониторы + + + + Monitor Position + + + + + Primary monitor: + Первичный монитор: + + + None + Нет + + + + Do you want to save changes? + + + + + Please, check your config before to save. + + + + + Error + + + + + Config can not be saved + + + + + MonitorWidget + + + Turn on + Включить + + + + Resolution: + Разрешение: + + + + Rate: + Частота: + + + + Hz + Гц + + + + Position: + Позиция: + + + + x: + + + + + y: + + + + + Backlight: + + + + Default + По умолчанию + + + Left of + Левее + + + Right of + Правее + + + Above of + Выше + + + Below of + Ниже + + + + Brightness: + Яркость: + + + + Gamma: + Гамма: + + + + + : + + + + + + Auto + Авто + + + + QObject + + + + Auto + Авто + + + + TimeoutDialog + + + Settings are changed + Настройки изменились + + + + Are the current settings OK for you? + Вам подходят текущие настройки? + + + + %1 second(s) remaining + Осталось %1 секунд(ы) + + + diff --git a/lxqt-config-monitor/translations/lxqt-config-monitor_ru_RU.desktop b/lxqt-config-monitor/translations/lxqt-config-monitor_ru_RU.desktop new file mode 100644 index 0000000..a32362f --- /dev/null +++ b/lxqt-config-monitor/translations/lxqt-config-monitor_ru_RU.desktop @@ -0,0 +1,4 @@ +# Translations +Comment[ru_RU]=Настроить мониторы +Name[ru_RU]=Настройки монитора +GenericName[ru_RU]=Настройки монитора \ No newline at end of file diff --git a/lxqt-config-monitor/translations/lxqt-config-monitor_ru_RU.ts b/lxqt-config-monitor/translations/lxqt-config-monitor_ru_RU.ts new file mode 100644 index 0000000..ff1b65e --- /dev/null +++ b/lxqt-config-monitor/translations/lxqt-config-monitor_ru_RU.ts @@ -0,0 +1,244 @@ + + + + + MonitorInfo + + + Laptop LCD Monitor + ЖК-монитор лэптопа + + + + External VGA Monitor + Внешний VGA-монитор + + + + VGA Monitor + VGA-монитор + + + + External DVI Monitor + Внешний DVI-монитор + + + + DVI Monitor + DVI-монитор + + + + TV + ТВ + + + + Default Monitor + Монитор по умолчанию + + + + MonitorPictureDialog + + + Dialog + + + + + Magnetic attraction + + + + + MonitorSettingsDialog + + + Monitor Settings + Настройки монитора + + + + Quick Options + Быстрые настройки + + + + Show the same screen on both laptop LCD and external monitor + Отображать одинаковый экран на внешнем мониторе и ЖК-мониторе лэптопа + + + + Extended view + Расширенный вид + + + + Turn off laptop LCD and use external monitor only + Выключить ЖК-монитор лэптопа и использовать только внешний монитор + + + + Turn off external monitor and use laptop LCD only + Выключить внешний монитор и использовать только ЖК-монитор лэптопа + + + + Settings + Настройки + + + + Unify all monitors + Объединить все мониторы + + + + Monitor Position + + + + + Primary monitor: + Первичный монитор: + + + None + Нет + + + + Do you want to save changes? + + + + + Please, check your config before to save. + + + + + Error + + + + + Config can not be saved + + + + + MonitorWidget + + + Turn on + Включить + + + + Resolution: + Разрешение: + + + + Rate: + Частота: + + + + Hz + Гц + + + + Position: + Позиция: + + + + x: + + + + + y: + + + + + Backlight: + + + + Default + По умолчанию + + + Left of + Левее + + + Right of + Правее + + + Above of + Выше + + + Below of + Ниже + + + + Brightness: + Яркость: + + + + Gamma: + Гамма: + + + + + : + + + + + + Auto + Авто + + + + QObject + + + + Auto + Авто + + + + TimeoutDialog + + + Settings are changed + Настройки изменились + + + + Are the current settings OK for you? + Вам подходят текущие настройки? + + + + %1 second(s) remaining + Осталось %1 секунд(ы) + + + diff --git a/lxqt-config-monitor/translations/lxqt-config-monitor_zh_TW.desktop b/lxqt-config-monitor/translations/lxqt-config-monitor_zh_TW.desktop new file mode 100644 index 0000000..638e341 --- /dev/null +++ b/lxqt-config-monitor/translations/lxqt-config-monitor_zh_TW.desktop @@ -0,0 +1,4 @@ +# Translations +Comment[zh_TW]=設定螢幕 +GenericName[zh_TW]=螢幕設定 +Name[zh_TW]=LXQt螢幕設定 diff --git a/lxqt-config-monitor/translations/lxqt-config-monitor_zh_TW.ts b/lxqt-config-monitor/translations/lxqt-config-monitor_zh_TW.ts new file mode 100644 index 0000000..16ee953 --- /dev/null +++ b/lxqt-config-monitor/translations/lxqt-config-monitor_zh_TW.ts @@ -0,0 +1,278 @@ + + + + + MonitorInfo + + + Laptop LCD Monitor + 筆記型電腦液晶螢幕 + + + + External VGA Monitor + 外接VGA螢幕 + + + + VGA Monitor + VGA 螢幕 + + + + External DVI Monitor + 外接 DVI 螢幕 + + + + DVI Monitor + DVI 螢幕 + + + + TV + 電視 + + + + Default Monitor + 預設螢幕 + + + + MonitorPictureDialog + + + Dialog + + + + + Magnetic attraction + + + + + MonitorSettingsDialog + + Laptop LCD Monitor + 筆記型電腦液晶螢幕 + + + External VGA Monitor + 外接VGA螢幕 + + + VGA Monitor + VGA 螢幕 + + + External DVI Monitor + 外接 DVI 螢幕 + + + DVI Monitor + DVI 螢幕 + + + TV + 電視 + + + Default Monitor + 預設螢幕 + + + Auto + 自動 + + + Yes + + + + About + 關於 + + + Show the same screen on both + 在兩邊都顯示相同畫面 + + + Turn off first monitor and use second monitor only + 關掉第一個螢幕,只用第二個螢幕 + + + Turn off second monitor and use first monitor only + 關掉第二個螢幕,只用第一個螢幕 + + + LXQt-config-monitor + +Monitor configuration tool for LXQt. + LXQt-config-monitor 螢幕設定工具 + + + + Monitor Settings + + + + + Quick Options + + + + + Show the same screen on both laptop LCD and external monitor + + + + + Extended view + + + + + Turn off laptop LCD and use external monitor only + + + + + Turn off external monitor and use laptop LCD only + + + + + Settings + + + + + Unify all monitors + + + + + Monitor Position + + + + + Primary monitor: + + + + + Do you want to save changes? + + + + + Please, check your config before to save. + + + + + Error + + + + + Config can not be saved + + + + + MonitorWidget + + + Turn on + + + + + Resolution: + + + + + Rate: + + + + + Hz + + + + + Position: + + + + + x: + + + + + y: + + + + + Brightness: + + + + + Gamma: + + + + + + : + + + + + Backlight: + + + + + + Auto + 自動 + + + + QObject + + + + Auto + 自動 + + + + TimeoutDialog + + + Settings are changed + + + + + Are the current settings OK for you? + + + + + %1 second(s) remaining + + + + diff --git a/lxqt-config-monitor/xrandr.cpp b/lxqt-config-monitor/xrandr.cpp new file mode 100644 index 0000000..19dc1c6 --- /dev/null +++ b/lxqt-config-monitor/xrandr.cpp @@ -0,0 +1,271 @@ +/* + Copyright (C) 2014 P.L. Lucas + Copyright (C) 2014 Hong Jen Yee (PCMan) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#include "xrandr.h" +#include +#include +#include +#include +#include +#include + +static QByteArray indentString(QByteArray line) { + QByteArray s; + int length = line.size(); + char ch; + for(int indent=0; indent < length; indent++ ) { + ch = line[indent]; + if( ch == ' ' || ch == '\t' ) + s.append(ch); + else + break; + } + return s; +} + +static int indentLevel(QByteArray line) { + int indent = 0; + while(indent < line.size() && ( line[indent] == ' ' || line[indent] == '\t' ) ) + ++indent; + return indent; +} + +// new parsing code using xrandr --verbose +QList XRandRBackend::getMonitorsInfo() { + QList monitors; + // execute xrandr command and read its output + QProcess process; + // set locale to "C" guarantee English output of xrandr + process.processEnvironment().insert("LC_ALL", "c"); + process.start("xrandr --verbose"); + //process.start("cat pruebas.txt"); + process.waitForFinished(-1); + if(process.exitCode() != 0) + return monitors; + QList lines = process.readAllStandardOutput().split('\n'); + // start parsing the output + QRegExp regMonitorLine("([\\w-]+) +connected +(primary)? *(\\d+x\\d+\\+(\\d+)\\+(\\d+))?.*"); + QRegExp regModeLine("\\s+(\\d+x\\d+).*"); + QRegExp regRateLine("\\s+([vh]):.* clock\\s+([\\d.]+).?Hz.*"); + QRegExp regKeyValue("\\s*(\\w[\\w ]*)\\s*:\\s*(\\S.*)?"); + + bool hasError = false; + MonitorInfo* monitor = NULL; + QList::iterator it = lines.begin(); + bool readingModes = false; + // currently, we only support one X screen, that is screen 0 + while(it != lines.end() && !hasError) { + QByteArray& line = *it; + if(!monitor) { + if(regMonitorLine.exactMatch(line)) { + // format: VGA-0 connected 1280x1024+1024+0 (0x55) normal... + monitor = new MonitorInfo(); + monitor->name = regMonitorLine.cap(1); + if(regMonitorLine.cap(2) == "primary") { // is primary monitor + monitor->primaryOk = true; + } + if(!regMonitorLine.cap(3).isEmpty()) // mode+xpos+ypos + monitor->enabledOk = true; + monitor->xPos = regMonitorLine.cap(4).toInt(); + monitor->yPos = regMonitorLine.cap(5).toInt(); + } + } + else { // reading properties of this monitor + if(regModeLine.exactMatch(line)) { // this is a mode line + // sample: 1280x1024 (0x55) 108.000MHz +HSync +VSync *current +preferred + readingModes = true; + QString mode = regModeLine.cap(1); + QString rate; + bool isCurrent = line.contains("current"); + bool isPreferred = line.contains("preferred"); + ++it; + while(it != lines.end()) { + line = *it; + if(regRateLine.exactMatch(line)) { + // sample: + // h: width 1280 start 1328 end 1440 total 1688 skew 0 clock 63.98KHz + // v: height 1024 start 1025 end 1028 total 1066 clock 60.02Hz + if(regRateLine.cap(1) == QLatin1String("v")) + rate = regRateLine.cap(2); + ++it; + } + else { + --it; + break; // rate lines ended for this mode + } + } + if(!mode.isEmpty() && !rate.isEmpty()) { + if(!monitor->modes.contains(mode)) + monitor->modes.append(mode); + if(!monitor->modeLines.contains(mode)) + monitor->modeLines[mode] = QStringList(); + monitor->modeLines[mode].append(rate); + if(isPreferred) { + monitor->preferredMode = mode; + monitor->preferredRate = rate; + } + if(isCurrent) { + monitor->currentMode = mode; + monitor->currentRate = rate; + } + } + } + else { // this is not a mode line, read other properties + if(readingModes) { + // mode lines ended, so the whole monitor info is read + monitors.append(monitor); + monitor = NULL; + readingModes = false; + continue; + } + + if(regKeyValue.exactMatch(line)) { // format: : + QString key = regKeyValue.cap(1); + QString value = regKeyValue.cap(2); + QByteArray lineStringStart = indentString(line); + int propertyIndentLevel = indentLevel(line); + ++it; + while( it != lines.end() ) { + QByteArray& line = *it; + int actualIndentLevel = indentLevel(line); + if( actualIndentLevel>propertyIndentLevel && line.startsWith(lineStringStart) ) { + value += "\n" + line.trimmed(); + ++it; + } else + break; + } + qDebug() << key << "=" << value; + if(key == "Gamma") { + monitor->gamma = value; + } + else if(key == "Brightness") { + monitor->brightness = value; + } + else if(key == "EDID") { + monitor->edid = value ; + // Get vendor + QString hex = value.replace("\n","").replace(" ","").toLower(); + int vendorPosStart = hex.indexOf("fc00"); + if(vendorPosStart>0) { + int vendorPosEnd = hex.indexOf("00", vendorPosStart+4); + QString vendorHex = hex.mid(vendorPosStart+4, vendorPosEnd-vendorPosStart-4); + QByteArray vendor; + //vendor = QByteArray::fromHex(vendorHex.toLocal8Bit()).trimmed(); + //qDebug() << "VendorHex:" << vendorHex << "Vendor" << vendor ; + // QByteArray::fromHex sometimes fails. This a trick + vendor=""; + for(int i=1; ivendor = vendor; + } + } + else if(key == "Backlight") { + QRegExp rx("(\\d+)"); + QStringList list; + int pos = 0; + while ((pos = rx.indexIn(value, pos)) != -1) { + list << rx.cap(1); + pos += rx.matchedLength(); + } + if(list.length()==3) { + monitor->backlight=list[0]; + monitor->backlightMin=list[1]; + monitor->backlightMax=list[2]; + } + } + continue; + } // End format: : + else { // this line is not key:value + } + } + } + if( it != lines.end() ) ++it; + } + + if(monitor) // this should not happen unless a parsing error happens + delete monitor; + + return monitors; +} + + + +bool XRandRBackend::setMonitorsSettings(const QList monitors) { + QString cmd = getCommand(monitors); + qDebug() << cmd; + // return true; + QProcess process; + process.start(cmd); + process.waitForFinished(); + return process.exitCode() == 0; +} + + + + +QString XRandRBackend::getCommand(const QList monitors) { + + QByteArray cmd = "xrandr"; + + foreach(MonitorSettings * monitor, monitors) { + cmd += " --output "; + cmd.append(monitor->name); + cmd.append(' '); + + // if the monitor is turned on + if(monitor->enabledOk) { + QString sel_res = monitor->currentMode; + QString sel_rate = monitor->currentRate; + + if(sel_res == QObject::tr("Auto")) // auto resolution + cmd.append("--auto"); + else { + cmd.append("--mode "); + cmd.append(sel_res); + if(sel_rate != QObject::tr("Auto")) { // not auto refresh rate + cmd.append(" --rate "); + cmd.append(sel_rate); + } + } + if(monitor->position == MonitorSettings::Manual) { // Manual position + cmd.append(QString(" --pos %1x%2").arg(monitor->xPos).arg(monitor->yPos)); + } else // Unify output + cmd.append(QString(" --pos 0x0")); + if(monitor->primaryOk) + cmd.append(" --primary"); + cmd.append(" --brightness "); + cmd.append(monitor->brightness); + cmd.append(" --gamma "); + cmd.append(monitor->gamma); + if( !monitor->backlight.isEmpty() ) { + cmd.append(" --set Backlight "); + cmd.append(monitor->backlight); + } + } + else // turn off + cmd.append("--off"); + } + + + qDebug() << "cmd:" << cmd; + return cmd; +} + diff --git a/lxqt-config-monitor/xrandr.h b/lxqt-config-monitor/xrandr.h new file mode 100644 index 0000000..7861aba --- /dev/null +++ b/lxqt-config-monitor/xrandr.h @@ -0,0 +1,36 @@ +/* + Copyright (C) 2014 P.L. Lucas + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef _XRANDR_H_ +#define _XRANDR_H_ + +#include "monitor.h" +#include + + +class XRandRBackend: public MonitorSettingsBackend { + Q_OBJECT +public: + // Execute xrandr command and read its output + QList getMonitorsInfo(); + // Set changes in xrandr + bool setMonitorsSettings(const QList monitors); + QString getCommand(const QList monitors); +}; + +#endif \ No newline at end of file diff --git a/man/lxqt-config.1 b/man/lxqt-config.1 new file mode 100644 index 0000000..5f5d7c6 --- /dev/null +++ b/man/lxqt-config.1 @@ -0,0 +1,59 @@ +.TH lxqt-config "1" "September 2012" "LXQt 0.7.0" "LXQt System Settings" +.SH NAME +lxqt-config \- \fBLXQt\fR Settings Center for all related modules and applications +.SH SYNOPSIS +.B lxqt-config +.br +.SH DESCRIPTION +This application its a settings center of all environment related applications, and all +config software instaled and registered by the \fBLXQt\fR desktop environment. +.P +\fBLXQt\fR is an advanced, easy-to-use, and fast desktop environment based on Qt +technologies, ships several core desktop components, all of which are optional: +.P + * Panel + * Desktop + * Application launcher + * Settings center \fI(this)\fR + * Session handler + * Polkit handler + * SSH password access + * Display manager handler +.P +These components perform similar actions to those available in other desktop +environments, and their names are self-descriptive. They are usually not launched +by hand but automatically, when choosing a \fBLXQt\fR session in the Display +Manager. +.P +.SH LXQt Settings Center related applications +.P +\fBLXQt\fR has various config applications: +.P + * Mouse settings: (\fBlxqt-config-mouse\fR) + * Desktop settings: (\fBlxqt-config-desktop\fR) + * Appereance settings: (\fBlxqt-config-appearance\fR) + * Session settings: (\fBlxqt-config-session\fR) + * Notification settings: (\fBlxqt-config-notificationd\fR) +.P +All of this also can be find in Settings or Preferences menu, please consult the respective manpages. +.SH "REPORTING BUGS" +Report bugs to https://github.com/lxde/lxde-qt/issues +.SH "SEE ALSO" +\fBLXQt\fR it has been tailored for users who value simplicity, speed, and +an intuitive interface. LXQt is also intended for less powerful machines. See: + +.\" any module must refers to session app, for more info on start it +.P + * Mouse settings: \fBlxqt-config-mouse.1\fR +.P + * Desktop settings: \fBlxqt-config-desktop.1\fR +.P + * Appeareance settings: \fBlxqt-config-appearance.1\fR +.P + * Session settings: \fBlxqt-config-session.1\fR +.P + * Notification settings: \fBlxqt-config-notificationd.1\fR +.P +.SH AUTHOR +This manual page was created by \fBPICCORO Lenz McKAY\fR \fI\fR +for \fBLXQt\fR project and VENENUX GNU/Linux but can be used by others. diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000..2b71dfd --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,67 @@ +project(lxqt-config) +add_subdirectory(qcategorizedview) + +include_directories ( + ${CMAKE_CURRENT_BINARY_DIR} + ${LXQT_INCLUDE_DIRS} + ${QTXDG_INCLUDE_DIRS} + "${CMAKE_CURRENT_SOURCE_DIR}/qcategorizedview" +) + +set(lxqt-config_HDRS "") + +set(lxqt-config_SRCS + main.cpp + mainwindow.cpp +) + +set(lxqt-config_MOCS + mainwindow.h +) + +set(lxqt-config_UIS + mainwindow.ui +) + +qt5_wrap_ui(UIS ${lxqt-config_UIS}) + +# Translations ********************************** +lxqt_translate_ts(QM_FILES + UPDATE_TRANSLATIONS + ${UPDATE_TRANSLATIONS} + SOURCES + ${lxqt-config_HDRS} + ${lxqt-config_SRCS} + ${lxqt-config_UIS} + INSTALL_DIR + "${LXQT_TRANSLATIONS_DIR}/${PROJECT_NAME}" +) + +lxqt_app_translation_loader(QM_LOADER ${PROJECT_NAME}) +lxqt_translate_desktop(DESKTOP_FILES SOURCES lxqt-config.desktop.in) + +#************************************************ + +add_executable(lxqt-config + ${lxqt-config_SRCS} + ${UIS} + ${MOCS} + ${DESKTOP_FILES} + ${QM_FILES} + ${QM_LOADER} +) + +target_link_libraries(lxqt-config + KF5::WindowSystem + Qt5::Widgets + Qt5::Xml + ${QTXDG_LIBRARIES} + ${LXQT_LIBRARIES} +) +# helper static lib +link_directories(${CMAKE_CURRENT_SOURCE_DIR}/qcategorizedview) +target_link_libraries(lxqt-config qcategorizedview) + +install(TARGETS lxqt-config RUNTIME DESTINATION bin) +install(FILES ${DESKTOP_FILES} DESTINATION "${CMAKE_INSTALL_PREFIX}/share/applications") +install(FILES lxqt-config.menu DESTINATION /etc/xdg/menus/) diff --git a/src/lxqt-config.desktop.in b/src/lxqt-config.desktop.in new file mode 100644 index 0000000..f8d97ca --- /dev/null +++ b/src/lxqt-config.desktop.in @@ -0,0 +1,11 @@ +[Desktop Entry] +Type=Application +Name=LXQt System Settings +GenericName=System Settings +Comment=Configure your system +Exec=lxqt-config +Icon=preferences-system +Categories=Settings;DesktopSettings;Qt;LXQt; +OnlyShowIn=LXDE;LXQt; + +#TRANSLATIONS_DIR=translations diff --git a/src/lxqt-config.menu b/src/lxqt-config.menu new file mode 100644 index 0000000..48e9bf9 --- /dev/null +++ b/src/lxqt-config.menu @@ -0,0 +1,70 @@ + + + Settings + lxqt-menu-applications.directory + + + + + + + Settings + + + + LXQt settings + lxqt-settings-lxqt.directory + + + DesktopSettings + + LXQt + + obconf-qt.desktop + compton-conf.desktop + pcmanfm-qt-desktop-pref.desktop + + + lxqt-config.desktop + System + + + + + + + System settings + lxqt-settings-system.directory + + + Settings + System + + + + + + Other settings + lxqt-settings-other.directory + + + + Settings + + + LXQt + LXDE + System + + + + + + + + LXQt settings + System settings + + + + diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..215d373 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,44 @@ +/* BEGIN_COMMON_COPYRIGHT_HEADER + * (c)LGPL2+ + * + * LXQt - a lightweight, Qt based, desktop toolset + * http://razor-qt.org + * + * Copyright: 2010-2011 Razor team + * Authors: + * Petr Vanek + * + * This program or library is free software; you can redistribute it + * and/or modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + * + * END_COMMON_COPYRIGHT_HEADER */ + +#include +#include "mainwindow.h" + + +int main(int argc, char **argv) +{ + LxQt::SingleApplication app(argc, argv); + + // ensure that we use lxqt-config.menu file. + qputenv("XDG_MENU_PREFIX", "lxqt-"); + + LxQtConfig::MainWindow w; + app.setActivationWindow(&w); + w.show(); + + return app.exec(); +} diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp new file mode 100644 index 0000000..8d5914e --- /dev/null +++ b/src/mainwindow.cpp @@ -0,0 +1,267 @@ +/* BEGIN_COMMON_COPYRIGHT_HEADER + * (c)LGPL2+ + * + * LXQt - a lightweight, Qt based, desktop toolset + * http://lxqt.org + * + * Copyright: 2010-2011 Razor team + * Authors: + * Petr Vanek + * + * This program or library is free software; you can redistribute it + * and/or modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + * + * END_COMMON_COPYRIGHT_HEADER */ + +#include +#include +#include + +#include "mainwindow.h" +#include +#include +#include + +#include +#include +#include +#include + +#include "qcategorizedview.h" +#include "qcategorydrawer.h" +#include "qcategorizedsortfilterproxymodel.h" + +namespace LxQtConfig { + +struct ConfigPaneData: public QSharedData +{ + QString id; + QString category; + XdgDesktopFile xdg; +}; + +class ConfigPane +{ +public: + ConfigPane(): d(new ConfigPaneData) { } + ConfigPane(const ConfigPane &other): d(other.d) { } + + inline QString &id() const { return d->id; } + inline XdgDesktopFile xdg() const { return d->xdg; } + inline void setXdg(XdgDesktopFile xdg) { d->xdg = xdg; } + inline QString &category() const { return d->category; } + + bool operator==(const ConfigPane &other) + { + return d->id == other.id(); + } + +private: + QExplicitlySharedDataPointer d; +}; + + +class ConfigPaneModel: public QAbstractListModel +{ +public: + ConfigPaneModel(): QAbstractListModel() + { + QString menuFile = XdgMenu::getMenuFileName("config.menu"); + XdgMenu xdgMenu; + xdgMenu.setEnvironments(QStringList() << "X-LXQT" << "LXQt" << "LXDE"); + bool res = xdgMenu.read(menuFile); + if (!res) + { + QMessageBox::warning(0, "Parse error", xdgMenu.errorString()); + return; + } + + DomElementIterator it(xdgMenu.xml().documentElement() , "Menu"); + while(it.hasNext()) + { + this->builGroup(it.next()); + } + } + + void builGroup(const QDomElement& xml) + { + QString category; + if (! xml.attribute("title").isEmpty()) + category = xml.attribute("title"); + else + category = xml.attribute("name"); + + DomElementIterator it(xml , "AppLink"); + while(it.hasNext()) + { + QDomElement x = it.next(); + + XdgDesktopFile xdg; + xdg.load(x.attribute("desktopFile")); + + ConfigPane pane; + pane.id() = xdg.value("Icon").toString(); + pane.category() = category; + pane.setXdg(xdg); + m_list.append(pane); + } + } + + void activateItem(const QModelIndex &index) + { + if (!index.isValid()) + return; + m_list[index.row()].xdg().startDetached(); + } + + ~ConfigPaneModel() { } + + int rowCount(const QModelIndex &parent = QModelIndex()) const + { + return m_list.count(); + } + + bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) + { + return false; + } + + QVariant data(const QModelIndex &index, int role) const + { + if (role == Qt::DisplayRole || role == Qt::ToolTipRole) + return m_list[index.row()].xdg().name(); + if (role == QCategorizedSortFilterProxyModel::CategoryDisplayRole) + return m_list[index.row()].category(); + if (role == QCategorizedSortFilterProxyModel::CategorySortRole) + return m_list[index.row()].category(); + if (role == Qt::UserRole) + return m_list[index.row()].id(); + if (role == Qt::DecorationRole) + { + return m_list[index.row()].xdg().icon(XdgIcon::defaultApplicationIcon()); + } + return QVariant(); + } + +private: + QList m_list; +}; + +} + + +class ConfigItemDelegate : public QStyledItemDelegate +{ +public: + ConfigItemDelegate(QCategorizedView* view) : mView(view) { } + ~ConfigItemDelegate() { } + + QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const + { + int height = QStyledItemDelegate::sizeHint(option, index).height(); + return QSize(mView->gridSize().width(), qMin(height, mView->gridSize().height())); + } + +protected: + void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const + { + QStyleOptionViewItemV4 opt = option; + initStyleOption(&opt, index); + + QSize size(mView->gridSize().width(), mView->iconSize().height()); + QPixmap pixmap = opt.icon.pixmap(mView->iconSize()); + opt.icon = QIcon(pixmap.copy(QRect(QPoint(0, 0), size))); + opt.decorationSize = size; + + QApplication::style()->drawControl(QStyle::CE_ItemViewItem, &opt, painter); + } + +private: + QCategorizedView *mView; +}; + + +LxQtConfig::MainWindow::MainWindow() : QMainWindow() +{ + setupUi(this); + + model = new ConfigPaneModel(); + + view->setViewMode(QListView::IconMode); + view->setIconSize(QSize(32, 32)); + view->setGridSize(QSize(100, 100)); + view->setWordWrap(true); + view->setUniformItemSizes(true); + view->setCategoryDrawer(new QCategoryDrawerV3(view)); + + // Qt bug: signal activated should respect the hint, but it doesn't + if (style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick)) + connect(view, SIGNAL(clicked(const QModelIndex&)), SLOT(activateItem(const QModelIndex&))); + else + connect(view, SIGNAL(doubleClicked(const QModelIndex&)), SLOT(activateItem(const QModelIndex&))); + view->setFocus(); + + QTimer::singleShot(1, this, SLOT(load())); +} + +bool LxQtConfig::MainWindow::event(QEvent* event) +{ + // LXQt's Qt5 plugin sends a ThemeChange event + if (event->type() == QEvent::ThemeChange) + { + // Qt bug: signal activated should respect the hint, but it doesn't + if (style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick)) + { + view->disconnect(this); + connect(view, SIGNAL(clicked(const QModelIndex&)), SLOT(activateItem(const QModelIndex&))); + } + else + { + view->disconnect(this); + connect(view, SIGNAL(doubleClicked(const QModelIndex&)), SLOT(activateItem(const QModelIndex&))); + } + } + else if (event->type() == QEvent::KeyRelease) + { + int key = static_cast(event)->key(); + if (key == Qt::Key_Enter || key == Qt::Key_Return) + activateItem(view->selectionModel()->currentIndex()); + } + + return QMainWindow::event(event); +} + +void LxQtConfig::MainWindow::load() +{ + QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); + + proxyModel = new QCategorizedSortFilterProxyModel(); + proxyModel->setCategorizedModel(true); + proxyModel->setSourceModel(model); + + view->setModel(proxyModel); + view->setItemDelegate(new ConfigItemDelegate(view)); + + QApplication::restoreOverrideCursor(); +} + +void LxQtConfig::MainWindow::activateItem(const QModelIndex &index) +{ + if (!index.isValid()) + return; + + QModelIndex orig = proxyModel->mapToSource(index); + model->activateItem(orig); +} diff --git a/src/mainwindow.h b/src/mainwindow.h new file mode 100644 index 0000000..eb79265 --- /dev/null +++ b/src/mainwindow.h @@ -0,0 +1,69 @@ +/* BEGIN_COMMON_COPYRIGHT_HEADER + * (c)LGPL2+ + * + * LXQt - a lightweight, Qt based, desktop toolset + * http://razor-qt.org + * + * Copyright: 2010-2011 Razor team + * Authors: + * Petr Vanek + * + * This program or library is free software; you can redistribute it + * and/or modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + * + * END_COMMON_COPYRIGHT_HEADER */ + +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + + + +#include "ui_mainwindow.h" +#include + +class QCategorizedSortFilterProxyModel; + +namespace LxQtConfig { + + class ConfigPaneModel; + +/*! \brief Main config window. +Just read desktop files with Settings category from /usr/share/applications +and list them in view. Then it can start those standalone apps. +*/ +class MainWindow : public QMainWindow, public Ui::MainWindow +{ + Q_OBJECT + +public: + MainWindow(); + +private: + QCategorizedSortFilterProxyModel *proxyModel; + ConfigPaneModel *model; + +private: + void builGroup(const QDomElement& xml); + bool event(QEvent *event); + +private slots: + void load(); + void activateItem(const QModelIndex &index); +}; + +}; // namespace + + +#endif diff --git a/src/mainwindow.ui b/src/mainwindow.ui new file mode 100644 index 0000000..02002d6 --- /dev/null +++ b/src/mainwindow.ui @@ -0,0 +1,89 @@ + + + MainWindow + + + + 0 + 0 + 696 + 404 + + + + Configuration Center + + + + + + + + 0 + + + 1 + + + 1 + + + + + QFrame::NoFrame + + + + + + + 4 + + + 4 + + + 4 + + + 4 + + + + + QDialogButtonBox::Close + + + + + + + + + + + QCategorizedView + QListView +
qcategorizedview.h
+
+
+ + + + buttonBox + rejected() + MainWindow + close() + + + 481 + 324 + + + 458 + 341 + + + + +
diff --git a/src/qcategorizedview/CMakeLists.txt b/src/qcategorizedview/CMakeLists.txt new file mode 100644 index 0000000..ffa4403 --- /dev/null +++ b/src/qcategorizedview/CMakeLists.txt @@ -0,0 +1,14 @@ +project(qcategorizedview) + +set(SOURCES + qcategorizedview.cpp + qcategorydrawer.cpp + qcategorizedsortfilterproxymodel.cpp +) + +include_directories( + "${CMAKE_CURRENT_BINARY_DIR}" +) + +add_library(qcategorizedview STATIC ${SOURCES} ${MOC_SOURCES}) +target_link_libraries(qcategorizedview Qt5::Widgets) diff --git a/src/qcategorizedview/qcategorizedsortfilterproxymodel.cpp b/src/qcategorizedview/qcategorizedsortfilterproxymodel.cpp new file mode 100644 index 0000000..c74636b --- /dev/null +++ b/src/qcategorizedview/qcategorizedsortfilterproxymodel.cpp @@ -0,0 +1,320 @@ +/** + * (c)LGPL2+ + * This file is part of the KDE project + * Copyright (C) 2007 Rafael Fernández López + * Copyright (C) 2007 John Tapsell + * + * 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 "qcategorizedsortfilterproxymodel.h" +#include "qcategorizedsortfilterproxymodel_p.h" + +#include + +#include +#include +#include + +//#include + +int naturalCompare(const QString &_a, const QString &_b, Qt::CaseSensitivity caseSensitivity = Qt::CaseSensitive) +{ + // This method chops the input a and b into pieces of + // digits and non-digits (a1.05 becomes a | 1 | . | 05) + // and compares these pieces of a and b to each other + // (first with first, second with second, ...). + // + // This is based on the natural sort order code code by Martin Pool + // http://sourcefrog.net/projects/natsort/ + // Martin Pool agreed to license this under LGPL or GPL. + + // FIXME: Using toLower() to implement case insensitive comparison is + // sub-optimal, but is needed because we compare strings with + // localeAwareCompare(), which does not know about case sensitivity. + // A task has been filled for this in Qt Task Tracker with ID 205990. + // http://trolltech.com/developer/task-tracker/index_html?method=entry&id=205990 + QString a; + QString b; + if (caseSensitivity == Qt::CaseSensitive) { + a = _a; + b = _b; + } else { + a = _a.toLower(); + b = _b.toLower(); + } + + const QChar* currA = a.unicode(); // iterator over a + const QChar* currB = b.unicode(); // iterator over b + + if (currA == currB) { + return 0; + } + + while (!currA->isNull() && !currB->isNull()) { + const QChar* begSeqA = currA; // beginning of a new character sequence of a + const QChar* begSeqB = currB; + if (currA->unicode() == QChar::ObjectReplacementCharacter) { + return 1; + } + + if (currB->unicode() == QChar::ObjectReplacementCharacter) { + return -1; + } + + if (currA->unicode() == QChar::ReplacementCharacter) { + return 1; + } + + if (currB->unicode() == QChar::ReplacementCharacter) { + return -1; + } + + // find sequence of characters ending at the first non-character + while (!currA->isNull() && !currA->isDigit() && !currA->isPunct() && !currA->isSpace()) { + ++currA; + } + + while (!currB->isNull() && !currB->isDigit() && !currB->isPunct() && !currB->isSpace()) { + ++currB; + } + + // compare these sequences + const QStringRef& subA(a.midRef(begSeqA - a.unicode(), currA - begSeqA)); + const QStringRef& subB(b.midRef(begSeqB - b.unicode(), currB - begSeqB)); + const int cmp = QStringRef::localeAwareCompare(subA, subB); + if (cmp != 0) { + return cmp < 0 ? -1 : +1; + } + + if (currA->isNull() || currB->isNull()) { + break; + } + + // find sequence of characters ending at the first non-character + while ((currA->isPunct() || currA->isSpace()) && (currB->isPunct() || currB->isSpace())) { + if (*currA != *currB) { + return (*currA < *currB) ? -1 : +1; + } + ++currA; + ++currB; + if (currA->isNull() || currB->isNull()) { + break; + } + } + + // now some digits follow... + if ((*currA == QLatin1Char('0')) || (*currB == QLatin1Char('0'))) { + // one digit-sequence starts with 0 -> assume we are in a fraction part + // do left aligned comparison (numbers are considered left aligned) + while (1) { + if (!currA->isDigit() && !currB->isDigit()) { + break; + } else if (!currA->isDigit()) { + return +1; + } else if (!currB->isDigit()) { + return -1; + } else if (*currA < *currB) { + return -1; + } else if (*currA > *currB) { + return + 1; + } + ++currA; + ++currB; + } + } else { + // No digit-sequence starts with 0 -> assume we are looking at some integer + // do right aligned comparison. + // + // The longest run of digits wins. That aside, the greatest + // value wins, but we can't know that it will until we've scanned + // both numbers to know that they have the same magnitude. + + bool isFirstRun = true; + int weight = 0; + while (1) { + if (!currA->isDigit() && !currB->isDigit()) { + if (weight != 0) { + return weight; + } + break; + } else if (!currA->isDigit()) { + if (isFirstRun) { + return *currA < *currB ? -1 : +1; + } else { + return -1; + } + } else if (!currB->isDigit()) { + if (isFirstRun) { + return *currA < *currB ? -1 : +1; + } else { + return +1; + } + } else if ((*currA < *currB) && (weight == 0)) { + weight = -1; + } else if ((*currA > *currB) && (weight == 0)) { + weight = + 1; + } + ++currA; + ++currB; + isFirstRun = false; + } + } + } + + if (currA->isNull() && currB->isNull()) { + return 0; + } + + return currA->isNull() ? -1 : + 1; +} + +QCategorizedSortFilterProxyModel::QCategorizedSortFilterProxyModel(QObject *parent) + : QSortFilterProxyModel(parent) + , d(new Private()) + +{ +} + +QCategorizedSortFilterProxyModel::~QCategorizedSortFilterProxyModel() +{ + delete d; +} + +void QCategorizedSortFilterProxyModel::sort(int column, Qt::SortOrder order) +{ + d->sortColumn = column; + d->sortOrder = order; + + QSortFilterProxyModel::sort(column, order); +} + +bool QCategorizedSortFilterProxyModel::isCategorizedModel() const +{ + return d->categorizedModel; +} + +void QCategorizedSortFilterProxyModel::setCategorizedModel(bool categorizedModel) +{ + if (categorizedModel == d->categorizedModel) + { + return; + } + + d->categorizedModel = categorizedModel; + + invalidate(); +} + +int QCategorizedSortFilterProxyModel::sortColumn() const +{ + return d->sortColumn; +} + +Qt::SortOrder QCategorizedSortFilterProxyModel::sortOrder() const +{ + return d->sortOrder; +} + +void QCategorizedSortFilterProxyModel::setSortCategoriesByNaturalComparison(bool sortCategoriesByNaturalComparison) +{ + if (sortCategoriesByNaturalComparison == d->sortCategoriesByNaturalComparison) + { + return; + } + + d->sortCategoriesByNaturalComparison = sortCategoriesByNaturalComparison; + + invalidate(); +} + +bool QCategorizedSortFilterProxyModel::sortCategoriesByNaturalComparison() const +{ + return d->sortCategoriesByNaturalComparison; +} + +bool QCategorizedSortFilterProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const +{ + if (d->categorizedModel) + { + int compare = compareCategories(left, right); + + if (compare > 0) // left is greater than right + { + return false; + } + else if (compare < 0) // left is less than right + { + return true; + } + } + + return subSortLessThan(left, right); +} + +bool QCategorizedSortFilterProxyModel::subSortLessThan(const QModelIndex &left, const QModelIndex &right) const +{ + return QSortFilterProxyModel::lessThan(left, right); +} + +int QCategorizedSortFilterProxyModel::compareCategories(const QModelIndex &left, const QModelIndex &right) const +{ + QVariant l = (left.model() ? left.model()->data(left, CategorySortRole) : QVariant()); + QVariant r = (right.model() ? right.model()->data(right, CategorySortRole) : QVariant()); + + Q_ASSERT(l.isValid()); + Q_ASSERT(r.isValid()); + Q_ASSERT(l.type() == r.type()); + + if (l.type() == QVariant::String) + { + QString lstr = l.toString(); + QString rstr = r.toString(); + + if (d->sortCategoriesByNaturalComparison) + { + return naturalCompare(lstr, rstr); + } + else + { + if (lstr < rstr) + { + return -1; + } + + if (lstr > rstr) + { + return 1; + } + + return 0; + } + } + + qlonglong lint = l.toLongLong(); + qlonglong rint = r.toLongLong(); + + if (lint < rint) + { + return -1; + } + + if (lint > rint) + { + return 1; + } + + return 0; +} diff --git a/src/qcategorizedview/qcategorizedsortfilterproxymodel.h b/src/qcategorizedview/qcategorizedsortfilterproxymodel.h new file mode 100644 index 0000000..95f0c71 --- /dev/null +++ b/src/qcategorizedview/qcategorizedsortfilterproxymodel.h @@ -0,0 +1,177 @@ +/* + * (c)LGPL2+ + * This file is part of the KDE project + * Copyright (C) 2007 Rafael Fernández López + * Copyright (C) 2007 John Tapsell + * + * 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 KCATEGORIZEDSORTFILTERPROXYMODEL_H +#define KCATEGORIZEDSORTFILTERPROXYMODEL_H + +#include + +#define KDEUI_EXPORT + +//#include + +class QItemSelection; + + +/** + * This class lets you categorize a view. It is meant to be used along with + * QCategorizedView class. + * + * In general terms all you need to do is to reimplement subSortLessThan() and + * compareCategories() methods. In order to make categorization work, you need + * to also call setCategorizedModel() class to enable it, since the categorization + * is disabled by default. + * + * @see QCategorizedView + * + * @author Rafael Fernández López + */ +class KDEUI_EXPORT QCategorizedSortFilterProxyModel + : public QSortFilterProxyModel +{ +public: + enum AdditionalRoles { + // Note: use printf "0x%08X\n" $(($RANDOM*$RANDOM)) + // to define additional roles. + CategoryDisplayRole = 0x17CE990A, ///< This role is used for asking the category to a given index + + CategorySortRole = 0x27857E60 ///< This role is used for sorting categories. You can return a + ///< string or a long long value. Strings will be sorted alphabetically + ///< while long long will be sorted by their value. Please note that this + ///< value won't be shown on the view, is only for sorting purposes. What will + ///< be shown as "Category" on the view will be asked with the role + ///< CategoryDisplayRole. + }; + + QCategorizedSortFilterProxyModel(QObject *parent = 0); + virtual ~QCategorizedSortFilterProxyModel(); + + /** + * Overridden from QSortFilterProxyModel. Sorts the source model using + * @p column for the given @p order. + */ + virtual void sort(int column, Qt::SortOrder order = Qt::AscendingOrder); + + /** + * @return whether the model is categorized or not. Disabled by default. + */ + bool isCategorizedModel() const; + + /** + * Enables or disables the categorization feature. + * + * @param categorizedModel whether to enable or disable the categorization feature. + */ + void setCategorizedModel(bool categorizedModel); + + /** + * @return the column being used for sorting. + */ + int sortColumn() const; + + /** + * @return the sort order being used for sorting. + */ + Qt::SortOrder sortOrder() const; + + /** + * Set if the sorting using CategorySortRole will use a natural comparison + * in the case that strings were returned. If enabled, QString::localeAwareCompare + * will be used for sorting. + * + * @param sortCategoriesByNaturalComparison whether to sort using a natural comparison or not. + */ + void setSortCategoriesByNaturalComparison(bool sortCategoriesByNaturalComparison); + + /** + * @return whether it is being used a natural comparison for sorting. Enabled by default. + */ + bool sortCategoriesByNaturalComparison() const; + +protected: + /** + * Overridden from QSortFilterProxyModel. If you are subclassing + * QCategorizedSortFilterProxyModel, you will probably not need to reimplement this + * method. + * + * It calls compareCategories() to sort by category. If the both items are in the + * same category (i.e. compareCategories returns 0), then subSortLessThan is called. + * + * @return Returns true if the item @p left is less than the item @p right when sorting. + * + * @warning You usually won't need to reimplement this method when subclassing + * from QCategorizedSortFilterProxyModel. + */ + virtual bool lessThan(const QModelIndex &left, const QModelIndex &right) const; + + /** + * This method has a similar purpose as lessThan() has on QSortFilterProxyModel. + * It is used for sorting items that are in the same category. + * + * @return Returns true if the item @p left is less than the item @p right when sorting. + */ + virtual bool subSortLessThan(const QModelIndex &left, const QModelIndex &right) const; + + /** + * This method compares the category of the @p left index with the category + * of the @p right index. + * + * Internally and if not reimplemented, this method will ask for @p left and + * @p right models for role CategorySortRole. In order to correctly sort + * categories, the data() metod of the model should return a qlonglong (or numeric) value, or + * a QString object. QString objects will be sorted with QString::localeAwareCompare if + * sortCategoriesByNaturalComparison() is true. + * + * @note Please have present that: + * QString(QChar(QChar::ObjectReplacementCharacter)) > + * QString(QChar(QChar::ReplacementCharacter)) > + * [ all possible strings ] > + * QString(); + * + * This means that QString() will be sorted the first one, while + * QString(QChar(QChar::ObjectReplacementCharacter)) and + * QString(QChar(QChar::ReplacementCharacter)) will be sorted in last + * position. + * + * @warning Please note that data() method of the model should return always + * information of the same type. If you return a QString for an index, + * you should return always QStrings for all indexes for role CategorySortRole + * in order to correctly sort categories. You can't mix by returning + * a QString for one index, and a qlonglong for other. + * + * @note If you need a more complex layout, you will have to reimplement this + * method. + * + * @return A negative value if the category of @p left should be placed before the + * category of @p right. 0 if @p left and @p right are on the same category, and + * a positive value if the category of @p left should be placed after the + * category of @p right. + */ + virtual int compareCategories(const QModelIndex &left, const QModelIndex &right) const; + +private: + class Private; + Private *const d; +}; + + +#endif // KCATEGORIZEDSORTFILTERPROXYMODEL_H diff --git a/src/qcategorizedview/qcategorizedsortfilterproxymodel_p.h b/src/qcategorizedview/qcategorizedsortfilterproxymodel_p.h new file mode 100644 index 0000000..f2cd9a0 --- /dev/null +++ b/src/qcategorizedview/qcategorizedsortfilterproxymodel_p.h @@ -0,0 +1,49 @@ +/** + * (c)LGPL2+ + * This file is part of the KDE project + * Copyright (C) 2007 Rafael Fernández López + * Copyright (C) 2007 John Tapsell + * + * 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 KCATEGORIZEDSORTFILTERPROXYMODEL_P_H +#define KCATEGORIZEDSORTFILTERPROXYMODEL_P_H + +class QCategorizedSortFilterProxyModel; + +class QCategorizedSortFilterProxyModel::Private +{ +public: + Private() + : sortColumn(0) + , sortOrder(Qt::AscendingOrder) + , categorizedModel(false) + , sortCategoriesByNaturalComparison(true) + { + } + + ~Private() + { + } + + int sortColumn; + Qt::SortOrder sortOrder; + bool categorizedModel; + bool sortCategoriesByNaturalComparison; +}; + +#endif diff --git a/src/qcategorizedview/qcategorizedview.cpp b/src/qcategorizedview/qcategorizedview.cpp new file mode 100644 index 0000000..4c3ca6e --- /dev/null +++ b/src/qcategorizedview/qcategorizedview.cpp @@ -0,0 +1,1535 @@ +/** + * (c)LGPL2+ + * This file is part of the KDE project + * Copyright (C) 2007, 2009 Rafael Fernández López + * + * 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. + */ + +/** + * IMPLEMENTATION NOTES: + * + * QListView::setRowHidden() and QListView::isRowHidden() are not taken into + * account. This methods should actually not exist. This effect should be handled + * by an hypothetical QSortFilterProxyModel which filters out the desired rows. + * + * In case this needs to be implemented, contact me, but I consider this a faulty + * design. + */ + +#include "qcategorizedview.h" +#include "qcategorizedview_p.h" + +#include // trunc on C99 compliant systems +//#include // trunc for not C99 compliant systems + +#include +#include +#include + +#include "qcategorydrawer.h" +#include "qcategorizedsortfilterproxymodel.h" + +//BEGIN: Private part + +struct QCategorizedView::Private::Item +{ + Item() + : topLeft(QPoint()) + , size(QSize()) + { + } + + QPoint topLeft; + QSize size; +}; + +struct QCategorizedView::Private::Block +{ + Block() + : topLeft(QPoint()) + , height(-1) + , firstIndex(QModelIndex()) + , quarantineStart(QModelIndex()) + , items(QList()) + , outOfQuarantine(false) + , alternate(false) + , collapsed(false) + { + } + + bool operator!=(const Block &rhs) const + { + return firstIndex != rhs.firstIndex; + } + + static bool lessThan(const Block &left, const Block &right) + { + Q_ASSERT(left.firstIndex.isValid()); + Q_ASSERT(right.firstIndex.isValid()); + return left.firstIndex.row() < right.firstIndex.row(); + } + + QPoint topLeft; + int height; + QPersistentModelIndex firstIndex; + // if we have n elements on this block, and we inserted an element at position i. The quarantine + // will start at index (i, column, parent). This means that for all elements j where i <= j <= n, the + // visual rect position of item j will have to be recomputed (cannot use the cached point). The quarantine + // will only affect the current block, since the rest of blocks can be affected only in the way + // that the whole block will have different offset, but items will keep the same relative position + // in terms of their parent blocks. + QPersistentModelIndex quarantineStart; + QList items; + + // this affects the whole block, not items separately. items contain the topLeft point relative + // to the block. Because of insertions or removals a whole block can be moved, so the whole block + // will enter in quarantine, what is faster than moving all items in absolute terms. + bool outOfQuarantine; + + // should we alternate its color ? is just a hint, could not be used + bool alternate; + bool collapsed; +}; + +QCategorizedView::Private::Private(QCategorizedView *q) + : q(q) + , proxyModel(0) + , categoryDrawer(0) + , categoryDrawerV2(0) + , categoryDrawerV3(0) + , categorySpacing(5) + , alternatingBlockColors(false) + , collapsibleBlocks(false) + , hoveredBlock(new Block()) + , hoveredIndex(QModelIndex()) + , pressedPosition(QPoint()) + , rubberBandRect(QRect()) +{ +} + +QCategorizedView::Private::~Private() +{ + delete hoveredBlock; +} + +bool QCategorizedView::Private::isCategorized() const +{ + return proxyModel && categoryDrawer && proxyModel->isCategorizedModel(); +} + +QStyleOptionViewItemV4 QCategorizedView::Private::blockRect(const QModelIndex &representative) +{ + QStyleOptionViewItemV4 option(q->viewOptions()); + const int height = categoryDrawer->categoryHeight(representative, option); + const QString categoryDisplay = representative.data(QCategorizedSortFilterProxyModel::CategoryDisplayRole).toString(); + QPoint pos = blockPosition(categoryDisplay); + pos.ry() -= height; + option.rect.setTopLeft(pos); + option.rect.setWidth(viewportWidth() + categoryDrawer->leftMargin() + categoryDrawer->rightMargin()); + option.rect.setHeight(height + blockHeight(categoryDisplay)); + option.rect = mapToViewport(option.rect); + + return option; +} + +QPair QCategorizedView::Private::intersectingIndexesWithRect(const QRect &_rect) const +{ + const int rowCount = proxyModel->rowCount(); + + const QRect rect = _rect.normalized(); + + // binary search to find out the top border + int bottom = 0; + int top = rowCount - 1; + while (bottom <= top) { + const int middle = (bottom + top) / 2; + const QModelIndex index = proxyModel->index(middle, q->modelColumn(), q->rootIndex()); + QRect itemRect = q->visualRect(index); + const int verticalOff = q->verticalOffset(); + const int horizontalOff = q->horizontalOffset(); + itemRect.topLeft().ry() += verticalOff; + itemRect.topLeft().rx() += horizontalOff; + itemRect.bottomRight().ry() += verticalOff; + itemRect.bottomRight().rx() += horizontalOff; + if (itemRect.bottomRight().y() <= rect.topLeft().y()) { + bottom = middle + 1; + } else { + top = middle - 1; + } + } + + const QModelIndex bottomIndex = proxyModel->index(bottom, q->modelColumn(), q->rootIndex()); + + // binary search to find out the bottom border + bottom = 0; + top = rowCount - 1; + while (bottom <= top) { + const int middle = (bottom + top) / 2; + const QModelIndex index = proxyModel->index(middle, q->modelColumn(), q->rootIndex()); + QRect itemRect = q->visualRect(index); + const int verticalOff = q->verticalOffset(); + const int horizontalOff = q->horizontalOffset(); + itemRect.topLeft().ry() += verticalOff; + itemRect.topLeft().rx() += horizontalOff; + itemRect.bottomRight().ry() += verticalOff; + itemRect.bottomRight().rx() += horizontalOff; + if (itemRect.topLeft().y() <= rect.bottomRight().y()) { + bottom = middle + 1; + } else { + top = middle - 1; + } + } + + const QModelIndex topIndex = proxyModel->index(top, q->modelColumn(), q->rootIndex()); + + return qMakePair(bottomIndex, topIndex); +} + +QPoint QCategorizedView::Private::blockPosition(const QString &category) +{ + Block &block = blocks[category]; + + if (block.outOfQuarantine && !block.topLeft.isNull()) { + return block.topLeft; + } + + QPoint res(categorySpacing, 0); + + const QModelIndex index = block.firstIndex; + + for (QHash::Iterator it = blocks.begin(); it != blocks.end(); ++it) { + Block &block = *it; + const QModelIndex categoryIndex = block.firstIndex; + if (index.row() < categoryIndex.row()) { + continue; + } + res.ry() += categoryDrawer->categoryHeight(categoryIndex, q->viewOptions()) + categorySpacing; + if (index.row() == categoryIndex.row()) { + continue; + } + res.ry() += blockHeight(it.key()); + } + + block.outOfQuarantine = true; + block.topLeft = res; + + return res; +} + +int QCategorizedView::Private::blockHeight(const QString &category) +{ + Block &block = blocks[category]; + + if (block.collapsed) { + return 0; + } + + if (block.height > -1) { + return block.height; + } + + const QModelIndex firstIndex = block.firstIndex; + const QModelIndex lastIndex = proxyModel->index(firstIndex.row() + block.items.count() - 1, q->modelColumn(), q->rootIndex()); + const QRect topLeft = q->visualRect(firstIndex); + QRect bottomRight = q->visualRect(lastIndex); + + if (hasGrid()) { + bottomRight.setHeight(qMax(bottomRight.height(), q->gridSize().height())); + } else { + if (!q->uniformItemSizes()) { + bottomRight.setHeight(highestElementInLastRow(block) + q->spacing() * 2); + } + } + + const int height = bottomRight.bottomRight().y() - topLeft.topLeft().y() + 1; + block.height = height; + + return height; +} + +int QCategorizedView::Private::viewportWidth() const +{ + return q->viewport()->width() - categorySpacing * 2 - categoryDrawer->leftMargin() - categoryDrawer->rightMargin(); +} + +void QCategorizedView::Private::regenerateAllElements() +{ + for (QHash::Iterator it = blocks.begin(); it != blocks.end(); ++it) { + Block &block = *it; + block.outOfQuarantine = false; + block.quarantineStart = block.firstIndex; + block.height = -1; + } +} + +void QCategorizedView::Private::rowsInserted(const QModelIndex &parent, int start, int end) +{ + if (!isCategorized()) { + return; + } + + for (int i = start; i <= end; ++i) { + const QModelIndex index = proxyModel->index(i, q->modelColumn(), parent); + + Q_ASSERT(index.isValid()); + + const QString category = categoryForIndex(index); + + Block &block = blocks[category]; + + //BEGIN: update firstIndex + // save as firstIndex in block if + // - it forced the category creation (first element on this category) + // - it is before the first row on that category + const QModelIndex firstIndex = block.firstIndex; + if (!firstIndex.isValid() || index.row() < firstIndex.row()) { + block.firstIndex = index; + } + //END: update firstIndex + + Q_ASSERT(block.firstIndex.isValid()); + + const int firstIndexRow = block.firstIndex.row(); + + block.items.insert(index.row() - firstIndexRow, Private::Item()); + block.height = -1; + + q->visualRect(index); + q->viewport()->update(); + } + + //BEGIN: update the items that are in quarantine in affected categories + { + const QModelIndex lastIndex = proxyModel->index(end, q->modelColumn(), parent); + const QString category = categoryForIndex(lastIndex); + Private::Block &block = blocks[category]; + block.quarantineStart = block.firstIndex; + } + //END: update the items that are in quarantine in affected categories + + //BEGIN: mark as in quarantine those categories that are under the affected ones + { + const QModelIndex firstIndex = proxyModel->index(start, q->modelColumn(), parent); + const QString category = categoryForIndex(firstIndex); + const QModelIndex firstAffectedCategory = blocks[category].firstIndex; + //BEGIN: order for marking as alternate those blocks that are alternate + QList blockList = blocks.values(); + qSort(blockList.begin(), blockList.end(), Block::lessThan); + QList firstIndexesRows; + foreach (const Block &block, blockList) { + firstIndexesRows << block.firstIndex.row(); + } + //END: order for marking as alternate those blocks that are alternate + for (QHash::Iterator it = blocks.begin(); it != blocks.end(); ++it) { + Private::Block &block = *it; + if (block.firstIndex.row() > firstAffectedCategory.row()) { + block.outOfQuarantine = false; + block.alternate = firstIndexesRows.indexOf(block.firstIndex.row()) % 2; + } else if (block.firstIndex.row() == firstAffectedCategory.row()) { + block.alternate = firstIndexesRows.indexOf(block.firstIndex.row()) % 2; + } + } + } + //END: mark as in quarantine those categories that are under the affected ones +} + +QRect QCategorizedView::Private::mapToViewport(const QRect &rect) const +{ + const int dx = -q->horizontalOffset(); + const int dy = -q->verticalOffset(); + return rect.adjusted(dx, dy, dx, dy); +} + +QRect QCategorizedView::Private::mapFromViewport(const QRect &rect) const +{ + const int dx = q->horizontalOffset(); + const int dy = q->verticalOffset(); + return rect.adjusted(dx, dy, dx, dy); +} + +int QCategorizedView::Private::highestElementInLastRow(const Block &block) const +{ + //Find the highest element in the last row + const QModelIndex lastIndex = proxyModel->index(block.firstIndex.row() + block.items.count() - 1, q->modelColumn(), q->rootIndex()); + const QRect prevRect = q->visualRect(lastIndex); + int res = prevRect.height(); + QModelIndex prevIndex = proxyModel->index(lastIndex.row() - 1, q->modelColumn(), q->rootIndex()); + if (!prevIndex.isValid()) { + return res; + } + Q_FOREVER { + const QRect tempRect = q->visualRect(prevIndex); + if (tempRect.topLeft().y() < prevRect.topLeft().y()) { + break; + } + res = qMax(res, tempRect.height()); + if (prevIndex == block.firstIndex) { + break; + } + prevIndex = proxyModel->index(prevIndex.row() - 1, q->modelColumn(), q->rootIndex()); + } + + return res; +} + +bool QCategorizedView::Private::hasGrid() const +{ + const QSize gridSize = q->gridSize(); + return gridSize.isValid() && !gridSize.isNull(); +} + +QString QCategorizedView::Private::categoryForIndex(const QModelIndex &index) const +{ + const QModelIndex categoryIndex = index.model()->index(index.row(), proxyModel->sortColumn(), index.parent()); + return categoryIndex.data(QCategorizedSortFilterProxyModel::CategoryDisplayRole).toString(); +} + +void QCategorizedView::Private::leftToRightVisualRect(const QModelIndex &index, Item &item, + const Block &block, const QPoint &blockPos) const +{ + const int firstIndexRow = block.firstIndex.row(); + + if (hasGrid()) { + const int relativeRow = index.row() - firstIndexRow; + const int maxItemsPerRow = qMax(viewportWidth() / q->gridSize().width(), 1); + if (q->layoutDirection() == Qt::LeftToRight) { + item.topLeft.rx() = (relativeRow % maxItemsPerRow) * q->gridSize().width() + blockPos.x() + categoryDrawer->leftMargin(); + } else { + item.topLeft.rx() = viewportWidth() - ((relativeRow % maxItemsPerRow) + 1) * q->gridSize().width() + categoryDrawer->leftMargin() + categorySpacing; + } + item.topLeft.ry() = (relativeRow / maxItemsPerRow) * q->gridSize().height(); + } else { + if (q->uniformItemSizes()) { + const int relativeRow = index.row() - firstIndexRow; + const QSize itemSize = q->sizeHintForIndex(index); + const int maxItemsPerRow = qMax((viewportWidth() - q->spacing()) / (itemSize.width() + q->spacing()), 1); + if (q->layoutDirection() == Qt::LeftToRight) { + item.topLeft.rx() = (relativeRow % maxItemsPerRow) * itemSize.width() + blockPos.x() + categoryDrawer->leftMargin(); + } else { + item.topLeft.rx() = viewportWidth() - (relativeRow % maxItemsPerRow) * itemSize.width() + categoryDrawer->leftMargin() + categorySpacing; + } + item.topLeft.ry() = (relativeRow / maxItemsPerRow) * itemSize.height(); + } else { + const QSize currSize = q->sizeHintForIndex(index); + if (index != block.firstIndex) { + const int viewportW = viewportWidth() - q->spacing(); + QModelIndex prevIndex = proxyModel->index(index.row() - 1, q->modelColumn(), q->rootIndex()); + QRect prevRect = q->visualRect(prevIndex); + prevRect = mapFromViewport(prevRect); + if ((prevRect.bottomRight().x() + 1) + currSize.width() - blockPos.x() + q->spacing() > viewportW) { + // we have to check the whole previous row, and see which one was the + // highest. + Q_FOREVER { + prevIndex = proxyModel->index(prevIndex.row() - 1, q->modelColumn(), q->rootIndex()); + const QRect tempRect = q->visualRect(prevIndex); + if (tempRect.topLeft().y() < prevRect.topLeft().y()) { + break; + } + if (tempRect.bottomRight().y() > prevRect.bottomRight().y()) { + prevRect = tempRect; + } + if (prevIndex == block.firstIndex) { + break; + } + } + if (q->layoutDirection() == Qt::LeftToRight) { + item.topLeft.rx() = categoryDrawer->leftMargin() + blockPos.x() + q->spacing(); + } else { + item.topLeft.rx() = viewportWidth() - currSize.width() + categoryDrawer->leftMargin() + categorySpacing; + } + item.topLeft.ry() = (prevRect.bottomRight().y() + 1) + q->spacing() - blockPos.y(); + } else { + if (q->layoutDirection() == Qt::LeftToRight) { + item.topLeft.rx() = (prevRect.bottomRight().x() + 1) + q->spacing(); + } else { + item.topLeft.rx() = (prevRect.bottomLeft().x() - 1) - q->spacing() - item.size.width() + categoryDrawer->leftMargin() + categorySpacing; + } + item.topLeft.ry() = prevRect.topLeft().y() - blockPos.y(); + } + } else { + if (q->layoutDirection() == Qt::LeftToRight) { + item.topLeft.rx() = blockPos.x() + categoryDrawer->leftMargin() + q->spacing(); + } else { + item.topLeft.rx() = viewportWidth() - currSize.width() + categoryDrawer->leftMargin() + categorySpacing; + } + item.topLeft.ry() = q->spacing(); + } + } + } + item.size = q->sizeHintForIndex(index); +} + +void QCategorizedView::Private::topToBottomVisualRect(const QModelIndex &index, Item &item, + const Block &block, const QPoint &blockPos) const +{ + const int firstIndexRow = block.firstIndex.row(); + + if (hasGrid()) { + const int relativeRow = index.row() - firstIndexRow; + item.topLeft.rx() = blockPos.x() + categoryDrawer->leftMargin(); + item.topLeft.ry() = relativeRow * q->gridSize().height(); + } else { + if (q->uniformItemSizes()) { + const int relativeRow = index.row() - firstIndexRow; + const QSize itemSize = q->sizeHintForIndex(index); + item.topLeft.rx() = blockPos.x() + categoryDrawer->leftMargin(); + item.topLeft.ry() = relativeRow * itemSize.height(); + } else { + if (index != block.firstIndex) { + QModelIndex prevIndex = proxyModel->index(index.row() - 1, q->modelColumn(), q->rootIndex()); + QRect prevRect = q->visualRect(prevIndex); + prevRect = mapFromViewport(prevRect); + item.topLeft.rx() = blockPos.x() + categoryDrawer->leftMargin() + q->spacing(); + item.topLeft.ry() = (prevRect.bottomRight().y() + 1) + q->spacing() - blockPos.y(); + } else { + item.topLeft.rx() = blockPos.x() + categoryDrawer->leftMargin() + q->spacing(); + item.topLeft.ry() = q->spacing(); + } + } + } + item.size = q->sizeHintForIndex(index); + item.size.setWidth(viewportWidth()); +} + +void QCategorizedView::Private::_k_slotCollapseOrExpandClicked(QModelIndex) +{ +} + +//END: Private part + +//BEGIN: Public part + +QCategorizedView::QCategorizedView(QWidget *parent) + : QListView(parent) + , d(new Private(this)) +{ +} + +QCategorizedView::~QCategorizedView() +{ + delete d; +} + +void QCategorizedView::setModel(QAbstractItemModel *model) +{ + if (d->proxyModel == model) { + return; + } + + d->blocks.clear(); + + if (d->proxyModel) { + disconnect(d->proxyModel, SIGNAL(layoutChanged()), this, SLOT(slotLayoutChanged())); + } + + d->proxyModel = dynamic_cast(model); + + if (d->proxyModel) { + connect(d->proxyModel, SIGNAL(layoutChanged()), this, SLOT(slotLayoutChanged())); + } + + QListView::setModel(model); + + // if the model already had information inserted, update our data structures to it + if (model->rowCount()) { + slotLayoutChanged(); + } +} + +void QCategorizedView::setGridSize(const QSize &size) +{ + setGridSizeOwn(size); +} + +void QCategorizedView::setGridSizeOwn(const QSize &size) +{ + d->regenerateAllElements(); + QListView::setGridSize(size); +} + +QRect QCategorizedView::visualRect(const QModelIndex &index) const +{ + if (!d->isCategorized()) { + return QListView::visualRect(index); + } + + if (!index.isValid()) { + return QRect(); + } + + const QString category = d->categoryForIndex(index); + + if (!d->blocks.contains(category)) { + return QRect(); + } + + Private::Block &block = d->blocks[category]; + const int firstIndexRow = block.firstIndex.row(); + + Q_ASSERT(block.firstIndex.isValid()); + + if (index.row() - firstIndexRow < 0 || index.row() - firstIndexRow >= block.items.count()) { + return QRect(); + } + + const QPoint blockPos = d->blockPosition(category); + + Private::Item &ritem = block.items[index.row() - firstIndexRow]; + + if (ritem.topLeft.isNull() || (block.quarantineStart.isValid() && + index.row() >= block.quarantineStart.row())) { + if (flow() == LeftToRight) { + d->leftToRightVisualRect(index, ritem, block, blockPos); + } else { + d->topToBottomVisualRect(index, ritem, block, blockPos); + } + + //BEGIN: update the quarantine start + const bool wasLastIndex = (index.row() == (block.firstIndex.row() + block.items.count() - 1)); + if (index.row() == block.quarantineStart.row()) { + if (wasLastIndex) { + block.quarantineStart = QModelIndex(); + } else { + const QModelIndex nextIndex = d->proxyModel->index(index.row() + 1, modelColumn(), rootIndex()); + block.quarantineStart = nextIndex; + } + } + //END: update the quarantine start + } + + // we get now the absolute position through the relative position of the parent block. do not + // save this on ritem, since this would override the item relative position in block terms. + Private::Item item(ritem); + item.topLeft.ry() += blockPos.y(); + + const QSize sizeHint = item.size; + + if (d->hasGrid()) { + const QSize sizeGrid = gridSize(); + const QSize resultingSize = sizeHint.boundedTo(sizeGrid); + QRect res(item.topLeft.x() + ((sizeGrid.width() - resultingSize.width()) / 2), + item.topLeft.y(), resultingSize.width(), resultingSize.height()); + if (block.collapsed) { + // we can still do binary search, while we "hide" items. We move those items in collapsed + // blocks to the left and set a 0 height. + res.setLeft(-resultingSize.width()); + res.setHeight(0); + } + return d->mapToViewport(res); + } + + QRect res(item.topLeft.x(), item.topLeft.y(), sizeHint.width(), sizeHint.height()); + if (block.collapsed) { + // we can still do binary search, while we "hide" items. We move those items in collapsed + // blocks to the left and set a 0 height. + res.setLeft(-sizeHint.width()); + res.setHeight(0); + } + return d->mapToViewport(res); +} + +QCategoryDrawer *QCategorizedView::categoryDrawer() const +{ + return d->categoryDrawer; +} + +void QCategorizedView::setCategoryDrawer(QCategoryDrawer *categoryDrawer) +{ + if (d->categoryDrawerV2) { + disconnect(d->categoryDrawerV2, SIGNAL(collapseOrExpandClicked(QModelIndex)), + this, SLOT(_k_slotCollapseOrExpandClicked(QModelIndex))); + } + + d->categoryDrawer = categoryDrawer; + d->categoryDrawerV2 = dynamic_cast(categoryDrawer); + d->categoryDrawerV3 = dynamic_cast(categoryDrawer); + + if (d->categoryDrawerV2) { + connect(d->categoryDrawerV2, SIGNAL(collapseOrExpandClicked(QModelIndex)), + this, SLOT(_k_slotCollapseOrExpandClicked(QModelIndex))); + } +} + +int QCategorizedView::categorySpacing() const +{ + return d->categorySpacing; +} + +void QCategorizedView::setCategorySpacing(int categorySpacing) +{ + if (d->categorySpacing == categorySpacing) { + return; + } + + d->categorySpacing = categorySpacing; + + for (QHash::Iterator it = d->blocks.begin(); it != d->blocks.end(); ++it) { + Private::Block &block = *it; + block.outOfQuarantine = false; + } +} + +bool QCategorizedView::alternatingBlockColors() const +{ + return d->alternatingBlockColors; +} + +void QCategorizedView::setAlternatingBlockColors(bool enable) +{ + d->alternatingBlockColors = enable; +} + +bool QCategorizedView::collapsibleBlocks() const +{ + return d->collapsibleBlocks; +} + +void QCategorizedView::setCollapsibleBlocks(bool enable) +{ + d->collapsibleBlocks = enable; +} + +QModelIndexList QCategorizedView::block(const QString &category) +{ + QModelIndexList res; + const Private::Block &block = d->blocks[category]; + if (block.height == -1) { + return res; + } + QModelIndex current = block.firstIndex; + const int first = current.row(); + for (int i = 1; i <= block.items.count(); ++i) { + if (current.isValid()) { + res << current; + } + current = d->proxyModel->index(first + i, modelColumn(), rootIndex()); + } + return res; +} + +QModelIndexList QCategorizedView::block(const QModelIndex &representative) +{ + return block(representative.data(QCategorizedSortFilterProxyModel::CategoryDisplayRole).toString()); +} + +QModelIndex QCategorizedView::indexAt(const QPoint &point) const +{ + if (!d->isCategorized()) { + return QListView::indexAt(point); + } + + const int rowCount = d->proxyModel->rowCount(); + if (!rowCount) { + return QModelIndex(); + } + + // Binary search that will try to spot if there is an index under point + int bottom = 0; + int top = rowCount - 1; + while (bottom <= top) { + const int middle = (bottom + top) / 2; + const QModelIndex index = d->proxyModel->index(middle, modelColumn(), rootIndex()); + QRect rect = visualRect(index); + const int verticalOff = verticalOffset(); + int horizontalOff = horizontalOffset(); + if (layoutDirection() == Qt::RightToLeft) { + horizontalOff *= -1; + } + rect.topLeft().ry() += verticalOff; + rect.topLeft().rx() += horizontalOff; + rect.bottomRight().ry() += verticalOff; + rect.bottomRight().rx() += horizontalOff; + if (rect.contains(point)) { + if (index.model()->flags(index) & Qt::ItemIsEnabled) { + return index; + } + return QModelIndex(); + } + bool directionCondition; + if (layoutDirection() == Qt::LeftToRight) { + directionCondition = point.x() > rect.bottomRight().x(); + } else { + directionCondition = point.x() < rect.bottomLeft().x(); + } + if (point.y() > rect.bottomRight().y() || + (point.y() > rect.topLeft().y() && point.y() < rect.bottomRight().y() && directionCondition)) { + bottom = middle + 1; + } else { + top = middle - 1; + } + } + return QModelIndex(); +} + +void QCategorizedView::reset() +{ + d->blocks.clear(); + QListView::reset(); +} + +void QCategorizedView::paintEvent(QPaintEvent *event) +{ + if (!d->isCategorized()) { + QListView::paintEvent(event); + return; + } + + const QPair intersecting = d->intersectingIndexesWithRect(viewport()->rect().intersected(event->rect())); + + QPainter p(viewport()); + p.save(); + + Q_ASSERT(selectionModel()->model() == d->proxyModel); + + //BEGIN: draw categories + QHash::ConstIterator it(d->blocks.constBegin()); + while (it != d->blocks.constEnd()) { + const Private::Block &block = *it; + const QModelIndex categoryIndex = d->proxyModel->index(block.firstIndex.row(), d->proxyModel->sortColumn(), rootIndex()); + QStyleOptionViewItemV4 option(viewOptions()); + option.features |= d->alternatingBlockColors && block.alternate ? QStyleOptionViewItemV4::Alternate + : QStyleOptionViewItemV4::None; + option.state |= !d->collapsibleBlocks || !block.collapsed ? QStyle::State_Open + : QStyle::State_None; + const int height = d->categoryDrawer->categoryHeight(categoryIndex, option); + QPoint pos = d->blockPosition(it.key()); + pos.ry() -= height; + option.rect.setTopLeft(pos); + option.rect.setWidth(d->viewportWidth() + d->categoryDrawer->leftMargin() + d->categoryDrawer->rightMargin()); + option.rect.setHeight(height + d->blockHeight(it.key())); + option.rect = d->mapToViewport(option.rect); + option.decorationPosition = QStyleOptionViewItem::Bottom; + if (!option.rect.intersects(viewport()->rect())) { + ++it; + continue; + } + d->categoryDrawer->drawCategory(categoryIndex, d->proxyModel->sortRole(), option, &p); + ++it; + } + //END: draw categories + + if (intersecting.first.isValid() && intersecting.second.isValid()) { + //BEGIN: draw items + int i = intersecting.first.row(); + int indexToCheckIfBlockCollapsed = i; + QModelIndex categoryIndex; + QString category; + Private::Block *block = 0; + while (i <= intersecting.second.row()) { + //BEGIN: first check if the block is collapsed. if so, we have to skip the item painting + if (i == indexToCheckIfBlockCollapsed) { + categoryIndex = d->proxyModel->index(i, d->proxyModel->sortColumn(), rootIndex()); + category = categoryIndex.data(QCategorizedSortFilterProxyModel::CategoryDisplayRole).toString(); + block = &d->blocks[category]; + indexToCheckIfBlockCollapsed = block->firstIndex.row() + block->items.count(); + if (block->collapsed) { + i = indexToCheckIfBlockCollapsed; + continue; + } + } + //END: first check if the block is collapsed. if so, we have to skip the item painting + + Q_ASSERT(block); + + const bool alternateItem = (i - block->firstIndex.row()) % 2; + + const QModelIndex index = d->proxyModel->index(i, modelColumn(), rootIndex()); + const Qt::ItemFlags flags = d->proxyModel->flags(index); + QStyleOptionViewItemV4 option(viewOptions()); + option.rect = visualRect(index); + option.widget = this; + option.features |= wordWrap() ? QStyleOptionViewItemV2::WrapText + : QStyleOptionViewItemV2::None; + option.features |= alternatingRowColors() && alternateItem ? QStyleOptionViewItemV4::Alternate + : QStyleOptionViewItemV4::None; + if (flags & Qt::ItemIsSelectable) { + option.state |= selectionModel()->isSelected(index) ? QStyle::State_Selected + : QStyle::State_None; + } else { + option.state &= ~QStyle::State_Selected; + } + option.state |= (index == currentIndex()) ? QStyle::State_HasFocus + : QStyle::State_None; + if (!(flags & Qt::ItemIsEnabled)) { + option.state &= ~QStyle::State_Enabled; + } else { + option.state |= (index == d->hoveredIndex) ? QStyle::State_MouseOver + : QStyle::State_None; + } + + itemDelegate(index)->paint(&p, option, index); + ++i; + } + //END: draw items + } + + //BEGIN: draw selection rect + if (isSelectionRectVisible() && d->rubberBandRect.isValid()) { + QStyleOptionRubberBand opt; + opt.initFrom(this); + opt.shape = QRubberBand::Rectangle; + opt.opaque = false; + opt.rect = d->mapToViewport(d->rubberBandRect).intersected(viewport()->rect().adjusted(-16, -16, 16, 16)); + p.save(); + style()->drawControl(QStyle::CE_RubberBand, &opt, &p); + p.restore(); + } + //END: draw selection rect + + p.restore(); +} + +void QCategorizedView::resizeEvent(QResizeEvent *event) +{ + d->regenerateAllElements(); + QListView::resizeEvent(event); +} + +void QCategorizedView::setSelection(const QRect &rect, + QItemSelectionModel::SelectionFlags flags) +{ + if (!d->isCategorized()) { + QListView::setSelection(rect, flags); + return; + } + + if (rect.topLeft() == rect.bottomRight()) { + const QModelIndex index = indexAt(rect.topLeft()); + selectionModel()->select(index, flags); + return; + } + + const QPair intersecting = d->intersectingIndexesWithRect(rect); + + QItemSelection selection; + + //TODO: think of a faster implementation + QModelIndex firstIndex; + QModelIndex lastIndex; + for (int i = intersecting.first.row(); i <= intersecting.second.row(); ++i) { + const QModelIndex index = d->proxyModel->index(i, modelColumn(), rootIndex()); + const bool visualRectIntersects = visualRect(index).intersects(rect); + if (firstIndex.isValid()) { + if (visualRectIntersects) { + lastIndex = index; + } else { + selection << QItemSelectionRange(firstIndex, lastIndex); + firstIndex = QModelIndex(); + } + } else if (visualRectIntersects) { + firstIndex = index; + lastIndex = index; + } + } + + if (firstIndex.isValid()) { + selection << QItemSelectionRange(firstIndex, lastIndex); + } + + selectionModel()->select(selection, flags); +} + +void QCategorizedView::mouseMoveEvent(QMouseEvent *event) +{ + QListView::mouseMoveEvent(event); + d->hoveredIndex = indexAt(event->pos()); + const SelectionMode itemViewSelectionMode = selectionMode(); + if (state() == DragSelectingState && isSelectionRectVisible() && itemViewSelectionMode != SingleSelection + && itemViewSelectionMode != NoSelection) { + QRect rect(d->pressedPosition, event->pos() + QPoint(horizontalOffset(), verticalOffset())); + rect = rect.normalized(); + update(rect.united(d->rubberBandRect)); + d->rubberBandRect = rect; + } + if (!d->categoryDrawerV2) { + return; + } + QHash::ConstIterator it(d->blocks.constBegin()); + while (it != d->blocks.constEnd()) { + const Private::Block &block = *it; + const QModelIndex categoryIndex = d->proxyModel->index(block.firstIndex.row(), d->proxyModel->sortColumn(), rootIndex()); + QStyleOptionViewItemV4 option(viewOptions()); + const int height = d->categoryDrawer->categoryHeight(categoryIndex, option); + QPoint pos = d->blockPosition(it.key()); + pos.ry() -= height; + option.rect.setTopLeft(pos); + option.rect.setWidth(d->viewportWidth() + d->categoryDrawer->leftMargin() + d->categoryDrawer->rightMargin()); + option.rect.setHeight(height + d->blockHeight(it.key())); + option.rect = d->mapToViewport(option.rect); + const QPoint mousePos = viewport()->mapFromGlobal(QCursor::pos()); + if (option.rect.contains(mousePos)) { + if (d->categoryDrawerV3 && d->hoveredBlock->height != -1 && *d->hoveredBlock != block) { + const QModelIndex categoryIndex = d->proxyModel->index(d->hoveredBlock->firstIndex.row(), d->proxyModel->sortColumn(), rootIndex()); + const QStyleOptionViewItemV4 option = d->blockRect(categoryIndex); + d->categoryDrawerV3->mouseLeft(categoryIndex, option.rect); + *d->hoveredBlock = block; + d->hoveredCategory = it.key(); + viewport()->update(option.rect); + } else if (d->hoveredBlock->height == -1) { + *d->hoveredBlock = block; + d->hoveredCategory = it.key(); + } else if (d->categoryDrawerV3) { + d->categoryDrawerV3->mouseMoved(categoryIndex, option.rect, event); + } else { + d->categoryDrawerV2->mouseButtonMoved(categoryIndex, event); + } + viewport()->update(option.rect); + return; + } + ++it; + } + if (d->categoryDrawerV3 && d->hoveredBlock->height != -1) { + const QModelIndex categoryIndex = d->proxyModel->index(d->hoveredBlock->firstIndex.row(), d->proxyModel->sortColumn(), rootIndex()); + const QStyleOptionViewItemV4 option = d->blockRect(categoryIndex); + d->categoryDrawerV3->mouseLeft(categoryIndex, option.rect); + *d->hoveredBlock = Private::Block(); + d->hoveredCategory = QString(); + viewport()->update(option.rect); + } +} + +void QCategorizedView::mousePressEvent(QMouseEvent *event) +{ + if (event->button() == Qt::LeftButton) { + d->pressedPosition = event->pos(); + d->pressedPosition.rx() += horizontalOffset(); + d->pressedPosition.ry() += verticalOffset(); + } + if (!d->categoryDrawerV2) { + QListView::mousePressEvent(event); + return; + } + QHash::ConstIterator it(d->blocks.constBegin()); + while (it != d->blocks.constEnd()) { + const Private::Block &block = *it; + const QModelIndex categoryIndex = d->proxyModel->index(block.firstIndex.row(), d->proxyModel->sortColumn(), rootIndex()); + const QStyleOptionViewItemV4 option = d->blockRect(categoryIndex); + const QPoint mousePos = viewport()->mapFromGlobal(QCursor::pos()); + if (option.rect.contains(mousePos)) { + if (d->categoryDrawerV3) { + d->categoryDrawerV3->mouseButtonPressed(categoryIndex, option.rect, event); + } else { + d->categoryDrawerV2->mouseButtonPressed(categoryIndex, event); + } + viewport()->update(option.rect); + if (!event->isAccepted()) { + QListView::mousePressEvent(event); + } + return; + } + ++it; + } + QListView::mousePressEvent(event); +} + +void QCategorizedView::mouseReleaseEvent(QMouseEvent *event) +{ + d->pressedPosition = QPoint(); + d->rubberBandRect = QRect(); + if (!d->categoryDrawerV2) { + QListView::mouseReleaseEvent(event); + return; + } + QHash::ConstIterator it(d->blocks.constBegin()); + while (it != d->blocks.constEnd()) { + const Private::Block &block = *it; + const QModelIndex categoryIndex = d->proxyModel->index(block.firstIndex.row(), d->proxyModel->sortColumn(), rootIndex()); + const QStyleOptionViewItemV4 option = d->blockRect(categoryIndex); + const QPoint mousePos = viewport()->mapFromGlobal(QCursor::pos()); + if (option.rect.contains(mousePos)) { + if (d->categoryDrawerV3) { + d->categoryDrawerV3->mouseButtonReleased(categoryIndex, option.rect, event); + } else { + d->categoryDrawerV2->mouseButtonReleased(categoryIndex, event); + } + viewport()->update(option.rect); + if (!event->isAccepted()) { + QListView::mouseReleaseEvent(event); + } + return; + } + ++it; + } + QListView::mouseReleaseEvent(event); +} + +void QCategorizedView::leaveEvent(QEvent *event) +{ + QListView::leaveEvent(event); + if (d->hoveredIndex.isValid()) { + viewport()->update(visualRect(d->hoveredIndex)); + d->hoveredIndex = QModelIndex(); + } + if (d->categoryDrawerV3 && d->hoveredBlock->height != -1) { + const QModelIndex categoryIndex = d->proxyModel->index(d->hoveredBlock->firstIndex.row(), d->proxyModel->sortColumn(), rootIndex()); + const QStyleOptionViewItemV4 option = d->blockRect(categoryIndex); + d->categoryDrawerV3->mouseLeft(categoryIndex, option.rect); + *d->hoveredBlock = Private::Block(); + d->hoveredCategory = QString(); + viewport()->update(option.rect); + } +} + +void QCategorizedView::startDrag(Qt::DropActions supportedActions) +{ + QListView::startDrag(supportedActions); +} + +void QCategorizedView::dragMoveEvent(QDragMoveEvent *event) +{ + QListView::dragMoveEvent(event); + d->hoveredIndex = indexAt(event->pos()); +} + +void QCategorizedView::dragEnterEvent(QDragEnterEvent *event) +{ + QListView::dragEnterEvent(event); +} + +void QCategorizedView::dragLeaveEvent(QDragLeaveEvent *event) +{ + QListView::dragLeaveEvent(event); +} + +void QCategorizedView::dropEvent(QDropEvent *event) +{ + QListView::dropEvent(event); +} + +//TODO: improve se we take into account collapsed blocks +//TODO: take into account when there is no grid and no uniformItemSizes +QModelIndex QCategorizedView::moveCursor(CursorAction cursorAction, + Qt::KeyboardModifiers modifiers) +{ + if (!d->isCategorized()) { + return QListView::moveCursor(cursorAction, modifiers); + } + + const QModelIndex current = currentIndex(); + const QRect currentRect = visualRect(current); + if (!current.isValid()) { + const int rowCount = d->proxyModel->rowCount(rootIndex()); + if (!rowCount) { + return QModelIndex(); + } + return d->proxyModel->index(0, modelColumn(), rootIndex()); + } + + switch (cursorAction) { + case MoveLeft: { + if (!current.row()) { + return QModelIndex(); + } + const QModelIndex previous = d->proxyModel->index(current.row() - 1, modelColumn(), rootIndex()); + const QRect previousRect = visualRect(previous); + if (previousRect.top() == currentRect.top()) { + return previous; + } + + return QModelIndex(); + } + case MoveRight: { + if (current.row() == d->proxyModel->rowCount() - 1) { + return QModelIndex(); + } + const QModelIndex next = d->proxyModel->index(current.row() + 1, modelColumn(), rootIndex()); + const QRect nextRect = visualRect(next); + if (nextRect.top() == currentRect.top()) { + return next; + } + + return QModelIndex(); + } + case MoveDown: { + if (d->hasGrid() || uniformItemSizes()) { + const QModelIndex current = currentIndex(); + const QSize itemSize = d->hasGrid() ? gridSize() + : sizeHintForIndex(current); + const Private::Block &block = d->blocks[d->categoryForIndex(current)]; + const int maxItemsPerRow = qMax(d->viewportWidth() / itemSize.width(), 1); + const bool canMove = current.row() + maxItemsPerRow < block.firstIndex.row() + + block.items.count(); + + if (canMove) { + return d->proxyModel->index(current.row() + maxItemsPerRow, modelColumn(), rootIndex()); + } + + const int currentRelativePos = (current.row() - block.firstIndex.row()) % maxItemsPerRow; + const QModelIndex nextIndex = d->proxyModel->index(block.firstIndex.row() + block.items.count(), modelColumn(), rootIndex()); + + if (!nextIndex.isValid()) { + return QModelIndex(); + } + + const Private::Block &nextBlock = d->blocks[d->categoryForIndex(nextIndex)]; + + if (nextBlock.items.count() <= currentRelativePos) { + return QModelIndex(); + } + + if (currentRelativePos < (block.items.count() % maxItemsPerRow)) { + return d->proxyModel->index(nextBlock.firstIndex.row() + currentRelativePos, modelColumn(), rootIndex()); + } + + return QModelIndex(); + } + } + case MoveUp: { + if (d->hasGrid() || uniformItemSizes()) { + const QModelIndex current = currentIndex(); + const QSize itemSize = d->hasGrid() ? gridSize() + : sizeHintForIndex(current); + const Private::Block &block = d->blocks[d->categoryForIndex(current)]; + const int maxItemsPerRow = qMax(d->viewportWidth() / itemSize.width(), 1); + const bool canMove = current.row() - maxItemsPerRow >= block.firstIndex.row(); + + if (canMove) { + return d->proxyModel->index(current.row() - maxItemsPerRow, modelColumn(), rootIndex()); + } + + const int currentRelativePos = (current.row() - block.firstIndex.row()) % maxItemsPerRow; + const QModelIndex prevIndex = d->proxyModel->index(block.firstIndex.row() - 1, modelColumn(), rootIndex()); + + if (!prevIndex.isValid()) { + return QModelIndex(); + } + + const Private::Block &prevBlock = d->blocks[d->categoryForIndex(prevIndex)]; + + if (prevBlock.items.count() <= currentRelativePos) { + return QModelIndex(); + } + + const int remainder = prevBlock.items.count() % maxItemsPerRow; + if (currentRelativePos < remainder) { + return d->proxyModel->index(prevBlock.firstIndex.row() + prevBlock.items.count() - remainder + currentRelativePos, modelColumn(), rootIndex()); + } + + return QModelIndex(); + } + } + default: + break; + } + + return QModelIndex(); +} + +void QCategorizedView::rowsAboutToBeRemoved(const QModelIndex &parent, + int start, + int end) +{ + if (!d->isCategorized()) { + QListView::rowsAboutToBeRemoved(parent, start, end); + return; + } + + *d->hoveredBlock = Private::Block(); + d->hoveredCategory = QString(); + + if (end - start + 1 == d->proxyModel->rowCount()) { + d->blocks.clear(); + QListView::rowsAboutToBeRemoved(parent, start, end); + return; + } + + // Removal feels a bit more complicated than insertion. Basically we can consider there are + // 3 different cases when going to remove items. (*) represents an item, Items between ([) and + // (]) are the ones which are marked for removal. + // + // - 1st case: + // ... * * * * * * [ * * * ... + // + // The items marked for removal are the last part of this category. No need to mark any item + // of this category as in quarantine, because no special offset will be pushed to items at + // the right because of any changes (since the removed items are those on the right most part + // of the category). + // + // - 2nd case: + // ... * * * * * * ] * * * ... + // + // The items marked for removal are the first part of this category. We have to mark as in + // quarantine all items in this category. Absolutely all. All items will have to be moved to + // the left (or moving up, because rows got a different offset). + // + // - 3rd case: + // ... * * [ * * * * ] * * ... + // + // The items marked for removal are in between of this category. We have to mark as in + // quarantine only those items that are at the right of the end of the removal interval, + // (starting on "]"). + // + // It hasn't been explicitly said, but when we remove, we have to mark all blocks that are + // located under the top most affected category as in quarantine (the block itself, as a whole), + // because such a change can force it to have a different offset (note that items themselves + // contain relative positions to the block, so marking the block as in quarantine is enough). + // + // Also note that removal implicitly means that we have to update correctly firstIndex of each + // block, and in general keep updated the internal information of elements. + + QStringList listOfCategoriesMarkedForRemoval; + + QString lastCategory; + int alreadyRemoved = 0; + for (int i = start; i <= end; ++i) { + const QModelIndex index = d->proxyModel->index(i, modelColumn(), parent); + + Q_ASSERT(index.isValid()); + + const QString category = d->categoryForIndex(index); + + if (lastCategory != category) { + lastCategory = category; + alreadyRemoved = 0; + } + + Private::Block &block = d->blocks[category]; + block.items.removeAt(i - block.firstIndex.row() - alreadyRemoved); + ++alreadyRemoved; + + if (!block.items.count()) { + listOfCategoriesMarkedForRemoval << category; + } + + block.height = -1; + + viewport()->update(); + } + + //BEGIN: update the items that are in quarantine in affected categories + { + const QModelIndex lastIndex = d->proxyModel->index(end, modelColumn(), parent); + const QString category = d->categoryForIndex(lastIndex); + Private::Block &block = d->blocks[category]; + if (block.items.count() && start <= block.firstIndex.row() && end >= block.firstIndex.row()) { + block.firstIndex = d->proxyModel->index(end + 1, modelColumn(), parent); + } + block.quarantineStart = block.firstIndex; + } + //END: update the items that are in quarantine in affected categories + + Q_FOREACH (const QString &category, listOfCategoriesMarkedForRemoval) { + d->blocks.remove(category); + } + + //BEGIN: mark as in quarantine those categories that are under the affected ones + { + //BEGIN: order for marking as alternate those blocks that are alternate + QList blockList = d->blocks.values(); + qSort(blockList.begin(), blockList.end(), Private::Block::lessThan); + QList firstIndexesRows; + foreach (const Private::Block &block, blockList) { + firstIndexesRows << block.firstIndex.row(); + } + //END: order for marking as alternate those blocks that are alternate + for (QHash::Iterator it = d->blocks.begin(); it != d->blocks.end(); ++it) { + Private::Block &block = *it; + if (block.firstIndex.row() > start) { + block.outOfQuarantine = false; + block.alternate = firstIndexesRows.indexOf(block.firstIndex.row()) % 2; + } else if (block.firstIndex.row() == start) { + block.alternate = firstIndexesRows.indexOf(block.firstIndex.row()) % 2; + } + } + } + //END: mark as in quarantine those categories that are under the affected ones + + QListView::rowsAboutToBeRemoved(parent, start, end); +} + +void QCategorizedView::updateGeometries() +{ + const int oldVerticalOffset = verticalOffset(); + const Qt::ScrollBarPolicy verticalP = verticalScrollBarPolicy(), horizontalP = horizontalScrollBarPolicy(); + + //BEGIN bugs 213068, 287847 ------------------------------------------------------------ + /* + * QListView::updateGeometries() has it's own opinion on whether the scrollbars should be visible (valid range) or not + * and triggers a (sometimes additionally timered) resize through ::layoutChildren() + * http://qt.gitorious.org/qt/qt/blobs/4.7/src/gui/itemviews/qlistview.cpp#line1499 + * (the comment above the main block isn't all accurate, layoutChldren is called regardless of the policy) + * + * As a result QListView and KCategorizedView occasionally started a race on the scrollbar visibility, effectively blocking the UI + * So we prevent QListView from having an own opinion on the scrollbar visibility by + * fixing it before calling the baseclass QListView::updateGeometries() + * + * Since the implicit show/hide by the followin range setting will cause further resizes if the policy is Qt::ScrollBarAsNeeded + * we keep it static until we're done, then restore the original value and ultimately change the scrollbar visibility ourself. + */ + if (d->isCategorized()) { // important! - otherwise we'd pollute the setting if the view is initially not categorized + setVerticalScrollBarPolicy((verticalP == Qt::ScrollBarAlwaysOn || verticalScrollBar()->isVisibleTo(this)) ? + Qt::ScrollBarAlwaysOn : Qt::ScrollBarAlwaysOff); + setHorizontalScrollBarPolicy((horizontalP == Qt::ScrollBarAlwaysOn || horizontalScrollBar()->isVisibleTo(this)) ? + Qt::ScrollBarAlwaysOn : Qt::ScrollBarAlwaysOff); + } + //END bugs 213068, 287847 -------------------------------------------------------------- + + QListView::updateGeometries(); + + if (!d->isCategorized()) { + return; + } + + const int rowCount = d->proxyModel->rowCount(); + if (!rowCount) { + verticalScrollBar()->setRange(0, 0); + // unconditional, see function end todo + horizontalScrollBar()->setRange(0, 0); + return; + } + + const QModelIndex lastIndex = d->proxyModel->index(rowCount - 1, modelColumn(), rootIndex()); + Q_ASSERT(lastIndex.isValid()); + QRect lastItemRect = visualRect(lastIndex); + + if (d->hasGrid()) { + lastItemRect.setSize(lastItemRect.size().expandedTo(gridSize())); + } else { + if (uniformItemSizes()) { + QSize itemSize = sizeHintForIndex(lastIndex); + itemSize.setHeight(itemSize.height() + spacing()); + lastItemRect.setSize(itemSize); + } else { + QSize itemSize = sizeHintForIndex(lastIndex); + const QString category = d->categoryForIndex(lastIndex); + itemSize.setHeight(d->highestElementInLastRow(d->blocks[category]) + spacing()); + lastItemRect.setSize(itemSize); + } + } + + const int bottomRange = lastItemRect.bottomRight().y() + verticalOffset() - viewport()->height(); + + if (verticalScrollMode() == ScrollPerItem) { + verticalScrollBar()->setSingleStep(lastItemRect.height()); + const int rowsPerPage = qMax(viewport()->height() / lastItemRect.height(), 1); + verticalScrollBar()->setPageStep(rowsPerPage * lastItemRect.height()); + } + + verticalScrollBar()->setRange(0, bottomRange); + verticalScrollBar()->setValue(oldVerticalOffset); + + //TODO: also consider working with the horizontal scroll bar. since at this level I am not still + // supporting "top to bottom" flow, there is no real problem. If I support that someday + // (think how to draw categories), we would have to take care of the horizontal scroll bar too. + // In theory, as QCategorizedView has been designed, there is no need of horizontal scroll bar. + horizontalScrollBar()->setRange(0, 0); + + //BEGIN bugs 213068, 287847 ------------------------------------------------------------ + // restoring values from above ... + setVerticalScrollBarPolicy(verticalP); + setHorizontalScrollBarPolicy(horizontalP); + // ... and correct the visibility + bool validRange = verticalScrollBar()->maximum() != verticalScrollBar()->minimum(); + if (verticalP == Qt::ScrollBarAsNeeded && (verticalScrollBar()->isVisibleTo(this) != validRange)) + verticalScrollBar()->setVisible(validRange); + validRange = horizontalScrollBar()->maximum() > horizontalScrollBar()->minimum(); + if (horizontalP == Qt::ScrollBarAsNeeded && (horizontalScrollBar()->isVisibleTo(this) != validRange)) + horizontalScrollBar()->setVisible(validRange); + //END bugs 213068, 287847 -------------------------------------------------------------- +} + +void QCategorizedView::currentChanged(const QModelIndex ¤t, + const QModelIndex &previous) +{ + QListView::currentChanged(current, previous); +} + +void QCategorizedView::dataChanged(const QModelIndex &topLeft, + const QModelIndex &bottomRight) +{ + QListView::dataChanged(topLeft, bottomRight); + if (!d->isCategorized()) { + return; + } + + *d->hoveredBlock = Private::Block(); + d->hoveredCategory = QString(); + + //BEGIN: since the model changed data, we need to reconsider item sizes + int i = topLeft.row(); + int indexToCheck = i; + QModelIndex categoryIndex; + QString category; + Private::Block *block; + while (i <= bottomRight.row()) { + const QModelIndex currIndex = d->proxyModel->index(i, modelColumn(), rootIndex()); + if (i == indexToCheck) { + categoryIndex = d->proxyModel->index(i, d->proxyModel->sortColumn(), rootIndex()); + category = categoryIndex.data(QCategorizedSortFilterProxyModel::CategoryDisplayRole).toString(); + block = &d->blocks[category]; + block->quarantineStart = currIndex; + indexToCheck = block->firstIndex.row() + block->items.count(); + } + visualRect(currIndex); + ++i; + } + //END: since the model changed data, we need to reconsider item sizes +} + +void QCategorizedView::rowsInserted(const QModelIndex &parent, + int start, + int end) +{ + QListView::rowsInserted(parent, start, end); + if (!d->isCategorized()) { + return; + } + + *d->hoveredBlock = Private::Block(); + d->hoveredCategory = QString(); + d->rowsInserted(parent, start, end); +} + +#ifndef KDE_NO_DEPRECATED +void QCategorizedView::rowsInsertedArtifficial(const QModelIndex &parent, + int start, + int end) +{ + Q_UNUSED(parent); + Q_UNUSED(start); + Q_UNUSED(end); +} +#endif + +#ifndef KDE_NO_DEPRECATED +void QCategorizedView::rowsRemoved(const QModelIndex &parent, + int start, + int end) +{ + Q_UNUSED(parent); + Q_UNUSED(start); + Q_UNUSED(end); +} +#endif + +void QCategorizedView::slotLayoutChanged() +{ + if (!d->isCategorized()) { + return; + } + + d->blocks.clear(); + *d->hoveredBlock = Private::Block(); + d->hoveredCategory = QString(); + if (d->proxyModel->rowCount()) { + d->rowsInserted(rootIndex(), 0, d->proxyModel->rowCount() - 1); + } +} + +//END: Public part + +#include "moc_qcategorizedview.cpp" diff --git a/src/qcategorizedview/qcategorizedview.h b/src/qcategorizedview/qcategorizedview.h new file mode 100644 index 0000000..d889402 --- /dev/null +++ b/src/qcategorizedview/qcategorizedview.h @@ -0,0 +1,349 @@ +/** + * (c)LGPL2+ + * This file is part of the KDE project + * Copyright (C) 2007, 2009 Rafael Fernández López + * + * 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 KCATEGORIZEDVIEW_H +#define KCATEGORIZEDVIEW_H + +#include + +//#include + +#define KDEUI_EXPORT +#define KDE_DEPRECATED + + +class QCategoryDrawer; +class QCategoryDrawerV2; + +/** + * @short Item view for listing items in a categorized fashion optionally + * + * QCategorizedView basically has the same functionality as QListView, only that it also lets you + * layout items in a way that they are categorized visually. + * + * For it to work you will need to set a QCategorizedSortFilterProxyModel and a QCategoryDrawer + * with methods setModel() and setCategoryDrawer() respectively. Also, the model will need to be + * flagged as categorized with QCategorizedSortFilterProxyModel::setCategorizedModel(true). + * + * The way it works (if categorization enabled): + * + * - When sorting, it does more things than QListView does. It will ask the model for the + * special role CategorySortRole (@see QCategorizedSortFilterProxyModel). This can return + * a QString or an int in order to tell the view the order of categories. In this sense, for + * instance, if we are sorting by name ascending, "A" would be before than "B". If we are + * sorting by size ascending, 512 bytes would be before 1024 bytes. This way categories are + * also sorted. + * + * - When the view has to paint, it will ask the model with the role CategoryDisplayRole + * (@see QCategorizedSortFilterProxyModel). It will for instance return "F" for "foo.pdf" if + * we are sorting by name ascending, or "Small" if a certain item has 100 bytes, for example. + * + * For drawing categories, QCategoryDrawer will be used. You can inherit this class to do your own + * drawing. + * + * @note All examples cited before talk about filesystems and such, but have present that this + * is a completely generic class, and it can be used for whatever your purpose is. For + * instance when talking about animals, you can separate them by "Mammal" and "Oviparous". In + * this very case, for example, the CategorySortRole and the CategoryDisplayRole could be the + * same ("Mammal" and "Oviparous"). + * + * @note There is a really performance boost if CategorySortRole returns an int instead of a QString. + * Have present that this role is asked (n * log n) times when sorting and compared. Comparing + * ints is always faster than comparing strings, whithout mattering how fast the string + * comparison is. Consider thinking of a way of returning ints instead of QStrings if your + * model can contain a high number of items. + * + * @warning Note that for really drawing items in blocks you will need some things to be done: + * - The model set to this view has to be (or inherit if you want to do special stuff + * in it) QCategorizedSortFilterProxyModel. + * - This model needs to be set setCategorizedModel to true. + * - Set a category drawer by calling setCategoryDrawer. + * + * @see QCategorizedSortFilterProxyModel, QCategoryDrawer + * + * @author Rafael Fernández López + */ +class KDEUI_EXPORT QCategorizedView + : public QListView +{ + Q_OBJECT + Q_PROPERTY(int categorySpacing READ categorySpacing WRITE setCategorySpacing) + Q_PROPERTY(bool alternatingBlockColors READ alternatingBlockColors WRITE setAlternatingBlockColors) + Q_PROPERTY(bool collapsibleBlocks READ collapsibleBlocks WRITE setCollapsibleBlocks) + +public: + QCategorizedView(QWidget *parent = 0); + + ~QCategorizedView(); + + /** + * Reimplemented from QAbstractItemView. + */ + virtual void setModel(QAbstractItemModel *model); + + /** + * Calls to setGridSizeOwn(). + */ + void setGridSize(const QSize &size); + + /** + * @warning note that setGridSize is not virtual in the base class (QListView), so if you are + * calling to this method, make sure you have a QCategorizedView pointer around. This + * means that something like: + * @code + * QListView *lv = new QCategorizedView(); + * lv->setGridSize(mySize); + * @endcode + * + * will not call to the expected setGridSize method. Instead do something like this: + * + * @code + * QListView *lv; + * ... + * QCategorizedView *cv = qobject_cast(lv); + * if (cv) { + * cv->setGridSizeOwn(mySize); + * } else { + * lv->setGridSize(mySize); + * } + * @endcode + * + * @note this method will call to QListView::setGridSize among other operations. + * + * @since 4.4 + */ + void setGridSizeOwn(const QSize &size); + + /** + * Reimplemented from QAbstractItemView. + */ + virtual QRect visualRect(const QModelIndex &index) const; + + /** + * Returns the current category drawer. + */ + QCategoryDrawer *categoryDrawer() const; + + /** + * The category drawer that will be used for drawing categories. + */ + void setCategoryDrawer(QCategoryDrawer *categoryDrawer); + + /** + * @return Category spacing. The spacing between categories. + * + * @since 4.4 + */ + int categorySpacing() const; + + /** + * Stablishes the category spacing. This is the spacing between categories. + * + * @since 4.4 + */ + void setCategorySpacing(int categorySpacing); + + /** + * @return Whether blocks should be drawn with alternating colors. + * + * @since 4.4 + */ + bool alternatingBlockColors() const; + + /** + * Sets whether blocks should be drawn with alternating colors. + * + * @since 4.4 + */ + void setAlternatingBlockColors(bool enable); + + /** + * @return Whether blocks can be collapsed or not. + * + * @since 4.4 + */ + bool collapsibleBlocks() const; + + /** + * Sets whether blocks can be collapsed or not. + * + * @since 4.4 + */ + void setCollapsibleBlocks(bool enable); + + /** + * @return Block of indexes that are into @p category. + * + * @since 4.5 + */ + QModelIndexList block(const QString &category); + + /** + * @return Block of indexes that are represented by @p representative. + * + * @since 4.5 + */ + QModelIndexList block(const QModelIndex &representative); + + /** + * Reimplemented from QAbstractItemView. + */ + virtual QModelIndex indexAt(const QPoint &point) const; + + /** + * Reimplemented from QAbstractItemView. + */ + virtual void reset(); + +protected: + /** + * Reimplemented from QWidget. + */ + virtual void paintEvent(QPaintEvent *event); + + /** + * Reimplemented from QWidget. + */ + virtual void resizeEvent(QResizeEvent *event); + + /** + * Reimplemented from QAbstractItemView. + */ + virtual void setSelection(const QRect &rect, + QItemSelectionModel::SelectionFlags flags); + + /** + * Reimplemented from QWidget. + */ + virtual void mouseMoveEvent(QMouseEvent *event); + + /** + * Reimplemented from QWidget. + */ + virtual void mousePressEvent(QMouseEvent *event); + + /** + * Reimplemented from QWidget. + */ + virtual void mouseReleaseEvent(QMouseEvent *event); + + /** + * Reimplemented from QWidget. + */ + virtual void leaveEvent(QEvent *event); + + /** + * Reimplemented from QAbstractItemView. + */ + virtual void startDrag(Qt::DropActions supportedActions); + + /** + * Reimplemented from QAbstractItemView. + */ + virtual void dragMoveEvent(QDragMoveEvent *event); + + /** + * Reimplemented from QAbstractItemView. + */ + virtual void dragEnterEvent(QDragEnterEvent *event); + + /** + * Reimplemented from QAbstractItemView. + */ + virtual void dragLeaveEvent(QDragLeaveEvent *event); + + /** + * Reimplemented from QAbstractItemView. + */ + virtual void dropEvent(QDropEvent *event); + + /** + * Reimplemented from QAbstractItemView. + */ + virtual QModelIndex moveCursor(CursorAction cursorAction, + Qt::KeyboardModifiers modifiers); + + /** + * Reimplemented from QAbstractItemView. + */ + virtual void rowsAboutToBeRemoved(const QModelIndex &parent, + int start, + int end); + + /** + * Reimplemented from QAbstractItemView. + */ + virtual void updateGeometries(); + + /** + * Reimplemented from QAbstractItemView. + */ + virtual void currentChanged(const QModelIndex ¤t, + const QModelIndex &previous); + + /** + * Reimplemented from QAbstractItemView. + */ + virtual void dataChanged(const QModelIndex &topLeft, + const QModelIndex &bottomRight); + + /** + * Reimplemented from QAbstractItemView. + */ + virtual void rowsInserted(const QModelIndex &parent, + int start, + int end); + +protected Q_SLOTS: + /** + * @internal + * @warning Deprecated since 4.4. + */ +#ifndef KDE_NO_DEPRECATED + virtual KDE_DEPRECATED void rowsInsertedArtifficial(const QModelIndex &parent, + int start, + int end); +#endif + + /** + * @internal + * @warning Deprecated since 4.4. + */ +#ifndef KDE_NO_DEPRECATED + virtual KDE_DEPRECATED void rowsRemoved(const QModelIndex &parent, + int start, + int end); +#endif + + /** + * @internal + * Reposition items as needed. + */ + virtual void slotLayoutChanged(); + +private: + class Private; + Private *const d; + + Q_PRIVATE_SLOT(d, void _k_slotCollapseOrExpandClicked(QModelIndex)) +}; + +#endif // KCATEGORIZEDVIEW_H diff --git a/src/qcategorizedview/qcategorizedview_p.h b/src/qcategorizedview/qcategorizedview_p.h new file mode 100644 index 0000000..8d32daa --- /dev/null +++ b/src/qcategorizedview/qcategorizedview_p.h @@ -0,0 +1,160 @@ +/** + * (c)LGPL2+ + * This file is part of the KDE project + * Copyright (C) 2007, 2009 Rafael Fernández López + * + * 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 KCATEGORIZEDVIEW_P_H +#define KCATEGORIZEDVIEW_P_H + +class QCategorizedSortFilterProxyModel; +class QCategoryDrawer; +class QCategoryDrawerV2; +class QCategoryDrawerV3; + +/** + * @internal + */ +class QCategorizedView::Private +{ +public: + struct Block; + struct Item; + + Private(QCategorizedView *q); + ~Private(); + + /** + * @return whether this view has all required elements to be categorized. + */ + bool isCategorized() const; + + /** + * @return the block rect for the representative @p representative. + */ + QStyleOptionViewItemV4 blockRect(const QModelIndex &representative); + + /** + * Returns the first and last element that intersects with rect. + * + * @note see that here we cannot take out items between first and last (as we could + * do with the rubberband). + * + * Complexity: O(log(n)) where n is model()->rowCount(). + */ + QPair intersectingIndexesWithRect(const QRect &rect) const; + + /** + * Returns the position of the block of @p category. + * + * Complexity: O(n) where n is the number of different categories when the block has been + * marked as in quarantine. O(1) the rest of the times (the vast majority). + */ + QPoint blockPosition(const QString &category); + + /** + * Returns the height of the block determined by @p category. + */ + int blockHeight(const QString &category); + + /** + * Returns the actual viewport width. + */ + int viewportWidth() const; + + /** + * Marks all elements as in quarantine. + * + * Complexity: O(n) where n is model()->rowCount(). + * + * @warning this is an expensive operation + */ + void regenerateAllElements(); + + /** + * Update internal information, and keep sync with the real information that the model contains. + */ + void rowsInserted(const QModelIndex &parent, int start, int end); + + /** + * Returns @p rect in viewport terms, taking in count horizontal and vertical offsets. + */ + QRect mapToViewport(const QRect &rect) const; + + /** + * Returns @p rect in absolute terms, converted from viewport position. + */ + QRect mapFromViewport(const QRect &rect) const; + + /** + * Returns the height of the highest element in last row. This is only applicable if there is + * no grid set and uniformItemSizes is false. + * + * @param block in which block are we searching. Necessary to stop the search if we hit the + * first item in this block. + */ + int highestElementInLastRow(const Block &block) const; + + /** + * Returns whether the view has a valid grid size. + */ + bool hasGrid() const; + + /** + * Returns the category for the given index. + */ + QString categoryForIndex(const QModelIndex &index) const; + + /** + * Updates the visual rect for item when flow is LeftToRight. + */ + void leftToRightVisualRect(const QModelIndex &index, Item &item, + const Block &block, const QPoint &blockPos) const; + + /** + * Updates the visual rect for item when flow is TopToBottom. + * @note we only support viewMode == ListMode in this case. + */ + void topToBottomVisualRect(const QModelIndex &index, Item &item, + const Block &block, const QPoint &blockPos) const; + + /** + * Called when expand or collapse has been clicked on the category drawer. + */ + void _k_slotCollapseOrExpandClicked(QModelIndex); + + QCategorizedView *q; + QCategorizedSortFilterProxyModel *proxyModel; + QCategoryDrawer *categoryDrawer; + QCategoryDrawerV2 *categoryDrawerV2; + QCategoryDrawerV3 *categoryDrawerV3; + int categorySpacing; + bool alternatingBlockColors; + bool collapsibleBlocks; + + Block *hoveredBlock; + QString hoveredCategory; + QModelIndex hoveredIndex; + + QPoint pressedPosition; + QRect rubberBandRect; + + QHash blocks; +}; + +#endif // KCATEGORIZEDVIEW_P_H diff --git a/src/qcategorizedview/qcategorydrawer.cpp b/src/qcategorizedview/qcategorydrawer.cpp new file mode 100644 index 0000000..1b23861 --- /dev/null +++ b/src/qcategorizedview/qcategorydrawer.cpp @@ -0,0 +1,285 @@ +/** + * (c)LGPL2+ + * This file is part of the KDE project + * Copyright (C) 2007, 2009 Rafael Fernández López + * + * 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 "qcategorydrawer.h" + +#include +#include +#include + +//#include +#include +#include + +#define HORIZONTAL_HINT 3 + +class QCategoryDrawer::Private +{ +public: + Private() + : leftMargin(0) + , rightMargin(0) + { + } + + ~Private() + { + } + + int leftMargin; + int rightMargin; +}; + +QCategoryDrawer::QCategoryDrawer() + : d(new Private) +{ + setLeftMargin(2); + setRightMargin(2); +} + +QCategoryDrawer::~QCategoryDrawer() +{ + delete d; +} + +void QCategoryDrawer::drawCategory(const QModelIndex &index, + int /*sortRole*/, + const QStyleOption &option, + QPainter *painter) const +{ + painter->setRenderHint(QPainter::Antialiasing); + + const QString category = index.model()->data(index, QCategorizedSortFilterProxyModel::CategoryDisplayRole).toString(); + const QRect optRect = option.rect; + QFont font(QApplication::font()); + font.setBold(true); + const QFontMetrics fontMetrics = QFontMetrics(font); + + QColor outlineColor = option.palette.text().color(); + outlineColor.setAlphaF(0.35); + + //BEGIN: top left corner + { + painter->save(); + painter->setPen(outlineColor); + const QPointF topLeft(optRect.topLeft()); + QRectF arc(topLeft, QSizeF(4, 4)); + arc.translate(0.5, 0.5); + painter->drawArc(arc, 1440, 1440); + painter->restore(); + } + //END: top left corner + + //BEGIN: left vertical line + { + QPoint start(optRect.topLeft()); + start.ry() += 3; + QPoint verticalGradBottom(optRect.topLeft()); + verticalGradBottom.ry() += fontMetrics.height() + 5; + QLinearGradient gradient(start, verticalGradBottom); + gradient.setColorAt(0, outlineColor); + gradient.setColorAt(1, Qt::transparent); + painter->fillRect(QRect(start, QSize(1, fontMetrics.height() + 5)), gradient); + } + //END: left vertical line + + //BEGIN: horizontal line + { + QPoint start(optRect.topLeft()); + start.rx() += 3; + QPoint horizontalGradTop(optRect.topLeft()); + horizontalGradTop.rx() += optRect.width() - 6; + painter->fillRect(QRect(start, QSize(optRect.width() - 6, 1)), outlineColor); + } + //END: horizontal line + + //BEGIN: top right corner + { + painter->save(); + painter->setPen(outlineColor); + QPointF topRight(optRect.topRight()); + topRight.rx() -= 4; + QRectF arc(topRight, QSizeF(4, 4)); + arc.translate(0.5, 0.5); + painter->drawArc(arc, 0, 1440); + painter->restore(); + } + //END: top right corner + + //BEGIN: right vertical line + { + QPoint start(optRect.topRight()); + start.ry() += 3; + QPoint verticalGradBottom(optRect.topRight()); + verticalGradBottom.ry() += fontMetrics.height() + 5; + QLinearGradient gradient(start, verticalGradBottom); + gradient.setColorAt(0, outlineColor); + gradient.setColorAt(1, Qt::transparent); + painter->fillRect(QRect(start, QSize(1, fontMetrics.height() + 5)), gradient); + } + //END: right vertical line + + //BEGIN: text + { + QRect textRect(option.rect); + textRect.setTop(textRect.top() + 7); + textRect.setLeft(textRect.left() + 7); + textRect.setHeight(fontMetrics.height()); + textRect.setRight(textRect.right() - 7); + + painter->save(); + painter->setFont(font); + QColor penColor(option.palette.text().color()); + penColor.setAlphaF(0.6); + painter->setPen(penColor); + painter->drawText(textRect, Qt::AlignLeft | Qt::AlignVCenter, category); + painter->restore(); + } + //END: text +} + +int QCategoryDrawer::categoryHeight(const QModelIndex &index, const QStyleOption &option) const +{ + Q_UNUSED(index); + Q_UNUSED(option) + + QFont font(QApplication::font()); + font.setBold(true); + QFontMetrics fontMetrics(font); + + const int height = fontMetrics.height() + 1 /* 1 pixel-width gradient */ + + 11 /* top and bottom separation */; + return height; +} + +int QCategoryDrawer::leftMargin() const +{ + return d->leftMargin; +} + +void QCategoryDrawer::setLeftMargin(int leftMargin) +{ + d->leftMargin = leftMargin; +} + +int QCategoryDrawer::rightMargin() const +{ + return d->rightMargin; +} + +void QCategoryDrawer::setRightMargin(int rightMargin) +{ + d->rightMargin = rightMargin; +} + +QCategoryDrawer &QCategoryDrawer::operator=(const QCategoryDrawer &cd) +{ + d->leftMargin = cd.d->leftMargin; + d->rightMargin = cd.d->rightMargin; + return *this; +} + +QCategoryDrawerV2::QCategoryDrawerV2(QObject *parent) + : QObject(parent) + , QCategoryDrawer() +{ +} + +QCategoryDrawerV2::~QCategoryDrawerV2() +{ +} + +void QCategoryDrawerV2::mouseButtonPressed(const QModelIndex&, QMouseEvent *event) +{ + event->ignore(); +} + +void QCategoryDrawerV2::mouseButtonReleased(const QModelIndex&, QMouseEvent *event) +{ + event->ignore(); +} + +void QCategoryDrawerV2::mouseButtonMoved(const QModelIndex&, QMouseEvent *event) +{ + event->ignore(); +} + +void QCategoryDrawerV2::mouseButtonDoubleClicked(const QModelIndex&, QMouseEvent *event) +{ + event->ignore(); +} + +class QCategoryDrawerV3::Private +{ +public: + Private(QCategorizedView *view) + : view(view) + { + } + + ~Private() + { + } + + QCategorizedView *view; +}; + +QCategoryDrawerV3::QCategoryDrawerV3(QCategorizedView *view) + : QCategoryDrawerV2(view) + , d(new Private(view)) +{ +} + +QCategoryDrawerV3::~QCategoryDrawerV3() +{ + delete d; +} + +QCategorizedView *QCategoryDrawerV3::view() const +{ + return d->view; +} + +void QCategoryDrawerV3::mouseButtonPressed(const QModelIndex&, const QRect&, QMouseEvent *event) +{ + event->ignore(); +} + +void QCategoryDrawerV3::mouseButtonReleased(const QModelIndex&, const QRect&, QMouseEvent *event) +{ + event->ignore(); +} + +void QCategoryDrawerV3::mouseMoved(const QModelIndex&, const QRect&, QMouseEvent *event) +{ + event->ignore(); +} + +void QCategoryDrawerV3::mouseButtonDoubleClicked(const QModelIndex&, const QRect&, QMouseEvent *event) +{ + event->ignore(); +} + +void QCategoryDrawerV3::mouseLeft(const QModelIndex&, const QRect&) +{ +} + +#include "moc_qcategorydrawer.cpp" diff --git a/src/qcategorizedview/qcategorydrawer.h b/src/qcategorizedview/qcategorydrawer.h new file mode 100644 index 0000000..4c5af0d --- /dev/null +++ b/src/qcategorizedview/qcategorydrawer.h @@ -0,0 +1,234 @@ +/** + * (c)LGPL2+ + * This file is part of the KDE project + * Copyright (C) 2007, 2009 Rafael Fernández López + * + * 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 KCATEGORYDRAWER_H +#define KCATEGORYDRAWER_H + +//#include + +#include +#include + +#define KDEUI_EXPORT +#define KDE_DEPRECATED + +class QPainter; +class QModelIndex; +class QStyleOption; + +class QCategorizedView; + +/** + * @deprecated + * + * The category drawing is performed by this class. It also gives information about the category + * height and margins. + * + * @warning Please use QCategoryDrawerV3 instead + */ +class KDEUI_EXPORT QCategoryDrawer +{ +public: + KDE_DEPRECATED QCategoryDrawer(); + + virtual ~QCategoryDrawer(); + + /** + * This method purpose is to draw a category represented by the given + * @param index with the given @param sortRole sorting role + * + * @note This method will be called one time per category, always with the + * first element in that category + */ + virtual void drawCategory(const QModelIndex &index, + int sortRole, + const QStyleOption &option, + QPainter *painter) const; + + /** + * @return The category height for the category representated by index @p index with + * style options @p option. + */ + virtual int categoryHeight(const QModelIndex &index, const QStyleOption &option) const; + + //TODO KDE5: make virtual as leftMargin + /** + * @note 0 by default + * + * @since 4.4 + */ + int leftMargin() const; + + /** + * @note call to this method on the QCategoryDrawer constructor to set the left margin + * + * @since 4.4 + */ + void setLeftMargin(int leftMargin); + + //TODO KDE5: make virtual as rightMargin + /** + * @note 0 by default + * + * @since 4.4 + */ + int rightMargin() const; + + /** + * @note call to this method on the QCategoryDrawer constructor to set the right margin + * + * @since 4.4 + */ + void setRightMargin(int rightMargin); + + QCategoryDrawer &operator=(const QCategoryDrawer &cd); + +private: + class Private; + Private *const d; +}; + + +/** + * @deprecated + * + * @since 4.4 + * + * @warning Please use QCategoryDrawerV3 instead + */ +class KDEUI_EXPORT QCategoryDrawerV2 + : public QObject + , public QCategoryDrawer +{ + Q_OBJECT + +public: + KDE_DEPRECATED QCategoryDrawerV2(QObject *parent = 0); + virtual ~QCategoryDrawerV2(); + + KDE_DEPRECATED virtual void mouseButtonPressed(const QModelIndex &index, QMouseEvent *event); + + KDE_DEPRECATED virtual void mouseButtonReleased(const QModelIndex &index, QMouseEvent *event); + + KDE_DEPRECATED virtual void mouseButtonMoved(const QModelIndex &index, QMouseEvent *event); + + KDE_DEPRECATED virtual void mouseButtonDoubleClicked(const QModelIndex &index, QMouseEvent *event); + +Q_SIGNALS: + /** + * This signal becomes emitted when collapse or expand has been clicked. + */ + void collapseOrExpandClicked(const QModelIndex &index); + + /** + * Emit this signal on your subclass implementation to notify that something happened. Usually + * this will be triggered when you have received an event, and its position matched some "hot spot". + * + * You give this action the integer you want, and having connected this signal to your code, + * the connected slot can perform the needed changes (view, model, selection model, delegate...) + */ + void actionRequested(int action, const QModelIndex &index); +}; + +/** + * @since 4.5 + */ +class KDEUI_EXPORT QCategoryDrawerV3 + : public QCategoryDrawerV2 +{ + friend class QCategorizedView; + +public: + QCategoryDrawerV3(QCategorizedView *view); + virtual ~QCategoryDrawerV3(); + + /** + * @return The view this category drawer is associated with. + */ + QCategorizedView *view() const; + + using QCategoryDrawerV2::mouseButtonPressed; + using QCategoryDrawerV2::mouseButtonReleased; + using QCategoryDrawerV2::mouseButtonDoubleClicked; + +protected: + /** + * Method called when the mouse button has been pressed. + * + * @param index The representative index of the block of items. + * @param blockRect The rect occupied by the block of items. + * @param event The mouse event. + * + * @warning You explicitly have to determine whether the event has been accepted or not. You + * have to call event->accept() or event->ignore() at all possible case branches in + * your code. + */ + virtual void mouseButtonPressed(const QModelIndex &index, const QRect &blockRect, QMouseEvent *event); + + /** + * Method called when the mouse button has been released. + * + * @param index The representative index of the block of items. + * @param blockRect The rect occupied by the block of items. + * @param event The mouse event. + * + * @warning You explicitly have to determine whether the event has been accepted or not. You + * have to call event->accept() or event->ignore() at all possible case branches in + * your code. + */ + virtual void mouseButtonReleased(const QModelIndex &index, const QRect &blockRect, QMouseEvent *event); + + /** + * Method called when the mouse has been moved. + * + * @param index The representative index of the block of items. + * @param blockRect The rect occupied by the block of items. + * @param event The mouse event. + */ + virtual void mouseMoved(const QModelIndex &index, const QRect &blockRect, QMouseEvent *event); + + /** + * Method called when the mouse button has been double clicked. + * + * @param index The representative index of the block of items. + * @param blockRect The rect occupied by the block of items. + * @param event The mouse event. + * + * @warning You explicitly have to determine whether the event has been accepted or not. You + * have to call event->accept() or event->ignore() at all possible case branches in + * your code. + */ + virtual void mouseButtonDoubleClicked(const QModelIndex &index, const QRect &blockRect, QMouseEvent *event); + + /** + * Method called when the mouse button has left this block. + * + * @param index The representative index of the block of items. + * @param blockRect The rect occupied by the block of items. + */ + virtual void mouseLeft(const QModelIndex &index, const QRect &blockRect); + +private: + class Private; + Private *const d; +}; + +#endif // KCATEGORYDRAWER_H diff --git a/src/translations/lxqt-config.ts b/src/translations/lxqt-config.ts new file mode 100644 index 0000000..cf20fd0 --- /dev/null +++ b/src/translations/lxqt-config.ts @@ -0,0 +1,12 @@ + + + + + MainWindow + + + Configuration Center + + + + diff --git a/src/translations/lxqt-config_ar.desktop b/src/translations/lxqt-config_ar.desktop new file mode 100644 index 0000000..729977f --- /dev/null +++ b/src/translations/lxqt-config_ar.desktop @@ -0,0 +1,4 @@ +# Translations +Comment[ar]=تهيئة أقسام ريزر كيوت +GenericName[ar]=تهيئة ريزر +Name[ar]=مركز تهيئة ريزر diff --git a/src/translations/lxqt-config_cs.desktop b/src/translations/lxqt-config_cs.desktop new file mode 100644 index 0000000..b07dceb --- /dev/null +++ b/src/translations/lxqt-config_cs.desktop @@ -0,0 +1,4 @@ +# Translations +Comment[cs]=Nastavit moduly LXQt +GenericName[cs]=Nastavení LXQtu +Name[cs]=Nastavení LXQtu diff --git a/src/translations/lxqt-config_cs.ts b/src/translations/lxqt-config_cs.ts new file mode 100644 index 0000000..77eee07 --- /dev/null +++ b/src/translations/lxqt-config_cs.ts @@ -0,0 +1,12 @@ + + + + + MainWindow + + + Configuration Center + Nastavení + + + diff --git a/src/translations/lxqt-config_cs_CZ.desktop b/src/translations/lxqt-config_cs_CZ.desktop new file mode 100644 index 0000000..e0281d5 --- /dev/null +++ b/src/translations/lxqt-config_cs_CZ.desktop @@ -0,0 +1,4 @@ +# Translations +Comment[cs_CZ]=Nastavit moduly LXQt +GenericName[cs_CZ]=Nastavení LXQtu +Name[cs_CZ]=Nastavení LXQtu diff --git a/src/translations/lxqt-config_cs_CZ.ts b/src/translations/lxqt-config_cs_CZ.ts new file mode 100644 index 0000000..f078a65 --- /dev/null +++ b/src/translations/lxqt-config_cs_CZ.ts @@ -0,0 +1,12 @@ + + + + + MainWindow + + + Configuration Center + Nastavení + + + diff --git a/src/translations/lxqt-config_da.desktop b/src/translations/lxqt-config_da.desktop new file mode 100644 index 0000000..fd5493c --- /dev/null +++ b/src/translations/lxqt-config_da.desktop @@ -0,0 +1,4 @@ +# Translations +Comment[da]=Indstil LXQt moduler +GenericName[da]=LXQt Indstillingscenter +Name[da]=LXQt Indstillingscenter diff --git a/src/translations/lxqt-config_da_DK.desktop b/src/translations/lxqt-config_da_DK.desktop new file mode 100644 index 0000000..ddb1d44 --- /dev/null +++ b/src/translations/lxqt-config_da_DK.desktop @@ -0,0 +1,4 @@ +# Translations +Comment[da_DK]=Indstil LXQt moduler +GenericName[da_DK]=LXQt Indstillinger +Name[da_DK]=LXQt Konfigurationsstyring diff --git a/src/translations/lxqt-config_da_DK.ts b/src/translations/lxqt-config_da_DK.ts new file mode 100644 index 0000000..0c63869 --- /dev/null +++ b/src/translations/lxqt-config_da_DK.ts @@ -0,0 +1,12 @@ + + + + + MainWindow + + + Configuration Center + Konfigurationscenter + + + diff --git a/src/translations/lxqt-config_de.desktop b/src/translations/lxqt-config_de.desktop new file mode 100644 index 0000000..38bd7b9 --- /dev/null +++ b/src/translations/lxqt-config_de.desktop @@ -0,0 +1,4 @@ +# Translations +Comment[de]=Konfiguriere LXQt Module +GenericName[de]=LXQt Konfiguration +Name[de]=LXQt Konfigurations Center diff --git a/src/translations/lxqt-config_de.ts b/src/translations/lxqt-config_de.ts new file mode 100644 index 0000000..52e771b --- /dev/null +++ b/src/translations/lxqt-config_de.ts @@ -0,0 +1,12 @@ + + + + + MainWindow + + + Configuration Center + Konfigurationszentrum + + + diff --git a/src/translations/lxqt-config_el_GR.desktop b/src/translations/lxqt-config_el_GR.desktop new file mode 100644 index 0000000..d44cfb6 --- /dev/null +++ b/src/translations/lxqt-config_el_GR.desktop @@ -0,0 +1,4 @@ +# Translations +Comment[el_GR]=Διαμόρφωση αρθρωμάτων LXQt +GenericName[el_GR]=Διαμόρφωση LXQt +Name[el_GR]=Κέντρο διαμόρφωσης LXQt diff --git a/src/translations/lxqt-config_el_GR.ts b/src/translations/lxqt-config_el_GR.ts new file mode 100644 index 0000000..a6ebb62 --- /dev/null +++ b/src/translations/lxqt-config_el_GR.ts @@ -0,0 +1,12 @@ + + + + + MainWindow + + + Configuration Center + Κέντρο διαμόρφωσης + + + diff --git a/src/translations/lxqt-config_eo.desktop b/src/translations/lxqt-config_eo.desktop new file mode 100644 index 0000000..0094fc6 --- /dev/null +++ b/src/translations/lxqt-config_eo.desktop @@ -0,0 +1,4 @@ +# Translations +Comment[eo]=Agordi modulojn de LXQt +GenericName[eo]=Agordilo de LXQt +Name[eo]=Agordcentro de LXQt diff --git a/src/translations/lxqt-config_es.desktop b/src/translations/lxqt-config_es.desktop new file mode 100644 index 0000000..9dc12ca --- /dev/null +++ b/src/translations/lxqt-config_es.desktop @@ -0,0 +1,4 @@ +# Translations +Comment[es]=Configura módulos de LXQt +GenericName[es]=Configuración LXQt +Name[es]=Centro de Configuración LXQt diff --git a/src/translations/lxqt-config_es.ts b/src/translations/lxqt-config_es.ts new file mode 100644 index 0000000..fb092d1 --- /dev/null +++ b/src/translations/lxqt-config_es.ts @@ -0,0 +1,12 @@ + + + + + MainWindow + + + Configuration Center + Centro de configuración + + + diff --git a/src/translations/lxqt-config_es_VE.desktop b/src/translations/lxqt-config_es_VE.desktop new file mode 100644 index 0000000..4794885 --- /dev/null +++ b/src/translations/lxqt-config_es_VE.desktop @@ -0,0 +1,4 @@ +# Translations +Comment[es_VE]=Configurar modulos de LXQt +GenericName[es_VE]=Configuracion de LXQt +Name[es_VE]=Centro de Configuracion LXQt diff --git a/src/translations/lxqt-config_es_VE.ts b/src/translations/lxqt-config_es_VE.ts new file mode 100644 index 0000000..1b2ffee --- /dev/null +++ b/src/translations/lxqt-config_es_VE.ts @@ -0,0 +1,12 @@ + + + + + MainWindow + + + Configuration Center + Centro de preferencias + + + diff --git a/src/translations/lxqt-config_eu.desktop b/src/translations/lxqt-config_eu.desktop new file mode 100644 index 0000000..6c54ad9 --- /dev/null +++ b/src/translations/lxqt-config_eu.desktop @@ -0,0 +1,4 @@ +# Translations +Comment[eu]=Konfiguratu LXQt moduluak +GenericName[eu]=LXQt konfigurazioa +Name[eu]=LXQt konfigurazio-zentroa diff --git a/src/translations/lxqt-config_eu.ts b/src/translations/lxqt-config_eu.ts new file mode 100644 index 0000000..806a7f4 --- /dev/null +++ b/src/translations/lxqt-config_eu.ts @@ -0,0 +1,12 @@ + + + + + MainWindow + + + Configuration Center + Konfigurazio-zentroa + + + diff --git a/src/translations/lxqt-config_fi.desktop b/src/translations/lxqt-config_fi.desktop new file mode 100644 index 0000000..28667fe --- /dev/null +++ b/src/translations/lxqt-config_fi.desktop @@ -0,0 +1,4 @@ +# Translations +Comment[fi]=Hallitse LXQtin moduuleita +GenericName[fi]=LXQt-hallinta +Name[fi]=LXQtin hallintakeskus diff --git a/src/translations/lxqt-config_fi.ts b/src/translations/lxqt-config_fi.ts new file mode 100644 index 0000000..7aef321 --- /dev/null +++ b/src/translations/lxqt-config_fi.ts @@ -0,0 +1,12 @@ + + + + + MainWindow + + + Configuration Center + Asetuskeskus + + + diff --git a/src/translations/lxqt-config_fr_FR.desktop b/src/translations/lxqt-config_fr_FR.desktop new file mode 100644 index 0000000..81b31c2 --- /dev/null +++ b/src/translations/lxqt-config_fr_FR.desktop @@ -0,0 +1,4 @@ +# Translations +Comment[fr_FR]=Configurer les modules de LXQt +GenericName[fr_FR]=Configuration de LXQt +Name[fr_FR]=Centre de configuration de LXQt diff --git a/src/translations/lxqt-config_hu.desktop b/src/translations/lxqt-config_hu.desktop new file mode 100644 index 0000000..504f0df --- /dev/null +++ b/src/translations/lxqt-config_hu.desktop @@ -0,0 +1,4 @@ +# Translations +Comment[hu]=A LXQt modulok beállítása +GenericName[hu]=LXQt beállítóközpont +Name[hu]=LXQt beállítóközpont diff --git a/src/translations/lxqt-config_ia.desktop b/src/translations/lxqt-config_ia.desktop new file mode 100644 index 0000000..26b0d99 --- /dev/null +++ b/src/translations/lxqt-config_ia.desktop @@ -0,0 +1 @@ +# Translations diff --git a/src/translations/lxqt-config_id_ID.desktop b/src/translations/lxqt-config_id_ID.desktop new file mode 100644 index 0000000..52995bd --- /dev/null +++ b/src/translations/lxqt-config_id_ID.desktop @@ -0,0 +1,4 @@ +# Translations +Comment[id_ID]=Konfigurasi modul LXQt +GenericName[id_ID]=Konfigurasi LXQt +Name[id_ID]=Pusat Konfigurasi LXQt diff --git a/src/translations/lxqt-config_it.desktop b/src/translations/lxqt-config_it.desktop new file mode 100644 index 0000000..40166fe --- /dev/null +++ b/src/translations/lxqt-config_it.desktop @@ -0,0 +1,4 @@ +# Translations +Comment[it]=Configura moduli di LXQt +GenericName[it]=Configura LXQt +Name[it]=Centro di Configurazione LXQt diff --git a/src/translations/lxqt-config_it_IT.desktop b/src/translations/lxqt-config_it_IT.desktop new file mode 100644 index 0000000..054e9c5 --- /dev/null +++ b/src/translations/lxqt-config_it_IT.desktop @@ -0,0 +1,4 @@ +# Translations +Comment[it_IT]=Configura i moduli di LXQt +GenericName[it_IT]=Configurazione di LXQt +Name[it_IT]=Centro di configurazione di LXQt diff --git a/src/translations/lxqt-config_it_IT.ts b/src/translations/lxqt-config_it_IT.ts new file mode 100644 index 0000000..37bb554 --- /dev/null +++ b/src/translations/lxqt-config_it_IT.ts @@ -0,0 +1,12 @@ + + + + + MainWindow + + + Configuration Center + Centro di configurazione + + + diff --git a/src/translations/lxqt-config_ja.desktop b/src/translations/lxqt-config_ja.desktop new file mode 100644 index 0000000..d12f4d3 --- /dev/null +++ b/src/translations/lxqt-config_ja.desktop @@ -0,0 +1,4 @@ +# Translations +Comment[ja]=LXQtモジュールを設定 +GenericName[ja]=LXQtの設定 +Name[ja]=LXQtコンフィグレーションセンター diff --git a/src/translations/lxqt-config_ja.ts b/src/translations/lxqt-config_ja.ts new file mode 100644 index 0000000..8ecd3cb --- /dev/null +++ b/src/translations/lxqt-config_ja.ts @@ -0,0 +1,12 @@ + + + + + MainWindow + + + Configuration Center + コンフィグレーションセンター + + + diff --git a/src/translations/lxqt-config_ko.desktop b/src/translations/lxqt-config_ko.desktop new file mode 100644 index 0000000..26b0d99 --- /dev/null +++ b/src/translations/lxqt-config_ko.desktop @@ -0,0 +1 @@ +# Translations diff --git a/src/translations/lxqt-config_lt.desktop b/src/translations/lxqt-config_lt.desktop new file mode 100644 index 0000000..83453ac --- /dev/null +++ b/src/translations/lxqt-config_lt.desktop @@ -0,0 +1,4 @@ +# Translations +Comment[lt]=Konfigūruoti LXQt modulius +GenericName[lt]=LXQt konfigūracija +Name[lt]=LXQt konfigūravimo centras diff --git a/src/translations/lxqt-config_nl.desktop b/src/translations/lxqt-config_nl.desktop new file mode 100644 index 0000000..50514bd --- /dev/null +++ b/src/translations/lxqt-config_nl.desktop @@ -0,0 +1,4 @@ +# Translations +Comment[nl]=Configureer LXQt modules +GenericName[nl]=LXQt Configuratie +Name[nl]=LXQt Configuratie Centrum diff --git a/src/translations/lxqt-config_pl.desktop b/src/translations/lxqt-config_pl.desktop new file mode 100644 index 0000000..b120eaf --- /dev/null +++ b/src/translations/lxqt-config_pl.desktop @@ -0,0 +1,4 @@ +# Translations +Comment[pl]=Wszystkie ustawienia LXQt +GenericName[pl]=Panel sterowania LXQt +Name[pl]=Panel sterowania LXQt diff --git a/src/translations/lxqt-config_pl.ts b/src/translations/lxqt-config_pl.ts new file mode 100644 index 0000000..3220cd4 --- /dev/null +++ b/src/translations/lxqt-config_pl.ts @@ -0,0 +1,12 @@ + + + + + MainWindow + + + Configuration Center + Centrum konfiguracji + + + diff --git a/src/translations/lxqt-config_pl_PL.desktop b/src/translations/lxqt-config_pl_PL.desktop new file mode 100644 index 0000000..c06e74a --- /dev/null +++ b/src/translations/lxqt-config_pl_PL.desktop @@ -0,0 +1,4 @@ +# Translations +Comment[pl_PL]=Konfiguruj moduły LXQt +GenericName[pl_PL]=Konfiguracja LXQt +Name[pl_PL]=Panel sterowania LXQt diff --git a/src/translations/lxqt-config_pl_PL.ts b/src/translations/lxqt-config_pl_PL.ts new file mode 100644 index 0000000..35d7ed6 --- /dev/null +++ b/src/translations/lxqt-config_pl_PL.ts @@ -0,0 +1,12 @@ + + + + + MainWindow + + + Configuration Center + Panel sterowania + + + diff --git a/src/translations/lxqt-config_pt.desktop b/src/translations/lxqt-config_pt.desktop new file mode 100644 index 0000000..921f3eb --- /dev/null +++ b/src/translations/lxqt-config_pt.desktop @@ -0,0 +1,4 @@ +# Translations +Comment[pt]=Configurar módulos do LXQt +GenericName[pt]=Configuração do LXQt +Name[pt]=Centro de configuração LXQt diff --git a/src/translations/lxqt-config_pt.ts b/src/translations/lxqt-config_pt.ts new file mode 100644 index 0000000..2078832 --- /dev/null +++ b/src/translations/lxqt-config_pt.ts @@ -0,0 +1,12 @@ + + + + + MainWindow + + + Configuration Center + Centro de configurações + + + diff --git a/src/translations/lxqt-config_pt_BR.desktop b/src/translations/lxqt-config_pt_BR.desktop new file mode 100644 index 0000000..3efbf18 --- /dev/null +++ b/src/translations/lxqt-config_pt_BR.desktop @@ -0,0 +1,4 @@ +# Translations +Comment[pt_BR]=Configurar módulos Qt +GenericName[pt_BR]=Configuração +Name[pt_BR]=Centro De Configuração diff --git a/src/translations/lxqt-config_pt_BR.ts b/src/translations/lxqt-config_pt_BR.ts new file mode 100644 index 0000000..d9c6bc5 --- /dev/null +++ b/src/translations/lxqt-config_pt_BR.ts @@ -0,0 +1,12 @@ + + + + + MainWindow + + + Configuration Center + Centro De Configuração + + + diff --git a/src/translations/lxqt-config_ro_RO.desktop b/src/translations/lxqt-config_ro_RO.desktop new file mode 100644 index 0000000..1b723ed --- /dev/null +++ b/src/translations/lxqt-config_ro_RO.desktop @@ -0,0 +1,4 @@ +# Translations +Comment[ro_RO]=Configurează modulele LXQt +GenericName[ro_RO]=Configurație LXQt +Name[ro_RO]=Centru de configurare LXQt diff --git a/src/translations/lxqt-config_ro_RO.ts b/src/translations/lxqt-config_ro_RO.ts new file mode 100644 index 0000000..fa45423 --- /dev/null +++ b/src/translations/lxqt-config_ro_RO.ts @@ -0,0 +1,12 @@ + + + + + MainWindow + + + Configuration Center + Centru de configurare + + + diff --git a/src/translations/lxqt-config_ru.desktop b/src/translations/lxqt-config_ru.desktop new file mode 100644 index 0000000..f9f1dac --- /dev/null +++ b/src/translations/lxqt-config_ru.desktop @@ -0,0 +1,4 @@ +# Translations +Comment[ru]=Настроить вашу систему +GenericName[ru]=Системные настройки +Name[ru]=Системные настройки LXQt diff --git a/src/translations/lxqt-config_ru.ts b/src/translations/lxqt-config_ru.ts new file mode 100644 index 0000000..f991c62 --- /dev/null +++ b/src/translations/lxqt-config_ru.ts @@ -0,0 +1,12 @@ + + + + + MainWindow + + + Configuration Center + Центр настроек + + + diff --git a/src/translations/lxqt-config_ru_RU.desktop b/src/translations/lxqt-config_ru_RU.desktop new file mode 100644 index 0000000..7f910fb --- /dev/null +++ b/src/translations/lxqt-config_ru_RU.desktop @@ -0,0 +1,4 @@ +# Translations +Comment[ru_RU]=Настроить вашу систему +GenericName[ru_RU]=Системные настройки +Name[ru_RU]=Системные настройки LXQt diff --git a/src/translations/lxqt-config_ru_RU.ts b/src/translations/lxqt-config_ru_RU.ts new file mode 100644 index 0000000..8a40e0b --- /dev/null +++ b/src/translations/lxqt-config_ru_RU.ts @@ -0,0 +1,12 @@ + + + + + MainWindow + + + Configuration Center + Центр настроек + + + diff --git a/src/translations/lxqt-config_sk.desktop b/src/translations/lxqt-config_sk.desktop new file mode 100644 index 0000000..f214d5b --- /dev/null +++ b/src/translations/lxqt-config_sk.desktop @@ -0,0 +1,4 @@ +# Translations +Comment[sk]=Centrum nastavení prostredia LXQt +GenericName[sk]=Centrum nastavení +Name[sk]=Centrum nastavení diff --git a/src/translations/lxqt-config_sl.desktop b/src/translations/lxqt-config_sl.desktop new file mode 100644 index 0000000..a13d84f --- /dev/null +++ b/src/translations/lxqt-config_sl.desktop @@ -0,0 +1,4 @@ +# Translations +Comment[sl]=Nastavitveni moduli za LXQt +GenericName[sl]=Nastavitve +Name[sl]=Nastavitveno središče za LXQt diff --git a/src/translations/lxqt-config_sr.desktop b/src/translations/lxqt-config_sr.desktop new file mode 100644 index 0000000..72d992b --- /dev/null +++ b/src/translations/lxqt-config_sr.desktop @@ -0,0 +1,4 @@ +# Translations +Comment[sr]=Подесите Рејзорове модуле +GenericName[sr]=Подешавање Рејзора +Name[sr]=Центар за подешавање diff --git a/src/translations/lxqt-config_sr@ijekavian.desktop b/src/translations/lxqt-config_sr@ijekavian.desktop new file mode 100644 index 0000000..bf36e19 --- /dev/null +++ b/src/translations/lxqt-config_sr@ijekavian.desktop @@ -0,0 +1,3 @@ +Name[sr@ijekavian]=Центар за подешавање +Comment[sr@ijekavian]=Подесите Рејзорове модуле +GenericName[sr@ijekavian]=Подешавање Рејзора diff --git a/src/translations/lxqt-config_sr@ijekavianlatin.desktop b/src/translations/lxqt-config_sr@ijekavianlatin.desktop new file mode 100644 index 0000000..84a9f35 --- /dev/null +++ b/src/translations/lxqt-config_sr@ijekavianlatin.desktop @@ -0,0 +1,3 @@ +Name[sr@ijekavianlatin]=Centar za podešavanje +Comment[sr@ijekavianlatin]=Podesite Rejzorove module +GenericName[sr@ijekavianlatin]=Podešavanje Rejzora diff --git a/src/translations/lxqt-config_sr@latin.desktop b/src/translations/lxqt-config_sr@latin.desktop new file mode 100644 index 0000000..2b58f2e --- /dev/null +++ b/src/translations/lxqt-config_sr@latin.desktop @@ -0,0 +1,4 @@ +# Translations +Comment[sr@latin]=Podesite Rejzorove module +GenericName[sr@latin]=Podešavanje Rejzora +Name[sr@latin]=Centar za podešavanje diff --git a/src/translations/lxqt-config_th_TH.desktop b/src/translations/lxqt-config_th_TH.desktop new file mode 100644 index 0000000..cbade56 --- /dev/null +++ b/src/translations/lxqt-config_th_TH.desktop @@ -0,0 +1,4 @@ +# Translations +Comment[th_TH]=ปรับแต่งมอดูล LXQt +GenericName[th_TH]=ปรับแต่ง LXQt +Name[th_TH]=ศูนย์การปรับแต่ง LXQt diff --git a/src/translations/lxqt-config_th_TH.ts b/src/translations/lxqt-config_th_TH.ts new file mode 100644 index 0000000..9ea9b8e --- /dev/null +++ b/src/translations/lxqt-config_th_TH.ts @@ -0,0 +1,12 @@ + + + + + MainWindow + + + Configuration Center + ศูนย์การปรับแต่ง + + + diff --git a/src/translations/lxqt-config_tr.desktop b/src/translations/lxqt-config_tr.desktop new file mode 100644 index 0000000..d388eb3 --- /dev/null +++ b/src/translations/lxqt-config_tr.desktop @@ -0,0 +1,4 @@ +# Translations +Comment[tr]=LXQt modüllerini yapılandır +GenericName[tr]=LXQt Yapılandırması +Name[tr]=LXQt Yapılandırma Merkezi diff --git a/src/translations/lxqt-config_uk.desktop b/src/translations/lxqt-config_uk.desktop new file mode 100644 index 0000000..3cf998b --- /dev/null +++ b/src/translations/lxqt-config_uk.desktop @@ -0,0 +1,4 @@ +# Translations +Comment[uk]=Налаштувати модулі LXQt +GenericName[uk]=Налаштування LXQt +Name[uk]=Центр налаштувань LXQt diff --git a/src/translations/lxqt-config_uk.ts b/src/translations/lxqt-config_uk.ts new file mode 100644 index 0000000..7675d69 --- /dev/null +++ b/src/translations/lxqt-config_uk.ts @@ -0,0 +1,12 @@ + + + + + MainWindow + + + Configuration Center + Центр налаштувань + + + diff --git a/src/translations/lxqt-config_zh_CN.GB2312.desktop b/src/translations/lxqt-config_zh_CN.GB2312.desktop new file mode 100644 index 0000000..26b0d99 --- /dev/null +++ b/src/translations/lxqt-config_zh_CN.GB2312.desktop @@ -0,0 +1 @@ +# Translations diff --git a/src/translations/lxqt-config_zh_CN.desktop b/src/translations/lxqt-config_zh_CN.desktop new file mode 100644 index 0000000..9588629 --- /dev/null +++ b/src/translations/lxqt-config_zh_CN.desktop @@ -0,0 +1,4 @@ +# Translations +Comment[zh_CN]=配置 LXQt 模块 +GenericName[zh_CN]=LXQt 配置 +Name[zh_CN]=LXQt 配置中心 diff --git a/src/translations/lxqt-config_zh_CN.ts b/src/translations/lxqt-config_zh_CN.ts new file mode 100644 index 0000000..dcbb52b --- /dev/null +++ b/src/translations/lxqt-config_zh_CN.ts @@ -0,0 +1,12 @@ + + + + + MainWindow + + + Configuration Center + 配置中心 + + + diff --git a/src/translations/lxqt-config_zh_TW.desktop b/src/translations/lxqt-config_zh_TW.desktop new file mode 100644 index 0000000..bb7780a --- /dev/null +++ b/src/translations/lxqt-config_zh_TW.desktop @@ -0,0 +1,4 @@ +# Translations +Comment[zh_TW]=設定LXQt模組 +GenericName[zh_TW]=LXQt設定 +Name[zh_TW]=LXQt設定中心 diff --git a/src/translations/lxqt-config_zh_TW.ts b/src/translations/lxqt-config_zh_TW.ts new file mode 100644 index 0000000..6e1dc15 --- /dev/null +++ b/src/translations/lxqt-config_zh_TW.ts @@ -0,0 +1,12 @@ + + + + + MainWindow + + + Configuration Center + 設定中心 + + +